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
27
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 }
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 /* the columns' own width drives a host's minimum dialog width; it is the
143 * left text pad plus every VISIBLE column, and hiding one drops it */
144 float pad = gui->style.item_text_padding;
145 expect_true("columns_width sums the visible columns",
146 n_gui_datagrid_columns_width(gui, dg) == pad + 60.0f + 100.0f + 80.0f);
148 expect_true("columns_width drops a hidden column",
149 n_gui_datagrid_columns_width(gui, dg) == pad + 60.0f + 80.0f);
151 int not_a_grid = n_gui_add_button(gui, win, "b", 0.0f, 500.0f, 40.0f, 20.0f,
152 N_GUI_SHAPE_RECT, NULL, NULL);
153 expect_true("columns_width is 0 for a non-datagrid widget",
154 n_gui_datagrid_columns_width(gui, not_a_grid) == 0.0f);
155 expect_true("columns_width is 0 for an unknown id",
156 n_gui_datagrid_columns_width(gui, 4242) == 0.0f);
157 }
158
159 {
160 const char* r0[] = {"3", "GET", "200"};
161 const char* r1[] = {"1", "POST", "404"};
162 const char* r2[] = {"2", "GET", "500"};
166 }
167 expect_true("row count is 3", n_gui_datagrid_get_row_count(gui, dg) == 3);
168 expect_streq("cell(0,1) before sort", n_gui_datagrid_get_cell(gui, dg, 0, 1), "GET");
169
170 /* columns are locked once rows exist */
171 expect_true("late column rejected", n_gui_datagrid_add_column(gui, dg, "Late", 50.0f) == -1);
172
173 /* selection round-trip (before sort, which clears selection) */
175 expect_true("selected row is 2", n_gui_datagrid_get_selected(gui, dg) == 2);
176
177 /* numeric ascending sort on the id column */
178 n_gui_datagrid_sort(gui, dg, 0, 1);
179 expect_streq("id asc row0", n_gui_datagrid_get_cell(gui, dg, 0, 0), "1");
180 expect_streq("id asc row2", n_gui_datagrid_get_cell(gui, dg, 2, 0), "3");
181
182 /* numeric sort on status: 200 < 404 < 500 (not lexical) */
183 n_gui_datagrid_sort(gui, dg, 2, 1);
184 expect_streq("status asc row0", n_gui_datagrid_get_cell(gui, dg, 0, 2), "200");
185 expect_streq("status asc row2", n_gui_datagrid_get_cell(gui, dg, 2, 2), "500");
186
187 /* descending */
188 n_gui_datagrid_sort(gui, dg, 2, -1);
189 expect_streq("status desc row0", n_gui_datagrid_get_cell(gui, dg, 0, 2), "500");
190
191 /* right-click context callback: a right press over a data row selects it and
192 fires on_context with the cursor position (the basis for GUI context menus).
193 The window is frameless, so a data row r sits at y in [(r+1)*row_h, (r+2)*row_h). */
194 {
195 ALLEGRO_EVENT ev;
196 float row_h = (float)al_get_font_line_height(font) + gui->style.item_height_pad;
197 int cx = 30; /* inside column 0 (width 60) */
198 int cy = (int)(row_h * 2.5f); /* header + row 1 center */
200 memset(&ev, 0, sizeof(ev));
201 ev.type = ALLEGRO_EVENT_MOUSE_BUTTON_DOWN;
202 ev.mouse.x = cx;
203 ev.mouse.y = cy;
204 ev.mouse.button = 2;
206 expect_true("context callback fired once", g_ctx_calls == 1);
207 expect_true("context row is 1", g_ctx_row == 1);
208 expect_true("context selects row 1", n_gui_datagrid_get_selected(gui, dg) == 1);
209 expect_true("context x echoes cursor", g_ctx_x == cx);
210 expect_true("context y echoes cursor", g_ctx_y == cy);
211
212 /* a left click selects but must not fire the context callback */
213 ev.type = ALLEGRO_EVENT_MOUSE_BUTTON_DOWN;
214 ev.mouse.button = 1;
216 ev.type = ALLEGRO_EVENT_MOUSE_BUTTON_UP;
218 expect_true("left click does not fire context", g_ctx_calls == 1);
219 }
220
221 /* multi-row selection: enable it, build a selection programmatically, query it,
222 then confirm a plain click collapses to one row and a sort clears it */
223 {
224 int sel[8];
225 size_t k;
226 ALLEGRO_EVENT ev;
227 float row_h = (float)al_get_font_line_height(font) + gui->style.item_height_pad;
230 expect_true("multiselect: none selected initially", n_gui_datagrid_get_selected_rows(gui, dg, NULL, 0) == 0);
233 expect_true("multiselect: two rows selected", n_gui_datagrid_get_selected_rows(gui, dg, NULL, 0) == 2);
234 expect_true("multiselect: row 0 is selected", n_gui_datagrid_is_row_selected(gui, dg, 0) == 1);
235 expect_true("multiselect: row 1 is not selected", n_gui_datagrid_is_row_selected(gui, dg, 1) == 0);
236 k = n_gui_datagrid_get_selected_rows(gui, dg, sel, 8);
237 expect_true("multiselect: indices are 0 and 2, ascending", k == 2 && sel[0] == 0 && sel[1] == 2);
238 n_gui_datagrid_select_row(gui, dg, 0, 0); /* deselect row 0 */
239 expect_true("multiselect: one selected after deselect", n_gui_datagrid_get_selected_rows(gui, dg, NULL, 0) == 1);
240
241 /* a plain left click (no Ctrl/Shift) collapses the selection to one row */
242 memset(&ev, 0, sizeof(ev));
243 ev.type = ALLEGRO_EVENT_MOUSE_BUTTON_DOWN;
244 ev.mouse.x = 30;
245 ev.mouse.y = (int)(row_h * 1.5f); /* header + row 0 center */
246 ev.mouse.button = 1;
248 ev.type = ALLEGRO_EVENT_MOUSE_BUTTON_UP;
250 expect_true("multiselect: plain click selects exactly one", n_gui_datagrid_get_selected_rows(gui, dg, NULL, 0) == 1);
251 expect_true("multiselect: plain click selects row 0", n_gui_datagrid_is_row_selected(gui, dg, 0) == 1);
252
253 /* a sort changes row indices, so it clears the selection */
255 n_gui_datagrid_sort(gui, dg, 0, -1);
256 expect_true("multiselect: sort clears the selection", n_gui_datagrid_get_selected_rows(gui, dg, NULL, 0) == 0);
257
258 /* with multi-select off, the query reports the single selected row */
261 expect_true("single-select: get_selected_rows reports one", n_gui_datagrid_get_selected_rows(gui, dg, NULL, 0) == 1);
262 }
263
264 /* ---- per-row background tints: set, query, follow a sort, and clear ---- */
265 {
266 ALLEGRO_COLOR got;
267 const char* r0[] = {"3", "GET", "200"};
268 const char* r1[] = {"1", "POST", "404"};
269 const char* r2[] = {"2", "GET", "500"};
274
275 expect_true("no tint by default", n_gui_datagrid_get_row_color(gui, dg, 0, NULL) == 0);
276 n_gui_datagrid_set_row_color(gui, dg, 0, al_map_rgb(255, 0, 0)); /* id 3 -> red */
277 n_gui_datagrid_set_row_color(gui, dg, 2, al_map_rgb(0, 0, 255)); /* id 2 -> blue */
278 expect_true("row 0 tinted", n_gui_datagrid_get_row_color(gui, dg, 0, &got) == 1 && got.r > 0.9f && got.b < 0.1f);
279 expect_true("row 1 untinted", n_gui_datagrid_get_row_color(gui, dg, 1, NULL) == 0);
280 expect_true("row 2 tinted", n_gui_datagrid_get_row_color(gui, dg, 2, &got) == 1 && got.b > 0.9f && got.r < 0.1f);
281 expect_true("out-of-range row has no tint", n_gui_datagrid_get_row_color(gui, dg, 9, NULL) == 0);
282
283 /* a sort reorders the cells physically, so the tints must travel with
284 their rows: after ascending on the id column the order is 1, 2, 3, so
285 the blue row (id 2) lands at index 1 and the red row (id 3) at index 2 */
286 n_gui_datagrid_sort(gui, dg, 0, 1);
287 expect_streq("tint sort: row0 is id 1", n_gui_datagrid_get_cell(gui, dg, 0, 0), "1");
288 expect_true("tint sort: row 0 (id 1) still untinted", n_gui_datagrid_get_row_color(gui, dg, 0, NULL) == 0);
289 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);
290 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);
291
292 /* a sort shrinks the cell buffer to nb_rows; the tint arrays shrink with
293 it, so adding rows afterwards must still grow them safely */
294 {
295 const char* r3[] = {"9", "PUT", "301"};
297 n_gui_datagrid_set_row_color(gui, dg, 3, al_map_rgb(0, 255, 0));
298 expect_true("tint after sort+add", n_gui_datagrid_get_row_color(gui, dg, 3, &got) == 1 && got.g > 0.9f);
299 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);
300 }
301
303 expect_true("single tint cleared", n_gui_datagrid_get_row_color(gui, dg, 2, NULL) == 0);
304 expect_true("other tint kept", n_gui_datagrid_get_row_color(gui, dg, 1, NULL) == 1);
306 expect_true("all tints cleared", n_gui_datagrid_get_row_color(gui, dg, 1, NULL) == 0);
307
308 /* clearing the rows drops their tints: rebuilt rows start untinted */
309 n_gui_datagrid_set_row_color(gui, dg, 0, al_map_rgb(255, 255, 0));
312 expect_true("clear_rows drops tints", n_gui_datagrid_get_row_color(gui, dg, 0, NULL) == 0);
313 }
314
315 /* ---- scroll offset: set, read back, clamp, and survive a rebuild ---- */
316 {
317 int i;
319 expect_true("scroll of empty grid is 0", n_gui_datagrid_get_scroll_offset(gui, dg) == 0);
320 for (i = 0; i < 40; i++) {
321 char a[16], b[16], c[16];
322 const char* r[3];
323 snprintf(a, sizeof(a), "%d", i);
324 snprintf(b, sizeof(b), "M%d", i);
325 snprintf(c, sizeof(c), "%d", 200 + i);
326 r[0] = a;
327 r[1] = b;
328 r[2] = c;
330 }
332 expect_true("scroll offset set to 12", n_gui_datagrid_get_scroll_offset(gui, dg) == 12);
333 /* the host preserves scroll across an in-place edit: save, clear+refill, restore */
334 {
335 int saved = n_gui_datagrid_get_scroll_offset(gui, dg);
337 for (i = 0; i < 40; i++) {
338 char a[16];
339 const char* r[3];
340 snprintf(a, sizeof(a), "%d", i);
341 r[0] = a;
342 r[1] = "M";
343 r[2] = "200";
345 }
347 expect_true("scroll offset survives a clear/refill", n_gui_datagrid_get_scroll_offset(gui, dg) == 12);
348 }
349 /* an over-range offset clamps into the row range */
351 expect_true("scroll offset clamps to last row", n_gui_datagrid_get_scroll_offset(gui, dg) == 39);
353 expect_true("scroll offset clamps to 0", n_gui_datagrid_get_scroll_offset(gui, dg) == 0);
354 }
355
356 /* ---- horizontal scroll: set, read back, clamp >= 0, survive a row refill ---- */
357 {
358 /* widen a column so the total content can exceed a typical pane (h-scroll is
359 meaningful); the getter/setter are the persistence hook the host uses to keep
360 the horizontal position across an in-place edit, like the vertical one above */
361 n_gui_datagrid_set_column_width(gui, dg, 2, 400.0f);
363 expect_true("h_scroll set to 80", n_gui_datagrid_get_h_scroll(gui, dg) == 80.0f);
364 /* the horizontal position is column-based, so a row clear/refill keeps it */
365 {
366 const char* r[3] = {"1", "M", "200"};
369 expect_true("h_scroll survives a row refill", n_gui_datagrid_get_h_scroll(gui, dg) == 80.0f);
370 }
371 /* a negative offset clamps to 0 (the draw path re-clamps the upper bound live) */
372 n_gui_datagrid_set_h_scroll(gui, dg, -25.0f);
373 expect_true("h_scroll clamps to 0", n_gui_datagrid_get_h_scroll(gui, dg) == 0.0f);
375 }
376
378 expect_true("cleared row count is 0", n_gui_datagrid_get_row_count(gui, dg) == 0);
379
380 /* a sort reallocates the cell buffer to exactly nb_rows; adding more rows
381 afterwards must still grow safely (regression: rows_cap was left stale, so
382 the next add_row wrote past the shrunken buffer -> heap overflow). Stress
383 the add -> sort -> add cycle so ASan catches any out-of-bounds write. */
384 {
385 int i;
386 for (i = 0; i < 25; i++) {
387 char a[16], b[16], c[16];
388 const char* r[3];
389 snprintf(a, sizeof(a), "%d", 25 - i);
390 snprintf(b, sizeof(b), "GET%d", i);
391 snprintf(c, sizeof(c), "%d", 200 + (i % 5));
392 r[0] = a;
393 r[1] = b;
394 r[2] = c;
396 }
397 n_gui_datagrid_sort(gui, dg, 0, 1); /* shrinks the buffer to nb_rows */
398 for (i = 0; i < 25; i++) { /* push back past the shrunken cap */
399 char a[16];
400 const char* r[3];
401 snprintf(a, sizeof(a), "%d", 100 + i);
402 r[0] = a;
403 r[1] = "POST";
404 r[2] = "201";
406 }
407 expect_true("rows after sort+add", n_gui_datagrid_get_row_count(gui, dg) == 50);
409 }
410
411 /* ---- column customization: count/title, resize-by-drag, width, visibility,
412 and reorder (the display-order indirection over the physical cells) ---- */
413 expect_true("column count is 3", n_gui_datagrid_get_column_count(gui, dg) == 3);
414 expect_streq("column 1 title", n_gui_datagrid_get_column_title(gui, dg, 1), "Method");
415 expect_streq("out-of-range title", n_gui_datagrid_get_column_title(gui, dg, 9), "");
416
417 /* dragging column 0's right border (at x=60) widens it and fires the callback */
419 {
420 ALLEGRO_EVENT ev;
421 float row_h = (float)al_get_font_line_height(font) + gui->style.item_height_pad;
422 float w0 = n_gui_datagrid_get_column_width(gui, dg, 0);
423 memset(&ev, 0, sizeof(ev));
424 ev.type = ALLEGRO_EVENT_MOUSE_BUTTON_DOWN;
425 ev.mouse.button = 1;
426 ev.mouse.x = 60;
427 ev.mouse.y = (int)(row_h * 0.5f);
429 ev.type = ALLEGRO_EVENT_MOUSE_AXES;
430 ev.mouse.x = 100;
432 ev.type = ALLEGRO_EVENT_MOUSE_BUTTON_UP;
434 expect_true("resize widened column 0", n_gui_datagrid_get_column_width(gui, dg, 0) > w0 + 20.0f);
435 expect_true("on_columns_changed fired once", g_cols_changed == 1);
436 }
437
438 /* width setter and its minimum clamp */
439 n_gui_datagrid_set_column_width(gui, dg, 2, 150.0f);
440 expect_true("column width set", n_gui_datagrid_get_column_width(gui, dg, 2) == 150.0f);
442 expect_true("column width min clamp", n_gui_datagrid_get_column_width(gui, dg, 2) == 16.0f);
443
444 /* visibility toggle */
445 expect_true("col 1 visible by default", n_gui_datagrid_get_column_visible(gui, dg, 1) == 1);
447 expect_true("col 1 now hidden", n_gui_datagrid_get_column_visible(gui, dg, 1) == 0);
448
449 /* reorder: identity, then move display position 0 to 2 -> order {1,2,0} */
450 expect_true("display 0 -> phys 0", n_gui_datagrid_display_to_physical(gui, dg, 0) == 0);
452 expect_true("after move display 2 -> phys 0", n_gui_datagrid_display_to_physical(gui, dg, 2) == 0);
453 expect_true("after move display 0 -> phys 1", n_gui_datagrid_display_to_physical(gui, dg, 0) == 1);
454 expect_true("after move display 1 -> phys 2", n_gui_datagrid_display_to_physical(gui, dg, 1) == 2);
455 expect_true("out-of-range display maps to -1", n_gui_datagrid_display_to_physical(gui, dg, 9) == -1);
456
457 /* guards: bad ids and out-of-range moves are no-ops */
459 expect_true("count for bad id is 0", n_gui_datagrid_get_column_count(gui, -1) == 0);
460
462 al_destroy_font(font);
463
464 if (failures) {
465 n_log(LOG_ERR, "ex_gui_datagrid: %d failure(s)", failures);
466 return 1;
467 }
468 n_log(LOG_NOTICE, "ex_gui_datagrid: all checks passed");
469 return 0;
470}
void process_args(int argc, char **argv)
static int failures
Definition ex_atlas.c:51
int main(void)
Definition ex_atlas.c:117
static void expect_true(const char *label, int cond)
Definition ex_atlas.c:53
static int log_level
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
static const char * row(N_GUI_TREE *tree, int index)
the text of a visible row, "" past the end
FONT * font
the default 8x8 font, valid after allegro_init()
void n_gui_set_display_size(N_GUI_CTX *ctx, float w, float h)
set the display (viewport) size so global scrollbars can be computed.
Definition n_gui.c:12348
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:5559
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:5537
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:5306
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:5401
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:5286
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:5292
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:5481
float n_gui_datagrid_get_h_scroll(N_GUI_CTX *ctx, int widget_id)
Definition n_gui.c:5459
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:5391
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:5432
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:5345
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:5426
int n_gui_process_event(N_GUI_CTX *ctx, ALLEGRO_EVENT event)
Process an allegro event through the GUI system.
Definition n_gui.c:13611
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:5317
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:5336
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:5153
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:5465
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:5323
#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:276
float n_gui_datagrid_columns_width(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:5443
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:5522
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:5409
void n_gui_datagrid_clear_selection(N_GUI_CTX *ctx, int widget_id)
clear the entire selection (no row selected)
Definition n_gui.c:5366
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:1277
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:5375
N_GUI_CTX * n_gui_new_ctx(ALLEGRO_FONT *default_font)
Create a new GUI context.
Definition n_gui.c:1103
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:5268
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:5516
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:5510
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:5486
void n_gui_destroy_ctx(N_GUI_CTX **ctx)
Destroy a GUI context and all its windows/widgets.
Definition n_gui.c:1209
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:5210
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:5504
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:5492
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:2515
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:5419
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:5300
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:5498
#define N_GUI_SHAPE_RECT
rectangle shape (default)
Definition n_gui.h:170
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:3460
int n_gui_add_button(N_GUI_CTX *ctx, int window_id, const char *label, float x, float y, float w, float h, int shape, void(*on_click)(int, void *), void *user_data)
Add a button widget to a window.
Definition n_gui.c:2720
The top-level GUI context that holds all windows.
Definition n_gui.h:1669
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:113
#define LOG_DEBUG
debug-level messages
Definition n_log.h:108
#define LOG_ERR
error conditions
Definition n_log.h:100
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL ).
Definition n_log.c:123
#define LOG_NOTICE
normal but significant condition
Definition n_log.h:104
#define LOG_NULL
no log output
Definition n_log.h:70
#define LOG_INFO
informational
Definition n_log.h:106
Common headers and low-level functions & define.
GUI system: buttons, sliders, text areas, checkboxes, scrollbars, dropdown menus, windows.
Generic log system.