Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
ex_gui_kvtable.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
42
43#define ALLEGRO_UNSTABLE 1
44
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <unistd.h>
49
50#include "nilorea/n_common.h"
51#include "nilorea/n_log.h"
52#include "nilorea/n_gui.h"
53
54static int log_level = LOG_ERR;
55
56static int process_args(int argc, char** argv) {
57 int opt;
58 while ((opt = getopt(argc, argv, "V:")) != -1) {
59 switch (opt) {
60 case 'V':
61 if (!strcmp("LOG_NULL", optarg))
63 else if (!strcmp("LOG_NOTICE", optarg))
65 else if (!strcmp("LOG_INFO", optarg))
67 else if (!strcmp("LOG_ERR", optarg))
69 else if (!strcmp("LOG_DEBUG", optarg))
71 else
72 return -1;
73 break;
74 default:
75 return -1;
76 }
77 }
78 return 0;
79}
80
81static int failures = 0;
82
83static void expect_close(const char* label, float got, float want, float tol) {
84 float d = got - want;
85 if (d < 0) d = -d;
86 if (d > tol) {
87 n_log(LOG_ERR, "%s: got %.3f, expected %.3f (tol %.3f)",
88 label, got, want, tol);
89 failures++;
90 } else {
91 n_log(LOG_INFO, "%s: %.3f ~= %.3f OK", label, got, want);
92 }
93}
94
95static void expect_true(const char* label, int cond) {
96 if (!cond) {
97 n_log(LOG_ERR, "%s: condition false", label);
98 failures++;
99 } else {
100 n_log(LOG_INFO, "%s: OK", label);
101 }
102}
103
104int main(int argc, char** argv) {
106 if (process_args(argc, argv) != 0) {
107 fprintf(stderr, "Usage: %s [-V LOG_LEVEL]\n", argv[0]);
108 return 2;
109 }
111
112 if (!al_init()) {
113 n_log(LOG_ERR, "al_init failed");
114 return 1;
115 }
116 if (!al_init_font_addon()) {
117 n_log(LOG_ERR, "al_init_font_addon failed");
118 return 1;
119 }
120
121 /* Builtin font does not need a display. */
122 ALLEGRO_FONT* font = al_create_builtin_font();
123 if (!font) {
124 n_log(LOG_ERR, "al_create_builtin_font failed");
125 return 1;
126 }
127
129 if (!gui) {
130 n_log(LOG_ERR, "n_gui_new_ctx failed");
131 al_destroy_font(font);
132 return 1;
133 }
134
135 /* Reference display matches the parent panel size used in Hook's
136 request panel (params/headers tab). Set display size BEFORE
137 switching to adaptive mode so ref_display_w/h is captured. */
138 n_gui_set_display_size(gui, 800.0f, 258.0f);
140
141 int win = n_gui_add_window(gui, "Panel", 0.0f, 0.0f, 800.0f, 258.0f);
142 expect_true("window created", win >= 0);
144
145 N_GUI_KVTABLE* kv = n_gui_kvtable_create(gui, win, 28.0f, 4.0f, NULL, NULL);
146 expect_true("kvtable created", kv != NULL);
147
148 /* Initial: one empty row, like Hook does. */
149 n_gui_kvtable_add_row(kv, "", "", "", 1);
150
151 N_GUI_WIDGET* add_btn = n_gui_get_widget(gui, kv->btn_add);
152 N_GUI_WIDGET* row0_key = n_gui_get_widget(gui, kv->rows[0].key_id);
153 expect_true("add button widget exists", add_btn != NULL);
154 expect_true("row 0 key widget exists", row0_key != NULL);
155
156 /* At initial size, "+" button must sit strictly below row 0. */
157 expect_true("+ below row 0 (initial)",
158 add_btn->y >= row0_key->y + row0_key->h - 0.5f);
159
160 /* Resize the display: window scales by 2x in both dimensions. */
161 n_gui_set_display_size(gui, 1600.0f, 516.0f);
162
163 /* After resize via apply_adaptive_resize, fetch fresh pointers
164 (same widgets, but their x/y/w/h have moved). */
165 add_btn = n_gui_get_widget(gui, kv->btn_add);
166 row0_key = n_gui_get_widget(gui, kv->rows[0].key_id);
167 expect_true("+ still exists after resize", add_btn != NULL);
168
169 /* The bug was: after resize, "+" reverted to the same y as row 0.
170 It should remain at or below row 0's bottom edge. */
171 expect_true("+ below row 0 (after resize)",
172 add_btn->y >= row0_key->y + row0_key->h - 0.5f);
173
174 /* Record row 0's scaled height for later comparison. */
175 float scaled_row_h = row0_key->h;
176 n_log(LOG_INFO, "row 0 scaled height after resize: %.3f", scaled_row_h);
177
178 /* Clear all rows then add new ones, mimicking Hook's "delete all
179 lines then add new lines" path on a maximized window. */
180 for (int i = kv->nb_rows - 1; i >= 0; i--) {
182 }
183 n_gui_kvtable_add_row(kv, "k", "v", "d", 1);
184 n_gui_kvtable_add_row(kv, "k2", "v2", "d2", 1);
185
186 add_btn = n_gui_get_widget(gui, kv->btn_add);
187 N_GUI_WIDGET* lbl_key = n_gui_get_widget(gui, kv->lbl_key);
188
189 /* "+" must NOT overlap the "Key" header label. */
190 expect_true("+ button below Key header (after clear+add)",
191 add_btn->y >= lbl_key->y + lbl_key->h - 0.5f);
192
193 /* New rows must match the scaled row height (within rounding tolerance). */
194 int last_active = -1;
195 for (int i = 0; i < kv->nb_rows; i++) {
196 if (kv->rows[i].active) last_active = i;
197 }
198 expect_true("at least one active row exists", last_active >= 0);
199 if (last_active >= 0) {
200 N_GUI_WIDGET* new_key = n_gui_get_widget(gui, kv->rows[last_active].key_id);
201 expect_close("new row height matches scaled row height",
202 new_key->h, scaled_row_h, 0.5f);
203 /* "+" sits immediately below the last active row. */
204 expect_true("+ directly below last active row",
205 add_btn->y >= new_key->y + new_key->h - 0.5f);
206 }
207
208 /* Public relayout entry-point smoke test. */
210 add_btn = n_gui_get_widget(gui, kv->btn_add);
211 expect_true("+ still placed after manual relayout",
212 add_btn != NULL && add_btn->y > 0.0f);
213
214 /* Reload-safe clear: repopulating the same row count reuses the freed
215 slots instead of growing the widget array toward N_GUI_KV_MAX. */
217 expect_true("clear -> 0 active rows", n_gui_kvtable_get_count(kv) == 0);
218 n_gui_kvtable_add_row(kv, "a", "1", "", 1);
219 n_gui_kvtable_add_row(kv, "b", "2", "", 1);
220 n_gui_kvtable_add_row(kv, "c", "3", "", 1);
221 int rows_after_first_fill = kv->nb_rows;
222 expect_true("3 active rows after fill", n_gui_kvtable_get_count(kv) == 3);
224 n_gui_kvtable_add_row(kv, "a", "1", "", 1);
225 n_gui_kvtable_add_row(kv, "b", "2", "", 1);
226 n_gui_kvtable_add_row(kv, "c", "3", "", 1);
227 expect_true("3 active rows after reload", n_gui_kvtable_get_count(kv) == 3);
228 expect_true("reload reuses slots (nb_rows does not grow)",
229 kv->nb_rows == rows_after_first_fill);
230
231 /* Single-column mode: only the key column and the remove button are shown;
232 the value/description/enabled widgets (and their headers) are hidden, and
233 the key column widens to fill the row. */
234 n_gui_kvtable_set_columns(kv, 0, 0, 0);
235 n_gui_kvtable_set_placeholders(kv, "host, .suffix, * or re:regex", NULL);
237 n_gui_kvtable_add_row(kv, ".example.com", "", "", 1);
238 {
239 int active = -1;
240 for (int i = 0; i < kv->nb_rows; i++) {
241 if (kv->rows[i].active) {
242 active = i;
243 break;
244 }
245 }
246 expect_true("single-column: one active row", active >= 0);
247 if (active >= 0) {
248 N_GUI_WIDGET* wk = n_gui_get_widget(gui, kv->rows[active].key_id);
249 N_GUI_WIDGET* wv = n_gui_get_widget(gui, kv->rows[active].value_id);
250 N_GUI_WIDGET* wd = n_gui_get_widget(gui, kv->rows[active].desc_id);
251 N_GUI_WIDGET* we = n_gui_get_widget(gui, kv->rows[active].enabled_id);
252 N_GUI_WIDGET* wr = n_gui_get_widget(gui, kv->rows[active].remove_id);
253 const N_GUI_WINDOW* wwin = n_gui_get_window(gui, win);
254 expect_true("single-column: key visible", wk && wk->visible);
255 expect_true("single-column: remove visible", wr && wr->visible);
256 expect_true("single-column: value hidden", wv && !wv->visible);
257 expect_true("single-column: description hidden", wd && !wd->visible);
258 expect_true("single-column: enabled hidden", we && !we->visible);
259 expect_true("single-column: value header hidden",
261 expect_true("single-column: key column widened",
262 wk && wwin && wk->w > wwin->w * 0.5f);
263 }
264 }
265
266 /* Top offset reserves space above the header row (for a toolbar/heading in
267 a shared window); the header (and rows) shift down by the scaled offset. */
268 {
269 N_GUI_WIDGET* lk_before = n_gui_get_widget(gui, kv->lbl_key);
270 float y_before = lk_before ? lk_before->y : 0.0f;
272 N_GUI_WIDGET* lk_after = n_gui_get_widget(gui, kv->lbl_key);
273 expect_true("top_offset pushes the header row down",
274 lk_after && lk_after->y > y_before + 10.0f);
275 }
276
277 /* Row heights follow the window only when the window scales its widgets. The
278 table above lives in a SCALE-policy window, so its rows scaled with the
279 display resize (asserted earlier). A MOVE-policy window instead keeps the
280 widgets' pixel layout, so the rows must keep their design height and a taller
281 window simply shows more of them, rather than the same rows drawn fatter. */
282 {
283 int win2 = n_gui_add_window(gui, "MovePanel", 0.0f, 0.0f, 800.0f, 258.0f);
285 N_GUI_KVTABLE* kv2 = n_gui_kvtable_create(gui, win2, 24.0f, 8.0f, NULL, NULL);
286 expect_true("move-policy table created", kv2 != NULL);
287 if (kv2) {
288 n_gui_kvtable_add_row(kv2, "k", "v", "d", 1);
290 float h_before = r0 ? r0->h : 0.0f;
291 expect_true("move-policy row has a height", h_before > 0.0f);
292
293 /* grow the window vertically only, then relayout */
294 N_GUI_WINDOW* w2 = n_gui_get_window(gui, win2);
295 if (w2) w2->h *= 2.0f;
297
298 r0 = n_gui_get_widget(gui, kv2->rows[0].key_id);
299 expect_close("move-policy row keeps its height", r0 ? r0->h : -1.0f, h_before, 0.5f);
300
301 /* a row added after the growth matches the existing ones */
302 n_gui_kvtable_add_row(kv2, "k2", "v2", "d2", 1);
304 expect_close("move-policy new row matches", r1 ? r1->h : -1.0f, h_before, 0.5f);
305
306 /* widths still follow the window: widen it and the key column grows */
307 N_GUI_WIDGET* k_before = n_gui_get_widget(gui, kv2->rows[0].key_id);
308 float w_before = k_before ? k_before->w : 0.0f;
309 if (w2) w2->w *= 2.0f;
311 N_GUI_WIDGET* k_after = n_gui_get_widget(gui, kv2->rows[0].key_id);
312 expect_true("move-policy key column still widens",
313 k_after && k_after->w > w_before + 1.0f);
314
315 n_gui_kvtable_free(&kv2);
316 }
317 }
318
319 /* Per-row actions: move up / move down / duplicate. Row slots are stable
320 (widgets are bound to them, freed slots are reused), so the operations
321 move the CONTENT and everything that walks the rows in slot order sees
322 the new order. */
323 {
324 int win3 = n_gui_add_window(gui, "ActionPanel", 0.0f, 0.0f, 800.0f, 300.0f);
325 N_GUI_KVTABLE* kv3 = n_gui_kvtable_create(gui, win3, 24.0f, 8.0f, NULL, NULL);
326 expect_true("actions table created", kv3 != NULL);
327 if (kv3) {
328 expect_true("actions off by default", kv3->show_actions == 0);
330 expect_true("actions enabled", kv3->show_actions == 1);
331 expect_true("add button drawn as a glyph",
333
334 n_gui_kvtable_add_row(kv3, "a", "1", "first", 1);
335 n_gui_kvtable_add_row(kv3, "b", "2", "second", 0);
336 n_gui_kvtable_add_row(kv3, "c", "3", "third", 1);
337 expect_true("three rows", n_gui_kvtable_get_count(kv3) == 3);
338
339 /* the action buttons are laid out inside the row, left of remove */
340 {
345 expect_true("action widgets exist", up && dn && dp && rm);
346 if (up && dn && dp && rm) {
347 expect_true("actions visible", up->visible && dn->visible && dp->visible);
348 expect_true("actions ordered up, down, duplicate, remove",
349 up->x < dn->x && dn->x < dp->x && dp->x < rm->x);
350 expect_true("actions stay inside the window", rm->x + rm->w <= 800.0f);
351 expect_true("actions share the row",
352 up->y == rm->y && dn->y == rm->y && dp->y == rm->y);
353 }
354 /* first row cannot move up, last cannot move down */
355 expect_true("first row up disabled",
357 expect_true("first row down enabled",
359 expect_true("last row down disabled",
361 }
362
363 /* move "c" up: rows read a, c, b */
364 expect_true("move up returns the target slot",
365 n_gui_kvtable_move_row(kv3, 2, -1) == 1);
366 expect_true("row 1 is now c",
367 strcmp(n_gui_textarea_get_text(gui, kv3->rows[1].key_id), "c") == 0);
368 expect_true("row 2 is now b",
369 strcmp(n_gui_textarea_get_text(gui, kv3->rows[2].key_id), "b") == 0);
370 expect_true("the enabled flag travels with the row",
372
373 /* edges refuse to move */
374 expect_true("first row cannot move up", n_gui_kvtable_move_row(kv3, 0, -1) == -1);
375 expect_true("last row cannot move down", n_gui_kvtable_move_row(kv3, 2, 1) == -1);
376
377 /* duplicate row 0 ("a"): rows read a, a, c, b */
378 expect_true("duplicate lands right after the source",
379 n_gui_kvtable_duplicate_row(kv3, 0) == 1);
380 expect_true("four rows after duplicate", n_gui_kvtable_get_count(kv3) == 4);
381 expect_true("copy holds the source key",
382 strcmp(n_gui_textarea_get_text(gui, kv3->rows[1].key_id), "a") == 0);
383 expect_true("copy holds the source value",
384 strcmp(n_gui_textarea_get_text(gui, kv3->rows[1].value_id), "1") == 0);
385 expect_true("copy holds the source description",
386 strcmp(n_gui_textarea_get_text(gui, kv3->rows[1].desc_id), "first") == 0);
387 expect_true("source is untouched",
388 strcmp(n_gui_textarea_get_text(gui, kv3->rows[0].key_id), "a") == 0);
389 expect_true("rows after the copy shifted down",
390 strcmp(n_gui_textarea_get_text(gui, kv3->rows[2].key_id), "c") == 0 &&
391 strcmp(n_gui_textarea_get_text(gui, kv3->rows[3].key_id), "b") == 0);
392
393 /* a removed slot in the middle is reused, and the copy still lands
394 next to its source rather than in whatever slot came free */
396 expect_true("three rows after remove", n_gui_kvtable_get_count(kv3) == 3);
397 expect_true("duplicate of the last row appends",
398 n_gui_kvtable_duplicate_row(kv3, 3) >= 0);
399 {
400 int order[8], n = 0;
401 for (int i = 0; i < kv3->nb_rows && n < 8; i++) {
402 if (kv3->rows[i].active) order[n++] = i;
403 }
404 expect_true("four rows again", n == 4);
405 if (n == 4) {
406 expect_true("order is a, c, b, b",
407 strcmp(n_gui_textarea_get_text(gui, kv3->rows[order[0]].key_id), "a") == 0 &&
408 strcmp(n_gui_textarea_get_text(gui, kv3->rows[order[1]].key_id), "c") == 0 &&
409 strcmp(n_gui_textarea_get_text(gui, kv3->rows[order[2]].key_id), "b") == 0 &&
410 strcmp(n_gui_textarea_get_text(gui, kv3->rows[order[3]].key_id), "b") == 0);
411 }
412 }
413
414 /* turning the actions off hides the buttons and restores the plain
415 three-column layout, remove button included */
416 {
422 expect_true("actions hidden", up && dn && dp && !up->visible && !dn->visible && !dp->visible);
423 expect_true("remove button stays", rm && rm->visible);
424 expect_true("row still fits the window", rm && rm->x + rm->w <= 800.0f);
425 expect_true("remove button back to its label",
427 expect_true("add button back to its label",
429 }
430
431 n_gui_kvtable_free(&kv3);
432 }
433 }
434
437 al_destroy_font(font);
438
439 if (failures > 0) {
440 n_log(LOG_ERR, "ex_gui_kvtable: %d check(s) failed", failures);
441 return 1;
442 }
443 n_log(LOG_NOTICE, "ex_gui_kvtable: all checks passed");
444 return 0;
445}
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 N_GUI_CTX * gui
static void expect_close(const char *label, float got, float want, float tol)
FONT * font
the default 8x8 font, valid after allegro_init()
float h
height
Definition n_gui.h:1104
int visible
visibility flag
Definition n_gui.h:1114
int show_actions
1 to show the per-row move-up / move-down / duplicate buttons (default 0)
Definition n_gui.h:3662
int nb_rows
total rows (including removed)
Definition n_gui.h:3645
int btn_add
button widget ID for "+" add row
Definition n_gui.h:3656
float w
width
Definition n_gui.h:1102
int remove_id
button widget ID for the remove action
Definition n_gui.h:3630
float w
window width
Definition n_gui.h:1316
N_GUI_KV_ROW rows[128]
row storage
Definition n_gui.h:3644
int key_id
textarea widget ID for the key
Definition n_gui.h:3626
float x
position x relative to parent window
Definition n_gui.h:1098
int dup_id
button widget ID for the duplicate action (row actions only)
Definition n_gui.h:3633
int desc_id
textarea widget ID for the description
Definition n_gui.h:3628
int lbl_key
label widget ID for "Key" header
Definition n_gui.h:3652
float h
window height
Definition n_gui.h:1318
float y
position y relative to parent window
Definition n_gui.h:1100
int active
1 if active, 0 if removed
Definition n_gui.h:3634
int up_id
button widget ID for the move-up action (row actions only)
Definition n_gui.h:3631
int lbl_value
label widget ID for "Value" header
Definition n_gui.h:3653
int enabled_id
checkbox widget ID for the enabled toggle
Definition n_gui.h:3629
int down_id
button widget ID for the move-down action (row actions only)
Definition n_gui.h:3632
int value_id
textarea widget ID for the value
Definition n_gui.h:3627
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_kvtable_set_top_offset(N_GUI_KVTABLE *table, float top_offset)
reserve top_offset unscaled pixels above the header row so other widgets (a toolbar,...
Definition n_gui.c:19011
void n_gui_kvtable_relayout(N_GUI_KVTABLE *table)
re-apply layout to all KV table widgets (positions, sizes, normalized coords).
Definition n_gui.c:19021
int n_gui_kvtable_get_count(const N_GUI_KVTABLE *table)
get the number of active rows
Definition n_gui.c:19017
N_GUI_KVTABLE * n_gui_kvtable_create(N_GUI_CTX *ctx, int window_id, float row_height, float padding, void(*on_remove)(int, void *), void *user_data)
create a KV table in an existing window
Definition n_gui.c:18672
#define N_GUI_GLYPH_NONE
no glyph: the button draws its text label (default)
Definition n_gui.h:418
#define N_GUI_WIN_RESIZE_SCALE
reposition AND resize proportionally, child widgets scale too
Definition n_gui.h:333
void n_gui_kvtable_free(N_GUI_KVTABLE **table)
free a KV table (does not destroy the N_GUI widgets)
Definition n_gui.c:19025
void n_gui_window_set_resize_policy(N_GUI_CTX *ctx, int window_id, int policy)
Set per-window resize policy (N_GUI_WIN_RESIZE_NONE / _MOVE / _SCALE).
Definition n_gui.c:12132
void n_gui_kvtable_clear(N_GUI_KVTABLE *table)
remove every row at once.
Definition n_gui.c:18837
void n_gui_kvtable_set_placeholders(N_GUI_KVTABLE *table, const char *key_hint, const char *value_hint)
set the placeholder/hint text shown in each row's key (and value) textarea while it is empty.
Definition n_gui.c:18997
int n_gui_kvtable_move_row(N_GUI_KVTABLE *table, int row_index, int direction)
Move a row one position up or down among the active rows.
Definition n_gui.c:18912
void n_gui_kvtable_remove_row(N_GUI_KVTABLE *table, int row_index)
remove a row by index (hides widgets, marks inactive)
Definition n_gui.c:18819
int n_gui_button_get_glyph(N_GUI_CTX *ctx, int widget_id)
Get the glyph currently drawn on a button.
Definition n_gui.c:2859
int n_gui_is_widget_enabled(N_GUI_CTX *ctx, int widget_id)
Check if a widget is enabled.
Definition n_gui.c:3896
N_GUI_WIDGET * n_gui_get_widget(N_GUI_CTX *ctx, int widget_id)
Get a widget pointer by id.
Definition n_gui.c:3701
N_GUI_WINDOW * n_gui_get_window(N_GUI_CTX *ctx, int window_id)
Get a window pointer by id.
Definition n_gui.c:1397
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
N_GUI_CTX * n_gui_new_ctx(ALLEGRO_FONT *default_font)
Create a new GUI context.
Definition n_gui.c:1103
void n_gui_kvtable_set_row_actions(N_GUI_KVTABLE *table, int enabled)
Show or hide the per-row move-up / move-down / duplicate buttons.
Definition n_gui.c:18880
int n_gui_kvtable_duplicate_row(N_GUI_KVTABLE *table, int row_index)
Insert a copy of a row directly after it.
Definition n_gui.c:18956
void n_gui_set_resize_mode(N_GUI_CTX *ctx, int mode)
Set context-level resize mode: N_GUI_RESIZE_VIRTUAL (default) or N_GUI_RESIZE_ADAPTIVE.
Definition n_gui.c:12093
void n_gui_kvtable_set_columns(N_GUI_KVTABLE *table, int show_value, int show_desc, int show_enabled)
choose which optional columns are shown: Value, Description, and the enabled checkbox.
Definition n_gui.c:18858
#define N_GUI_GLYPH_PLUS
plus sign
Definition n_gui.h:428
void n_gui_destroy_ctx(N_GUI_CTX **ctx)
Destroy a GUI context and all its windows/widgets.
Definition n_gui.c:1209
const char * n_gui_textarea_get_text(N_GUI_CTX *ctx, int widget_id)
get the text content of a textarea widget
Definition n_gui.c:4196
int n_gui_kvtable_add_row(N_GUI_KVTABLE *table, const char *key, const char *value, const char *description, int enabled)
add a row to the KV table
Definition n_gui.c:18733
int n_gui_checkbox_is_checked(N_GUI_CTX *ctx, int widget_id)
check if a checkbox widget is checked
Definition n_gui.c:4237
#define N_GUI_WIN_RESIZE_MOVE
reposition proportionally, keep pixel size
Definition n_gui.h:331
#define N_GUI_RESIZE_ADAPTIVE
virtual size tracks display; windows adapt per their resize_policy
Definition n_gui.h:325
The top-level GUI context that holds all windows.
Definition n_gui.h:1669
key-value table built from textareas, checkboxes, and buttons.
Definition n_gui.h:3641
A single GUI widget.
Definition n_gui.h:1092
A pseudo window that contains widgets.
Definition n_gui.h:1298
#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.