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.
4.5 KiB
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
RGBcolors 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.
- Automatically matches Clay's
- 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 ofgetchorwgetch. 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 usesClay_OnHoverinternally. Your callback function should check ifpointerInfo.state == CLAY_POINTER_DATA_RELEASED_THIS_FRAMEto 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.
fontSizeconfigs 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.