Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
ex_gui_datagrid.c

N_GUI_DATAGRID rows, numeric sort, selection and right-click context callback regression (headless).

N_GUI_DATAGRID rows, numeric sort, selection and right-click context callback regression (headless).

Author
Castagnier Mickael
Version
1.0
/*
* Nilorea Library
* Copyright (C) 2005-2026 Castagnier Mickael
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
#define ALLEGRO_UNSTABLE 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "nilorea/n_log.h"
#include "nilorea/n_gui.h"
static int log_level = LOG_ERR;
static int failures = 0;
static int process_args(int argc, char** argv) {
int opt;
while ((opt = getopt(argc, argv, "V:")) != -1) {
switch (opt) {
case 'V':
if (!strcmp("LOG_NULL", optarg))
else if (!strcmp("LOG_NOTICE", optarg))
else if (!strcmp("LOG_INFO", optarg))
else if (!strcmp("LOG_ERR", optarg))
else if (!strcmp("LOG_DEBUG", optarg))
else
return -1;
break;
default:
return -1;
}
}
return 0;
}
static void expect_true(const char* label, int cond) {
if (!cond) {
n_log(LOG_ERR, "%s: condition false", label);
}
}
static void expect_streq(const char* label, const char* got, const char* want) {
if (!got || strcmp(got, want) != 0) {
n_log(LOG_ERR, "%s: got '%s', expected '%s'", label, got ? got : "(null)", want);
}
}
/* column-layout-changed callback capture (fired on a header-border resize drag) */
static int g_cols_changed = 0;
static void on_cols_changed(int widget_id, void* user_data) {
(void)widget_id;
(void)user_data;
}
/* right-click context callback capture */
static int g_ctx_calls = 0;
static int g_ctx_row = -1;
static int g_ctx_x = -1;
static int g_ctx_y = -1;
static void on_ctx(int widget_id, int row, int x, int y, void* user_data) {
(void)widget_id;
(void)user_data;
g_ctx_row = row;
g_ctx_x = x;
g_ctx_y = y;
}
int main(int argc, char** argv) {
if (process_args(argc, argv) != 0) {
fprintf(stderr, "Usage: %s [-V LOG_LEVEL]\n", argv[0]);
return 2;
}
if (!al_init() || !al_init_font_addon()) {
n_log(LOG_ERR, "allegro init failed");
return 1;
}
ALLEGRO_FONT* font = al_create_builtin_font();
if (!font) {
n_log(LOG_ERR, "al_create_builtin_font failed");
return 1;
}
if (!gui) {
n_log(LOG_ERR, "n_gui_new_ctx failed");
al_destroy_font(font);
return 1;
}
n_gui_set_display_size(gui, 800.0f, 600.0f);
int win = n_gui_add_window(gui, "Panel", 0.0f, 0.0f, 800.0f, 600.0f);
expect_true("window created", win >= 0);
/* frameless: no titlebar offset, so the context-menu hit test below has
simple window-relative coordinates */
int dg = n_gui_add_datagrid(gui, win, 0.0f, 0.0f, 600.0f, 400.0f, NULL, NULL);
expect_true("datagrid created", dg >= 0);
expect_true("column 0 added", n_gui_datagrid_add_column(gui, dg, "#", 60.0f) == 0);
expect_true("column 1 added", n_gui_datagrid_add_column(gui, dg, "Method", 100.0f) == 1);
expect_true("column 2 added", n_gui_datagrid_add_column(gui, dg, "Status", 80.0f) == 2);
{
const char* r0[] = {"3", "GET", "200"};
const char* r1[] = {"1", "POST", "404"};
const char* r2[] = {"2", "GET", "500"};
}
expect_true("row count is 3", n_gui_datagrid_get_row_count(gui, dg) == 3);
expect_streq("cell(0,1) before sort", n_gui_datagrid_get_cell(gui, dg, 0, 1), "GET");
/* columns are locked once rows exist */
expect_true("late column rejected", n_gui_datagrid_add_column(gui, dg, "Late", 50.0f) == -1);
/* selection round-trip (before sort, which clears selection) */
expect_true("selected row is 2", n_gui_datagrid_get_selected(gui, dg) == 2);
/* numeric ascending sort on the id column */
expect_streq("id asc row0", n_gui_datagrid_get_cell(gui, dg, 0, 0), "1");
expect_streq("id asc row2", n_gui_datagrid_get_cell(gui, dg, 2, 0), "3");
/* numeric sort on status: 200 < 404 < 500 (not lexical) */
expect_streq("status asc row0", n_gui_datagrid_get_cell(gui, dg, 0, 2), "200");
expect_streq("status asc row2", n_gui_datagrid_get_cell(gui, dg, 2, 2), "500");
/* descending */
n_gui_datagrid_sort(gui, dg, 2, -1);
expect_streq("status desc row0", n_gui_datagrid_get_cell(gui, dg, 0, 2), "500");
/* right-click context callback: a right press over a data row selects it and
fires on_context with the cursor position (the basis for GUI context menus).
The window is frameless, so a data row r sits at y in [(r+1)*row_h, (r+2)*row_h). */
{
ALLEGRO_EVENT ev;
float row_h = (float)al_get_font_line_height(font) + gui->style.item_height_pad;
int cx = 30; /* inside column 0 (width 60) */
int cy = (int)(row_h * 2.5f); /* header + row 1 center */
memset(&ev, 0, sizeof(ev));
ev.type = ALLEGRO_EVENT_MOUSE_BUTTON_DOWN;
ev.mouse.x = cx;
ev.mouse.y = cy;
ev.mouse.button = 2;
expect_true("context callback fired once", g_ctx_calls == 1);
expect_true("context row is 1", g_ctx_row == 1);
expect_true("context selects row 1", n_gui_datagrid_get_selected(gui, dg) == 1);
expect_true("context x echoes cursor", g_ctx_x == cx);
expect_true("context y echoes cursor", g_ctx_y == cy);
/* a left click selects but must not fire the context callback */
ev.type = ALLEGRO_EVENT_MOUSE_BUTTON_DOWN;
ev.mouse.button = 1;
ev.type = ALLEGRO_EVENT_MOUSE_BUTTON_UP;
expect_true("left click does not fire context", g_ctx_calls == 1);
}
/* multi-row selection: enable it, build a selection programmatically, query it,
then confirm a plain click collapses to one row and a sort clears it */
{
int sel[8];
size_t k;
ALLEGRO_EVENT ev;
float row_h = (float)al_get_font_line_height(font) + gui->style.item_height_pad;
expect_true("multiselect: none selected initially", n_gui_datagrid_get_selected_rows(gui, dg, NULL, 0) == 0);
expect_true("multiselect: two rows selected", n_gui_datagrid_get_selected_rows(gui, dg, NULL, 0) == 2);
expect_true("multiselect: row 0 is selected", n_gui_datagrid_is_row_selected(gui, dg, 0) == 1);
expect_true("multiselect: row 1 is not selected", n_gui_datagrid_is_row_selected(gui, dg, 1) == 0);
expect_true("multiselect: indices are 0 and 2, ascending", k == 2 && sel[0] == 0 && sel[1] == 2);
n_gui_datagrid_select_row(gui, dg, 0, 0); /* deselect row 0 */
expect_true("multiselect: one selected after deselect", n_gui_datagrid_get_selected_rows(gui, dg, NULL, 0) == 1);
/* a plain left click (no Ctrl/Shift) collapses the selection to one row */
memset(&ev, 0, sizeof(ev));
ev.type = ALLEGRO_EVENT_MOUSE_BUTTON_DOWN;
ev.mouse.x = 30;
ev.mouse.y = (int)(row_h * 1.5f); /* header + row 0 center */
ev.mouse.button = 1;
ev.type = ALLEGRO_EVENT_MOUSE_BUTTON_UP;
expect_true("multiselect: plain click selects exactly one", n_gui_datagrid_get_selected_rows(gui, dg, NULL, 0) == 1);
expect_true("multiselect: plain click selects row 0", n_gui_datagrid_is_row_selected(gui, dg, 0) == 1);
/* a sort changes row indices, so it clears the selection */
n_gui_datagrid_sort(gui, dg, 0, -1);
expect_true("multiselect: sort clears the selection", n_gui_datagrid_get_selected_rows(gui, dg, NULL, 0) == 0);
/* with multi-select off, the query reports the single selected row */
expect_true("single-select: get_selected_rows reports one", n_gui_datagrid_get_selected_rows(gui, dg, NULL, 0) == 1);
}
/* ---- per-row background tints: set, query, follow a sort, and clear ---- */
{
ALLEGRO_COLOR got;
const char* r0[] = {"3", "GET", "200"};
const char* r1[] = {"1", "POST", "404"};
const char* r2[] = {"2", "GET", "500"};
expect_true("no tint by default", n_gui_datagrid_get_row_color(gui, dg, 0, NULL) == 0);
n_gui_datagrid_set_row_color(gui, dg, 0, al_map_rgb(255, 0, 0)); /* id 3 -> red */
n_gui_datagrid_set_row_color(gui, dg, 2, al_map_rgb(0, 0, 255)); /* id 2 -> blue */
expect_true("row 0 tinted", n_gui_datagrid_get_row_color(gui, dg, 0, &got) == 1 && got.r > 0.9f && got.b < 0.1f);
expect_true("row 1 untinted", n_gui_datagrid_get_row_color(gui, dg, 1, NULL) == 0);
expect_true("row 2 tinted", n_gui_datagrid_get_row_color(gui, dg, 2, &got) == 1 && got.b > 0.9f && got.r < 0.1f);
expect_true("out-of-range row has no tint", n_gui_datagrid_get_row_color(gui, dg, 9, NULL) == 0);
/* a sort reorders the cells physically, so the tints must travel with
their rows: after ascending on the id column the order is 1, 2, 3, so
the blue row (id 2) lands at index 1 and the red row (id 3) at index 2 */
expect_streq("tint sort: row0 is id 1", n_gui_datagrid_get_cell(gui, dg, 0, 0), "1");
expect_true("tint sort: row 0 (id 1) still untinted", n_gui_datagrid_get_row_color(gui, dg, 0, NULL) == 0);
expect_true("tint sort: row 1 (id 2) keeps blue", n_gui_datagrid_get_row_color(gui, dg, 1, &got) == 1 && got.b > 0.9f);
expect_true("tint sort: row 2 (id 3) keeps red", n_gui_datagrid_get_row_color(gui, dg, 2, &got) == 1 && got.r > 0.9f);
/* a sort shrinks the cell buffer to nb_rows; the tint arrays shrink with
it, so adding rows afterwards must still grow them safely */
{
const char* r3[] = {"9", "PUT", "301"};
n_gui_datagrid_set_row_color(gui, dg, 3, al_map_rgb(0, 255, 0));
expect_true("tint after sort+add", n_gui_datagrid_get_row_color(gui, dg, 3, &got) == 1 && got.g > 0.9f);
expect_true("tint after sort+add: row 2 kept red", n_gui_datagrid_get_row_color(gui, dg, 2, &got) == 1 && got.r > 0.9f);
}
expect_true("single tint cleared", n_gui_datagrid_get_row_color(gui, dg, 2, NULL) == 0);
expect_true("other tint kept", n_gui_datagrid_get_row_color(gui, dg, 1, NULL) == 1);
expect_true("all tints cleared", n_gui_datagrid_get_row_color(gui, dg, 1, NULL) == 0);
/* clearing the rows drops their tints: rebuilt rows start untinted */
n_gui_datagrid_set_row_color(gui, dg, 0, al_map_rgb(255, 255, 0));
expect_true("clear_rows drops tints", n_gui_datagrid_get_row_color(gui, dg, 0, NULL) == 0);
}
/* ---- scroll offset: set, read back, clamp, and survive a rebuild ---- */
{
int i;
expect_true("scroll of empty grid is 0", n_gui_datagrid_get_scroll_offset(gui, dg) == 0);
for (i = 0; i < 40; i++) {
char a[16], b[16], c[16];
const char* r[3];
snprintf(a, sizeof(a), "%d", i);
snprintf(b, sizeof(b), "M%d", i);
snprintf(c, sizeof(c), "%d", 200 + i);
r[0] = a;
r[1] = b;
r[2] = c;
}
expect_true("scroll offset set to 12", n_gui_datagrid_get_scroll_offset(gui, dg) == 12);
/* the host preserves scroll across an in-place edit: save, clear+refill, restore */
{
for (i = 0; i < 40; i++) {
char a[16];
const char* r[3];
snprintf(a, sizeof(a), "%d", i);
r[0] = a;
r[1] = "M";
r[2] = "200";
}
expect_true("scroll offset survives a clear/refill", n_gui_datagrid_get_scroll_offset(gui, dg) == 12);
}
/* an over-range offset clamps into the row range */
expect_true("scroll offset clamps to last row", n_gui_datagrid_get_scroll_offset(gui, dg) == 39);
expect_true("scroll offset clamps to 0", n_gui_datagrid_get_scroll_offset(gui, dg) == 0);
}
/* ---- horizontal scroll: set, read back, clamp >= 0, survive a row refill ---- */
{
/* widen a column so the total content can exceed a typical pane (h-scroll is
meaningful); the getter/setter are the persistence hook the host uses to keep
the horizontal position across an in-place edit, like the vertical one above */
expect_true("h_scroll set to 80", n_gui_datagrid_get_h_scroll(gui, dg) == 80.0f);
/* the horizontal position is column-based, so a row clear/refill keeps it */
{
const char* r[3] = {"1", "M", "200"};
expect_true("h_scroll survives a row refill", n_gui_datagrid_get_h_scroll(gui, dg) == 80.0f);
}
/* a negative offset clamps to 0 (the draw path re-clamps the upper bound live) */
expect_true("h_scroll clamps to 0", n_gui_datagrid_get_h_scroll(gui, dg) == 0.0f);
}
expect_true("cleared row count is 0", n_gui_datagrid_get_row_count(gui, dg) == 0);
/* a sort reallocates the cell buffer to exactly nb_rows; adding more rows
afterwards must still grow safely (regression: rows_cap was left stale, so
the next add_row wrote past the shrunken buffer -> heap overflow). Stress
the add -> sort -> add cycle so ASan catches any out-of-bounds write. */
{
int i;
for (i = 0; i < 25; i++) {
char a[16], b[16], c[16];
const char* r[3];
snprintf(a, sizeof(a), "%d", 25 - i);
snprintf(b, sizeof(b), "GET%d", i);
snprintf(c, sizeof(c), "%d", 200 + (i % 5));
r[0] = a;
r[1] = b;
r[2] = c;
}
n_gui_datagrid_sort(gui, dg, 0, 1); /* shrinks the buffer to nb_rows */
for (i = 0; i < 25; i++) { /* push back past the shrunken cap */
char a[16];
const char* r[3];
snprintf(a, sizeof(a), "%d", 100 + i);
r[0] = a;
r[1] = "POST";
r[2] = "201";
}
expect_true("rows after sort+add", n_gui_datagrid_get_row_count(gui, dg) == 50);
}
/* ---- column customization: count/title, resize-by-drag, width, visibility,
and reorder (the display-order indirection over the physical cells) ---- */
expect_true("column count is 3", n_gui_datagrid_get_column_count(gui, dg) == 3);
expect_streq("column 1 title", n_gui_datagrid_get_column_title(gui, dg, 1), "Method");
expect_streq("out-of-range title", n_gui_datagrid_get_column_title(gui, dg, 9), "");
/* dragging column 0's right border (at x=60) widens it and fires the callback */
{
ALLEGRO_EVENT ev;
float row_h = (float)al_get_font_line_height(font) + gui->style.item_height_pad;
memset(&ev, 0, sizeof(ev));
ev.type = ALLEGRO_EVENT_MOUSE_BUTTON_DOWN;
ev.mouse.button = 1;
ev.mouse.x = 60;
ev.mouse.y = (int)(row_h * 0.5f);
ev.type = ALLEGRO_EVENT_MOUSE_AXES;
ev.mouse.x = 100;
ev.type = ALLEGRO_EVENT_MOUSE_BUTTON_UP;
expect_true("resize widened column 0", n_gui_datagrid_get_column_width(gui, dg, 0) > w0 + 20.0f);
expect_true("on_columns_changed fired once", g_cols_changed == 1);
}
/* width setter and its minimum clamp */
expect_true("column width set", n_gui_datagrid_get_column_width(gui, dg, 2) == 150.0f);
expect_true("column width min clamp", n_gui_datagrid_get_column_width(gui, dg, 2) == 16.0f);
/* visibility toggle */
expect_true("col 1 visible by default", n_gui_datagrid_get_column_visible(gui, dg, 1) == 1);
expect_true("col 1 now hidden", n_gui_datagrid_get_column_visible(gui, dg, 1) == 0);
/* reorder: identity, then move display position 0 to 2 -> order {1,2,0} */
expect_true("display 0 -> phys 0", n_gui_datagrid_display_to_physical(gui, dg, 0) == 0);
expect_true("after move display 2 -> phys 0", n_gui_datagrid_display_to_physical(gui, dg, 2) == 0);
expect_true("after move display 0 -> phys 1", n_gui_datagrid_display_to_physical(gui, dg, 0) == 1);
expect_true("after move display 1 -> phys 2", n_gui_datagrid_display_to_physical(gui, dg, 1) == 2);
expect_true("out-of-range display maps to -1", n_gui_datagrid_display_to_physical(gui, dg, 9) == -1);
/* guards: bad ids and out-of-range moves are no-ops */
expect_true("count for bad id is 0", n_gui_datagrid_get_column_count(gui, -1) == 0);
al_destroy_font(font);
if (failures) {
n_log(LOG_ERR, "ex_gui_datagrid: %d failure(s)", failures);
return 1;
}
n_log(LOG_NOTICE, "ex_gui_datagrid: all checks passed");
return 0;
}
static int failures
int main(void)
void process_args(int argc, char **argv)
Definition ex_common.c:48
int log_level
Definition ex_fluid.c:60
static void expect_true(const char *label, int cond)
static void on_ctx(int widget_id, int row, int x, int y, void *user_data)
static int g_ctx_calls
static void on_cols_changed(int widget_id, void *user_data)
static void expect_streq(const char *label, const char *got, const char *want)
static int g_ctx_y
static int g_ctx_x
static int g_ctx_row
static int g_cols_changed
static N_GUI_CTX * gui
N_GUI_STYLE style
configurable style (sizes, colours, paddings)
Definition n_gui.h:1424
float item_height_pad
min padding added to font height for item height
Definition n_gui.h:1278
void n_gui_set_display_size(N_GUI_CTX *ctx, float w, float h)
Set the display (viewport) size for global scrollbar computation.
Definition n_gui.c:9034
void n_gui_datagrid_sort(N_GUI_CTX *ctx, int widget_id, int col, int dir)
sort the rows by a column (dir 1 ascending, -1 descending)
Definition n_gui.c:4176
void n_gui_datagrid_set_on_columns_changed(N_GUI_CTX *ctx, int widget_id, void(*cb)(int, void *))
set the callback fired after the user drags a column border to resize it, so the host can persist the...
Definition n_gui.c:4171
void n_gui_datagrid_set_selected(N_GUI_CTX *ctx, int widget_id, int row)
set the selected row index (fires the on_select callback)
Definition n_gui.c:3958
void n_gui_datagrid_clear_row_color(N_GUI_CTX *ctx, int widget_id, int row)
remove the background tint of data row row (it draws untinted again)
Definition n_gui.c:4051
int n_gui_datagrid_get_row_count(N_GUI_CTX *ctx, int widget_id)
get the number of rows in a data grid
Definition n_gui.c:3938
const char * n_gui_datagrid_get_cell(N_GUI_CTX *ctx, int widget_id, int row, int col)
get a cell string by row and column, or NULL if out of range
Definition n_gui.c:3944
size_t n_gui_datagrid_get_column_count(N_GUI_CTX *ctx, int widget_id)
number of columns in a data grid (physical), or 0
Definition n_gui.c:4115
float n_gui_datagrid_get_h_scroll(N_GUI_CTX *ctx, int widget_id)
horizontal scroll offset in pixels (how far the columns are scrolled left when their total width exce...
Definition n_gui.c:4093
void n_gui_datagrid_set_row_color(N_GUI_CTX *ctx, int widget_id, int row, ALLEGRO_COLOR color)
paint data row row with a background tint (a per-row highlight, e.g.
Definition n_gui.c:4041
void n_gui_datagrid_set_scroll_offset(N_GUI_CTX *ctx, int widget_id, int offset)
set the first visible data row (clamped to the row count); the draw path re-clamps to the live viewpo...
Definition n_gui.c:4082
size_t n_gui_datagrid_get_selected_rows(N_GUI_CTX *ctx, int widget_id, int *out, size_t max)
fill out with the indices of the selected rows (ascending), up to max, and return the total number of...
Definition n_gui.c:3995
int n_gui_datagrid_get_scroll_offset(N_GUI_CTX *ctx, int widget_id)
first visible data row (the vertical scroll position), or 0.
Definition n_gui.c:4076
int n_gui_process_event(N_GUI_CTX *ctx, ALLEGRO_EVENT event)
Process an allegro event through the GUI system.
Definition n_gui.c:9836
void n_gui_datagrid_set_on_context(N_GUI_CTX *ctx, int widget_id, void(*on_context)(int, int, int, int, void *))
set the right-click context callback; fired (with the cursor x/y in GUI coordinates) when a data row ...
Definition n_gui.c:3967
int n_gui_datagrid_is_row_selected(N_GUI_CTX *ctx, int widget_id, int row)
report whether a given data row is selected (1) or not (0)
Definition n_gui.c:3986
int n_gui_datagrid_add_column(N_GUI_CTX *ctx, int widget_id, const char *title, float width)
append a column with a header title and pixel width; returns the column index or -1
Definition n_gui.c:3805
void n_gui_datagrid_set_h_scroll(N_GUI_CTX *ctx, int widget_id, float px)
set the horizontal scroll offset in pixels (clamped to >= 0; the draw path re-clamps to the live cont...
Definition n_gui.c:4099
void n_gui_datagrid_set_multiselect(N_GUI_CTX *ctx, int widget_id, int enabled)
enable (1) or disable (0) multi-row selection.
Definition n_gui.c:3973
#define N_GUI_WIN_FRAMELESS
frameless window: no title bar drawn, drag via window body unless N_GUI_WIN_FIXED_POSITION is also se...
Definition n_gui.h:233
void n_gui_datagrid_move_column(N_GUI_CTX *ctx, int widget_id, int from, int to)
move the column at display position from to display position to, shifting the columns in between (reo...
Definition n_gui.c:4156
int n_gui_datagrid_get_row_color(N_GUI_CTX *ctx, int widget_id, int row, ALLEGRO_COLOR *out)
report whether data row row carries a background tint (1) or not (0), and copy the tint into out when...
Definition n_gui.c:4059
void n_gui_datagrid_clear_selection(N_GUI_CTX *ctx, int widget_id)
clear the entire selection (no row selected)
Definition n_gui.c:4016
int n_gui_add_window(N_GUI_CTX *ctx, const char *title, float x, float y, float w, float h)
Add a new pseudo-window to the context.
Definition n_gui.c:1063
void n_gui_datagrid_select_row(N_GUI_CTX *ctx, int widget_id, int row, int selected)
select (1) or deselect (0) a single row in a multi-select grid programmatically (e....
Definition n_gui.c:4025
N_GUI_CTX * n_gui_new_ctx(ALLEGRO_FONT *default_font)
Create a new GUI context.
Definition n_gui.c:903
void n_gui_datagrid_clear_rows(N_GUI_CTX *ctx, int widget_id)
remove all rows from a data grid (columns are kept)
Definition n_gui.c:3920
int n_gui_datagrid_display_to_physical(N_GUI_CTX *ctx, int widget_id, int display_pos)
physical column shown at display position display_pos, or -1 if out of range
Definition n_gui.c:4150
float n_gui_datagrid_get_column_width(N_GUI_CTX *ctx, int widget_id, int col)
current pixel width of physical column col, or 0 if out of range
Definition n_gui.c:4144
const char * n_gui_datagrid_get_column_title(N_GUI_CTX *ctx, int widget_id, int col)
header title of physical column col, or "" if out of range
Definition n_gui.c:4120
void n_gui_destroy_ctx(N_GUI_CTX **ctx)
Destroy a GUI context and all its windows/widgets.
Definition n_gui.c:995
int n_gui_datagrid_add_row(N_GUI_CTX *ctx, int widget_id, const char **values)
append a row of cell strings (values must have one entry per column); returns the row index or -1
Definition n_gui.c:3862
void n_gui_datagrid_set_column_width(N_GUI_CTX *ctx, int widget_id, int col, float width)
set the pixel width of physical column col (clamped to a small minimum)
Definition n_gui.c:4138
void n_gui_datagrid_set_column_visible(N_GUI_CTX *ctx, int widget_id, int col, int visible)
show (1) or hide (0) physical column col; hidden columns keep their cells but are skipped in the head...
Definition n_gui.c:4126
void n_gui_window_set_flags(N_GUI_CTX *ctx, int window_id, int flags)
Set feature flags on a window.
Definition n_gui.c:1968
void n_gui_datagrid_clear_row_colors(N_GUI_CTX *ctx, int widget_id)
remove every row background tint (the rows and cells are kept)
Definition n_gui.c:4069
int n_gui_datagrid_get_selected(N_GUI_CTX *ctx, int widget_id)
get the selected row index, or -1 if none
Definition n_gui.c:3952
int n_gui_datagrid_get_column_visible(N_GUI_CTX *ctx, int widget_id, int col)
whether physical column col is visible (1) or hidden (0); 0 if out of range
Definition n_gui.c:4132
int n_gui_add_datagrid(N_GUI_CTX *ctx, int window_id, float x, float y, float w, float h, void(*on_select)(int, int, void *), void *user_data)
Add a sortable data grid widget.
Definition n_gui.c:2787
The top-level GUI context that holds all windows.
Definition n_gui.h:1354
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:89
#define LOG_DEBUG
debug-level messages
Definition n_log.h:84
#define LOG_ERR
error conditions
Definition n_log.h:76
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL )
Definition n_log.c:121
#define LOG_NOTICE
normal but significant condition
Definition n_log.h:80
#define LOG_NULL
no log output
Definition n_log.h:46
#define LOG_INFO
informational
Definition n_log.h:82
Common headers and low-level functions & define.
GUI system: buttons, sliders, text areas, checkboxes, scrollbars, dropdown menus, windows.
Generic log system.