clay/renderers/ncurses
Seintian c700104760 feat(ncurses): Add interaction callbacks and improve input handling
Introduces Input Processing and Interaction helpers for the Ncurses renderer, ensuring robust mouse support and simplified event handling.

**Renderer (`renderers/ncurses`):**
- **`Clay_Ncurses_ProcessInput`**: Added a dedicated input processing function that handles both keyboard and mouse events.
  - Implemented persistent `_isMouseDown` state tracking to fix missed "fast clicks" and preserve button state during drag operations.
  - Adjusted `mousemask` to `BUTTON1_PRESSED | BUTTON1_RELEASED | REPORT_MOUSE_POSITION` to bypass Ncurses' internal click resolution delay.
- **`Clay_Ncurses_OnClick`**: Added a helper function to easily attach click listeners.
  - Registers the user's callback directly via `Clay_OnHover` (avoiding allocation/proxies).
  - Matches the standard Clay callback signature pattern.

**Example (`examples/ncurses-example`):**
- **Input Loop**: Migrated main loop to use `Clay_Ncurses_ProcessInput`.
- **Interactions**:
  - Added a "Toggle Help" button to the sidebar.
  - Implemented `HandleHelpToggleClick` callback, which explicitly checks for `CLAY_POINTER_DATA_RELEASED_THIS_FRAME` to validate clicks.
  - Added visual hover effects to sidebar items.

**Documentation (`renderers/ncurses/README.md`):**
- Updated "Usage" section to demonstrate `Clay_Ncurses_ProcessInput`.
- Added "Input & Interaction" section documenting the new helpers.
2025-12-28 22:17:27 +01:00
..
clay_renderer_ncurses.c feat(ncurses): Add interaction callbacks and improve input handling 2025-12-28 22:17:27 +01:00
README.md feat(ncurses): Add interaction callbacks and improve input handling 2025-12-28 22:17:27 +01:00

Clay Ncurses Renderer

This directory contains a backend renderer for Clay that targets the terminal using the ncurses library. It allows you to build text-based user interfaces (TUI) using the same Clay layout engine used for graphical applications.

Features

  • Responsive Layouts in the Terminal: Use flex-box like layout rules to organize text and panels in a terminal window.
  • Color Support:
    • Automatically matches Clay's RGB colors to the nearest available terminal color.
    • Supports 256-color terminals (xterm-256color) for richer palettes.
    • Graceful fallback to standard 8 ANSI colors for older terminals.
  • UTF-8 Support: Correctly measures and renders multibyte characters (assuming the terminal is configured for UTF-8).
  • Primitives Supported:
    • Rectangle: Renders as solid blocks of color.
    • Text: Renders colored text.
    • Border: Renders lines using ACS (Alternate Character Set) box-drawing characters, supporting rounded corners and different line styles where possible.
    • Scissor/Clipping: Fully supports nested clipping rectangles (e.g., for scroll containers).
  • Input Handling:
    • sets up standard ncurses input modes (cbreak, noecho, keypad).
    • Enables mouse event reporting.

Usage

To use the ncurses renderer in your Clay application:

1. Include the Renderer

#define CLAY_IMPLEMENTATION
#include "clay.h"
#include "renderers/ncurses/clay_renderer_ncurses.c"

2. Initialization

Initialize the renderer before your main loop. This sets up the terminal screen, colors, and input modes.

Clay_Initialize(arena, (Clay_Dimensions){0,0}, (Clay_ErrorHandler){NULL});
Clay_SetMeasureTextFunction(Clay_Ncurses_MeasureText, NULL);
Clay_Ncurses_Initialize();

3. Rendering Loop

In your main loop, update the layout dimensions based on the terminal size, run the layout, and then pass the render commands to the ncurses renderer.

while (!shouldQuit) {
    // 1. Get current terminal size
    Clay_Dimensions dims = Clay_Ncurses_GetLayoutDimensions();
    Clay_SetLayoutDimensions(dims);

    // 2. Handle Input
    int key = Clay_Ncurses_ProcessInput(stdscr); 
    if (key == 'q') break;

    // 3. Define Layout
    Clay_BeginLayout();

    // Example: Clickable Element
    CLAY(CLAY_ID("Clickable"), {0}) {
        Clay_Ncurses_OnClick(MyCallback, myData);
        CLAY_TEXT(CLAY_STRING("Click Me"), CLAY_TEXT_CONFIG({0}));
    }

    Clay_RenderCommandArray commands = Clay_EndLayout();

    // 4. Render
    Clay_Ncurses_Render(commands);
}

4. Input & Interaction

The renderer provides helper functions to easy integration of mouse interactions:

  • Clay_Ncurses_ProcessInput(WINDOW *window): Call this instead of getch or wgetch. It handles mouse events, updates the internal Clay pointer state, and returns the key code for your application to handle (e.g., keyboard shortcuts).
  • Clay_Ncurses_OnClick(void (*userData)(...), void *userData): A helper to attach a click listener to the current element. It uses Clay_OnHover internally. Your callback function should check if pointerInfo.state == CLAY_POINTER_DATA_RELEASED_THIS_FRAME to detect a valid click.

5. Cleanup

Restore the terminal to its normal state before exiting.

Clay_Ncurses_Terminate();

Compilation

You must link against the ncurses (and potentially tinfo) library.

gcc main.c -lncurses -o my_app

On some systems attempting to use wide characters/UTF-8 might require linking ncursesw instead:

gcc main.c -lncursesw -o my_app

How it Works

The renderer maps Clay's floating-point coordinate system to the integer grid of the terminal.

  • Cell Size: It assumes a logical "pixel" size for each character cell (defaults to 8x16 internally) to map Clay's high-precision layout to character columns and rows.
  • Double Buffering: It uses ncurses' standard buffering mechanisms (refresh()) to prevent flickering during updates.
  • Clipping: It uses a software scissor stack to determine visibility, as terminals do not natively support arbitrary clipping regions for drawing commands.

Limitations

  • Images: Rendering images is not currently supported.
  • Fonts: Text size is fixed to the terminal's cell size. fontSize configs are ignored for layout measurement, though they affect the logical ID generation.
  • Pixel Precision: Since the output is quantized to character cells, fine-grained pixel alignment (e.g., a 1px shift) will snap to the nearest cell boundary.