Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
ex_gui_datagrid.c
Go to the documentation of this file.
1/*
2 * Nilorea Library
3 * Copyright (C) 2005-2026 Castagnier Mickael
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * permissions and limitations under the License.
16 *
17 * SPDX-License-Identifier: Apache-2.0
18 */
19
28#define ALLEGRO_UNSTABLE 1
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <unistd.h>
34
35#include "nilorea/n_common.h"
36#include "nilorea/n_log.h"
37#include "nilorea/n_gui.h"
38
39static int log_level = LOG_ERR;
40static int failures = 0;
41
42static int process_args(int argc, char** argv) {
43 int opt;
44 while ((opt = getopt(argc, argv, "V:")) != -1) {
45 switch (opt) {
46 case 'V':
47 if (!strcmp("LOG_NULL", optarg))
49 else if (!strcmp("LOG_NOTICE", optarg))
51 else if (!strcmp("LOG_INFO", optarg))
53 else if (!strcmp("LOG_ERR", optarg))
55 else if (!strcmp("LOG_DEBUG", optarg))
57 else
58 return -1;
59 break;
60 default:
61 return -1;
62 }
63 }
64 return 0;
65}
66
67static void expect_true(const char* label, int cond) {
68 if (!cond) {
69 n_log(LOG_ERR, "%s: condition false", label);
70 failures++;
71 }
72}
73
74static void expect_streq(const char* label, const char* got, const char* want) {
75 if (!got || strcmp(got, want) != 0) {
76 n_log(LOG_ERR, "%s: got '%s', expected '%s'", label, got ? got : "(null)", want);
77 failures++;
78 }
79}
80
81/* column-layout-changed callback capture (fired on a header-border resize drag) */
82static int g_cols_changed = 0;
83static void on_cols_changed(int widget_id, void* user_data) {
84 (void)widget_id;
85 (void)user_data;
87}
88
89/* right-click context callback capture */
90static int g_ctx_calls = 0;
91static int g_ctx_row = -1;
92static int g_ctx_x = -1;
93static int g_ctx_y = -1;
94static void on_ctx(int widget_id, int row, int x, int y, void* user_data) {
95 (void)widget_id;
96 (void)user_data;
98 g_ctx_row = row;
99 g_ctx_x = x;
100 g_ctx_y = y;
101}
102
103int main(int argc, char** argv) {
105 if (process_args(argc, argv) != 0) {
106 fprintf(stderr, "Usage: %s [-V LOG_LEVEL]\n", argv[0]);
107 return 2;
108 }
110
111 if (!al_init() || !al_init_font_addon()) {
112 n_log(LOG_ERR, "allegro init failed");
113 return 1;
114 }
115 ALLEGRO_FONT* font = al_create_builtin_font();
116 if (!font) {
117 n_log(LOG_ERR, "al_create_builtin_font failed");
118 return 1;
119 }
120 N_GUI_CTX* gui = n_gui_new_ctx(font);
121 if (!gui) {
122 n_log(LOG_ERR, "n_gui_new_ctx failed");
123 al_destroy_font(font);
124 return 1;
125 }
126 n_gui_set_display_size(gui, 800.0f, 600.0f);
127
128 int win = n_gui_add_window(gui, "Panel", 0.0f, 0.0f, 800.0f, 600.0f);
129 expect_true("window created", win >= 0);
130 /* frameless: no titlebar offset, so the context-menu hit test below has
131 simple window-relative coordinates */
133
134 int dg = n_gui_add_datagrid(gui, win, 0.0f, 0.0f, 600.0f, 400.0f, NULL, NULL);
135 expect_true("datagrid created", dg >= 0);
136
137 expect_true("column 0 added", n_gui_datagrid_add_column(gui, dg, "#", 60.0f) == 0);
138 expect_true("column 1 added", n_gui_datagrid_add_column(gui, dg, "Method", 100.0f) == 1);
139 expect_true("column 2 added", n_gui_datagrid_add_column(gui, dg, "Status", 80.0f) == 2);
140
141 {
142 const char* r0[] = {"3", "GET", "200"};
143 const char* r1[] = {"1", "POST", "404"};
144 const char* r2[] = {"2", "GET", "500"};
148 }
149 expect_true("row count is 3", n_gui_datagrid_get_row_count(gui, dg) == 3);
150 expect_streq("cell(0,1) before sort", n_gui_datagrid_get_cell(gui, dg, 0, 1), "GET");
151
152 /* columns are locked once rows exist */
153 expect_true("late column rejected", n_gui_datagrid_add_column(gui, dg, "Late", 50.0f) == -1);
154
155 /* selection round-trip (before sort, which clears selection) */
157 expect_true("selected row is 2", n_gui_datagrid_get_selected(gui, dg) == 2);
158
159 /* numeric ascending sort on the id column */
160 n_gui_datagrid_sort(gui, dg, 0, 1);
161 expect_streq("id asc row0", n_gui_datagrid_get_cell(gui, dg, 0, 0), "1");
162 expect_streq("id asc row2", n_gui_datagrid_get_cell(gui, dg, 2, 0), "3");
163
164 /* numeric sort on status: 200 < 404 < 500 (not lexical) */
165 n_gui_datagrid_sort(gui, dg, 2, 1);
166 expect_streq("status asc row0", n_gui_datagrid_get_cell(gui, dg, 0, 2), "200");
167 expect_streq("status asc row2", n_gui_datagrid_get_cell(gui, dg, 2, 2), "500");
168
169 /* descending */
170 n_gui_datagrid_sort(gui, dg, 2, -1);
171 expect_streq("status desc row0", n_gui_datagrid_get_cell(gui, dg, 0, 2), "500");
172
173 /* right-click context callback: a right press over a data row selects it and
174 fires on_context with the cursor position (the basis for GUI context menus).
175 The window is frameless, so a data row r sits at y in [(r+1)*row_h, (r+2)*row_h). */
176 {
177 ALLEGRO_EVENT ev;
178 float row_h = (float)al_get_font_line_height(font) + gui->style.item_height_pad;
179 int cx = 30; /* inside column 0 (width 60) */
180 int cy = (int)(row_h * 2.5f); /* header + row 1 center */
182 memset(&ev, 0, sizeof(ev));
183 ev.type = ALLEGRO_EVENT_MOUSE_BUTTON_DOWN;
184 ev.mouse.x = cx;
185 ev.mouse.y = cy;
186 ev.mouse.button = 2;
188 expect_true("context callback fired once", g_ctx_calls == 1);
189 expect_true("context row is 1", g_ctx_row == 1);
190 expect_true("context selects row 1", n_gui_datagrid_get_selected(gui, dg) == 1);
191 expect_true("context x echoes cursor", g_ctx_x == cx);
192 expect_true("context y echoes cursor", g_ctx_y == cy);
193
194 /* a left click selects but must not fire the context callback */
195 ev.type = ALLEGRO_EVENT_MOUSE_BUTTON_DOWN;
196 ev.mouse.button = 1;
198 ev.type = ALLEGRO_EVENT_MOUSE_BUTTON_UP;
200 expect_true("left click does not fire context", g_ctx_calls == 1);
201 }
202
203 /* multi-row selection: enable it, build a selection programmatically, query it,
204 then confirm a plain click collapses to one row and a sort clears it */
205 {
206 int sel[8];
207 size_t k;
208 ALLEGRO_EVENT ev;
209 float row_h = (float)al_get_font_line_height(font) + gui->style.item_height_pad;
212 expect_true("multiselect: none selected initially", n_gui_datagrid_get_selected_rows(gui, dg, NULL, 0) == 0);
215 expect_true("multiselect: two rows selected", n_gui_datagrid_get_selected_rows(gui, dg, NULL, 0) == 2);
216 expect_true("multiselect: row 0 is selected", n_gui_datagrid_is_row_selected(gui, dg, 0) == 1);
217 expect_true("multiselect: row 1 is not selected", n_gui_datagrid_is_row_selected(gui, dg, 1) == 0);
218 k = n_gui_datagrid_get_selected_rows(gui, dg, sel, 8);
219 expect_true("multiselect: indices are 0 and 2, ascending", k == 2 && sel[0] == 0 && sel[1] == 2);
220 n_gui_datagrid_select_row(gui, dg, 0, 0); /* deselect row 0 */
221 expect_true("multiselect: one selected after deselect", n_gui_datagrid_get_selected_rows(gui, dg, NULL, 0) == 1);
222
223 /* a plain left click (no Ctrl/Shift) collapses the selection to one row */
224 memset(&ev, 0, sizeof(ev));
225 ev.type = ALLEGRO_EVENT_MOUSE_BUTTON_DOWN;
226 ev.mouse.x = 30;
227 ev.mouse.y = (int)(row_h * 1.5f); /* header + row 0 center */
228 ev.mouse.button = 1;
230 ev.type = ALLEGRO_EVENT_MOUSE_BUTTON_UP;
232 expect_true("multiselect: plain click selects exactly one", n_gui_datagrid_get_selected_rows(gui, dg, NULL, 0) == 1);
233 expect_true("multiselect: plain click selects row 0", n_gui_datagrid_is_row_selected(gui, dg, 0) == 1);
234
235 /* a sort changes row indices, so it clears the selection */
237 n_gui_datagrid_sort(gui, dg, 0, -1);
238 expect_true("multiselect: sort clears the selection", n_gui_datagrid_get_selected_rows(gui, dg, NULL, 0) == 0);
239
240 /* with multi-select off, the query reports the single selected row */
243 expect_true("single-select: get_selected_rows reports one", n_gui_datagrid_get_selected_rows(gui, dg, NULL, 0) == 1);
244 }
245
246 /* ---- per-row background tints: set, query, follow a sort, and clear ---- */
247 {
248 ALLEGRO_COLOR got;
249 const char* r0[] = {"3", "GET", "200"};
250 const char* r1[] = {"1", "POST", "404"};
251 const char* r2[] = {"2", "GET", "500"};
256
257 expect_true("no tint by default", n_gui_datagrid_get_row_color(gui, dg, 0, NULL) == 0);
258 n_gui_datagrid_set_row_color(gui, dg, 0, al_map_rgb(255, 0, 0)); /* id 3 -> red */
259 n_gui_datagrid_set_row_color(gui, dg, 2, al_map_rgb(0, 0, 255)); /* id 2 -> blue */
260 expect_true("row 0 tinted", n_gui_datagrid_get_row_color(gui, dg, 0, &got) == 1 && got.r > 0.9f && got.b < 0.1f);
261 expect_true("row 1 untinted", n_gui_datagrid_get_row_color(gui, dg, 1, NULL) == 0);
262 expect_true("row 2 tinted", n_gui_datagrid_get_row_color(gui, dg, 2, &got) == 1 && got.b > 0.9f && got.r < 0.1f);
263 expect_true("out-of-range row has no tint", n_gui_datagrid_get_row_color(gui, dg, 9, NULL) == 0);
264
265 /* a sort reorders the cells physically, so the tints must travel with
266 their rows: after ascending on the id column the order is 1, 2, 3, so
267 the blue row (id 2) lands at index 1 and the red row (id 3) at index 2 */
268 n_gui_datagrid_sort(gui, dg, 0, 1);
269 expect_streq("tint sort: row0 is id 1", n_gui_datagrid_get_cell(gui, dg, 0, 0), "1");
270 expect_true("tint sort: row 0 (id 1) still untinted", n_gui_datagrid_get_row_color(gui, dg, 0, NULL) == 0);
271 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);
272 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);
273
274 /* a sort shrinks the cell buffer to nb_rows; the tint arrays shrink with
275 it, so adding rows afterwards must still grow them safely */
276 {
277 const char* r3[] = {"9", "PUT", "301"};
279 n_gui_datagrid_set_row_color(gui, dg, 3, al_map_rgb(0, 255, 0));
280 expect_true("tint after sort+add", n_gui_datagrid_get_row_color(gui, dg, 3, &got) == 1 && got.g > 0.9f);
281 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);
282 }
283
285 expect_true("single tint cleared", n_gui_datagrid_get_row_color(gui, dg, 2, NULL) == 0);
286 expect_true("other tint kept", n_gui_datagrid_get_row_color(gui, dg, 1, NULL) == 1);
288 expect_true("all tints cleared", n_gui_datagrid_get_row_color(gui, dg, 1, NULL) == 0);
289
290 /* clearing the rows drops their tints: rebuilt rows start untinted */
291 n_gui_datagrid_set_row_color(gui, dg, 0, al_map_rgb(255, 255, 0));
294 expect_true("clear_rows drops tints", n_gui_datagrid_get_row_color(gui, dg, 0, NULL) == 0);
295 }
296
297 /* ---- scroll offset: set, read back, clamp, and survive a rebuild ---- */
298 {
299 int i;
301 expect_true("scroll of empty grid is 0", n_gui_datagrid_get_scroll_offset(gui, dg) == 0);
302 for (i = 0; i < 40; i++) {
303 char a[16], b[16], c[16];
304 const char* r[3];
305 snprintf(a, sizeof(a), "%d", i);
306 snprintf(b, sizeof(b), "M%d", i);
307 snprintf(c, sizeof(c), "%d", 200 + i);
308 r[0] = a;
309 r[1] = b;
310 r[2] = c;
312 }
314 expect_true("scroll offset set to 12", n_gui_datagrid_get_scroll_offset(gui, dg) == 12);
315 /* the host preserves scroll across an in-place edit: save, clear+refill, restore */
316 {
317 int saved = n_gui_datagrid_get_scroll_offset(gui, dg);
319 for (i = 0; i < 40; i++) {
320 char a[16];
321 const char* r[3];
322 snprintf(a, sizeof(a), "%d", i);
323 r[0] = a;
324 r[1] = "M";
325 r[2] = "200";
327 }
329 expect_true("scroll offset survives a clear/refill", n_gui_datagrid_get_scroll_offset(gui, dg) == 12);
330 }
331 /* an over-range offset clamps into the row range */
333 expect_true("scroll offset clamps to last row", n_gui_datagrid_get_scroll_offset(gui, dg) == 39);
335 expect_true("scroll offset clamps to 0", n_gui_datagrid_get_scroll_offset(gui, dg) == 0);
336 }
337
338 /* ---- horizontal scroll: set, read back, clamp >= 0, survive a row refill ---- */
339 {
340 /* widen a column so the total content can exceed a typical pane (h-scroll is
341 meaningful); the getter/setter are the persistence hook the host uses to keep
342 the horizontal position across an in-place edit, like the vertical one above */
343 n_gui_datagrid_set_column_width(gui, dg, 2, 400.0f);
345 expect_true("h_scroll set to 80", n_gui_datagrid_get_h_scroll(gui, dg) == 80.0f);
346 /* the horizontal position is column-based, so a row clear/refill keeps it */
347 {
348 const char* r[3] = {"1", "M", "200"};
351 expect_true("h_scroll survives a row refill", n_gui_datagrid_get_h_scroll(gui, dg) == 80.0f);
352 }
353 /* a negative offset clamps to 0 (the draw path re-clamps the upper bound live) */
354 n_gui_datagrid_set_h_scroll(gui, dg, -25.0f);
355 expect_true("h_scroll clamps to 0", n_gui_datagrid_get_h_scroll(gui, dg) == 0.0f);
357 }
358
360 expect_true("cleared row count is 0", n_gui_datagrid_get_row_count(gui, dg) == 0);
361
362 /* a sort reallocates the cell buffer to exactly nb_rows; adding more rows
363 afterwards must still grow safely (regression: rows_cap was left stale, so
364 the next add_row wrote past the shrunken buffer -> heap overflow). Stress
365 the add -> sort -> add cycle so ASan catches any out-of-bounds write. */
366 {
367 int i;
368 for (i = 0; i < 25; i++) {
369 char a[16], b[16], c[16];
370 const char* r[3];
371 snprintf(a, sizeof(a), "%d", 25 - i);
372 snprintf(b, sizeof(b), "GET%d", i);
373 snprintf(c, sizeof(c), "%d", 200 + (i % 5));
374 r[0] = a;
375 r[1] = b;
376 r[2] = c;
378 }
379 n_gui_datagrid_sort(gui, dg, 0, 1); /* shrinks the buffer to nb_rows */
380 for (i = 0; i < 25; i++) { /* push back past the shrunken cap */
381 char a[16];
382 const char* r[3];
383 snprintf(a, sizeof(a), "%d", 100 + i);
384 r[0] = a;
385 r[1] = "POST";
386 r[2] = "201";
388 }
389 expect_true("rows after sort+add", n_gui_datagrid_get_row_count(gui, dg) == 50);
391 }
392
393 /* ---- column customization: count/title, resize-by-drag, width, visibility,
394 and reorder (the display-order indirection over the physical cells) ---- */
395 expect_true("column count is 3", n_gui_datagrid_get_column_count(gui, dg) == 3);
396 expect_streq("column 1 title", n_gui_datagrid_get_column_title(gui, dg, 1), "Method");
397 expect_streq("out-of-range title", n_gui_datagrid_get_column_title(gui, dg, 9), "");
398
399 /* dragging column 0's right border (at x=60) widens it and fires the callback */
401 {
402 ALLEGRO_EVENT ev;
403 float row_h = (float)al_get_font_line_height(font) + gui->style.item_height_pad;
404 float w0 = n_gui_datagrid_get_column_width(gui, dg, 0);
405 memset(&ev, 0, sizeof(ev));
406 ev.type = ALLEGRO_EVENT_MOUSE_BUTTON_DOWN;
407 ev.mouse.button = 1;
408 ev.mouse.x = 60;
409 ev.mouse.y = (int)(row_h * 0.5f);
411 ev.type = ALLEGRO_EVENT_MOUSE_AXES;
412 ev.mouse.x = 100;
414 ev.type = ALLEGRO_EVENT_MOUSE_BUTTON_UP;
416 expect_true("resize widened column 0", n_gui_datagrid_get_column_width(gui, dg, 0) > w0 + 20.0f);
417 expect_true("on_columns_changed fired once", g_cols_changed == 1);
418 }
419
420 /* width setter and its minimum clamp */
421 n_gui_datagrid_set_column_width(gui, dg, 2, 150.0f);
422 expect_true("column width set", n_gui_datagrid_get_column_width(gui, dg, 2) == 150.0f);
424 expect_true("column width min clamp", n_gui_datagrid_get_column_width(gui, dg, 2) == 16.0f);
425
426 /* visibility toggle */
427 expect_true("col 1 visible by default", n_gui_datagrid_get_column_visible(gui, dg, 1) == 1);
429 expect_true("col 1 now hidden", n_gui_datagrid_get_column_visible(gui, dg, 1) == 0);
430
431 /* reorder: identity, then move display position 0 to 2 -> order {1,2,0} */
432 expect_true("display 0 -> phys 0", n_gui_datagrid_display_to_physical(gui, dg, 0) == 0);
434 expect_true("after move display 2 -> phys 0", n_gui_datagrid_display_to_physical(gui, dg, 2) == 0);
435 expect_true("after move display 0 -> phys 1", n_gui_datagrid_display_to_physical(gui, dg, 0) == 1);
436 expect_true("after move display 1 -> phys 2", n_gui_datagrid_display_to_physical(gui, dg, 1) == 2);
437 expect_true("out-of-range display maps to -1", n_gui_datagrid_display_to_physical(gui, dg, 9) == -1);
438
439 /* guards: bad ids and out-of-range moves are no-ops */
441 expect_true("count for bad id is 0", n_gui_datagrid_get_column_count(gui, -1) == 0);
442
444 al_destroy_font(font);
445
446 if (failures) {
447 n_log(LOG_ERR, "ex_gui_datagrid: %d failure(s)", failures);
448 return 1;
449 }
450 n_log(LOG_NOTICE, "ex_gui_datagrid: all checks passed");
451 return 0;
452}
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.