47 al_set_clipboard_text(
display, text);
57 char* a = al_malloc(strlen(s) + 1);
71#define N_GUI_KEY_PRESS_FLASH_SEC 0.12
78#define N_GUI_ANIM_TAIL_SEC 0.05
83static double _clamp(
double v,
double lo,
double hi) {
84 if (v < lo)
return lo;
85 if (v > hi)
return hi;
93 if (step <= 0.0) step = 1.0;
94 double steps = round((val - min_val) / step);
95 double snapped = min_val + steps * step;
96 if (snapped < min_val) snapped = min_val;
97 if (snapped > max_val) snapped = max_val;
105 if (font && text) al_get_text_dimensions(font, text, &d.
x, &d.
y, &d.
w, &d.
h);
140 for (
char* src = s; *src; src++) {
141 if (*src !=
'\r') *dst++ = *src;
166#define N_GUI_MEAS_CACHE_SIZE 1024u
167#define N_GUI_MEAS_KEY_MAX 32
187 unsigned int h = 2166136261u;
188 for (
size_t i = 0; i < len; i++) {
189 h ^= (
unsigned char)text[i];
192 int line_h = al_get_font_line_height(font);
193 h ^= (
unsigned int)line_h * 2654435761u;
196 e->
len == (
unsigned short)len && memcmp(e->
key, text, len) == 0) {
203 e->
len = (
unsigned short)len;
204 memcpy(e->
key, text, len);
214static float _text_w(ALLEGRO_FONT* font,
const char* text) {
215 if (!font || !text || !text[0])
return 0.0f;
216 size_t len = strlen(text);
220 e->
adv_w = (float)al_get_text_width(font, text);
229static void _text_dims(ALLEGRO_FONT* font,
const char* text,
int* x,
int* y,
int* w,
int* h) {
230 int bx = 0, by = 0, bw = 0, bh = 0;
231 if (font && text && text[0]) {
232 size_t len = strlen(text);
234 al_get_text_dimensions(font, text, &bx, &by, &bw, &bh);
238 al_get_text_dimensions(font, text, &e->
dx, &e->
dy, &e->
dw, &e->
dh);
296 if (!al_get_mouse_cursor_position(&cx, &cy))
return;
298 al_get_window_position(win->
native, &wx, &wy);
320 int want_w = (int)(win->
w + 0.5f);
321 int want_h = minimised ? (int)(
_win_tbh(win) + 0.5f) : (int)(win->
h + 0.5f);
322 int resizable = (al_get_display_flags(win->
native) & ALLEGRO_RESIZABLE) ? 1 : 0;
323 if (want_w < 1) want_w = 1;
324 if (want_h < 1) want_h = 1;
332 if (resizable && minimised) {
333 int cmin_w = (int)(win->
min_w + 0.5f);
334 if (cmin_w < 1) cmin_w = 1;
335 if (al_set_window_constraints(win->
native, cmin_w, want_h, 0, 0))
336 al_apply_window_constraints(win->
native,
true);
339 if (want_w != al_get_display_width(win->
native) || want_h != al_get_display_height(win->
native)) {
340 al_resize_display(win->
native, want_w, want_h);
343 if (resizable && !minimised) {
344 int cmin_w = (int)(win->
min_w + 0.5f);
345 int cmin_h = (int)(win->
min_h + 0.5f);
346 if (cmin_w < 1) cmin_w = 1;
347 if (cmin_h < 1) cmin_h = 1;
348 if (al_set_window_constraints(win->
native, cmin_w, cmin_h, 0, 0))
349 al_apply_window_constraints(win->
native,
true);
362 if (!
display || !info)
return 0;
364 al_get_window_position(
display, &wx, &wy);
365 int nb_adapters = al_get_num_video_adapters();
366 for (
int adapter = 0; adapter < nb_adapters; adapter++) {
367 ALLEGRO_MONITOR_INFO mi;
368 if (!al_get_monitor_info(adapter, &mi))
continue;
369 if (wx >= mi.x1 && wx < mi.x2 && wy >= mi.y1 && wy < mi.y2) {
374 return al_get_monitor_info(0, info) ? 1 : 0;
381 switch (event->type) {
382 case ALLEGRO_EVENT_MOUSE_AXES:
383 case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
384 case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
385 case ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY:
386 case ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY:
387 case ALLEGRO_EVENT_MOUSE_WARPED:
388 return event->mouse.display;
389 case ALLEGRO_EVENT_KEY_DOWN:
390 case ALLEGRO_EVENT_KEY_UP:
391 case ALLEGRO_EVENT_KEY_CHAR:
392 return event->keyboard.display;
393 case ALLEGRO_EVENT_TOUCH_BEGIN:
394 case ALLEGRO_EVENT_TOUCH_END:
395 case ALLEGRO_EVENT_TOUCH_MOVE:
396 case ALLEGRO_EVENT_TOUCH_CANCEL:
397 return event->touch.display;
398 case ALLEGRO_EVENT_DISPLAY_EXPOSE:
399 case ALLEGRO_EVENT_DISPLAY_RESIZE:
400 case ALLEGRO_EVENT_DISPLAY_CLOSE:
401 case ALLEGRO_EVENT_DISPLAY_LOST:
402 case ALLEGRO_EVENT_DISPLAY_FOUND:
403 case ALLEGRO_EVENT_DISPLAY_SWITCH_IN:
404 case ALLEGRO_EVENT_DISPLAY_SWITCH_OUT:
405 case ALLEGRO_EVENT_DISPLAY_ORIENTATION:
406 case ALLEGRO_EVENT_DISPLAY_HALT_DRAWING:
407 case ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING:
408 return event->display.source;
429static int _point_in_rect(
float px,
float py,
float rx,
float ry,
float rw,
float rh) {
430 return (px >= rx && px <= rx + rw && py >= ry && py <= ry + rh);
461static float _scrollbar_calc_scroll(
float mouse,
float track_start,
float track_length,
float viewport,
float content,
float thumb_min) {
462 float ratio = viewport / content;
463 if (ratio > 1.0f) ratio = 1.0f;
464 float thumb = ratio * track_length;
465 if (thumb < thumb_min) thumb = thumb_min;
466 float max_scroll = content - viewport;
467 float track_range = track_length - thumb;
468 if (track_range <= 0 || max_scroll <= 0)
return 0;
469 float pos_ratio = (mouse - track_start - thumb / 2.0f) / track_range;
470 if (pos_ratio < 0) pos_ratio = 0;
471 if (pos_ratio > 1) pos_ratio = 1;
472 return pos_ratio * max_scroll;
484static int _scrollbar_calc_scroll_int(
float mouse,
float track_start,
float track_length,
int visible_items,
int total_items,
float thumb_min) {
485 int max_off = total_items - visible_items;
486 if (max_off <= 0)
return 0;
488 (
float)visible_items, (
float)total_items, thumb_min);
489 int offset = (int)(scroll + 0.5f);
490 if (offset < 0) offset = 0;
491 if (offset > max_off) offset = max_off;
590 if (win && win->
id == window_id)
return node;
600 snprintf(
key,
sizeof(
key),
"%d", w->
id);
608 size_t new_cap = (*cap == 0) ? 8 : (*cap) * 2;
609 if (new_cap < *cap)
return 0;
613 if (*items && *nb > 0) {
653 t.
bg_normal = al_map_rgba(50, 50, 60, 230);
654 t.
bg_hover = al_map_rgba(70, 70, 85, 240);
655 t.
bg_active = al_map_rgba(90, 90, 110, 250);
660 t.
text_hover = al_map_rgba(255, 255, 255, 255);
687 ALLEGRO_COLOR bg_hover,
688 ALLEGRO_COLOR bg_active,
689 ALLEGRO_COLOR border,
690 ALLEGRO_COLOR border_hover,
691 ALLEGRO_COLOR border_active,
693 ALLEGRO_COLOR text_hover,
694 ALLEGRO_COLOR text_active,
695 float border_thickness,
731 t.
bg_hover = al_map_rgba(255, 255, 255, 40);
732 t.
bg_active = al_map_rgba(255, 255, 255, 80);
737 t.
text_hover = al_map_rgba(255, 255, 255, 255);
753 t.
bg_hover = al_map_rgba(232, 17, 35, 220);
754 t.
bg_active = al_map_rgba(200, 10, 25, 255);
831 s.
grip_color = al_map_rgba(160, 160, 180, 200);
910 n_log(
LOG_ERR,
"n_gui_new_ctx: failed to allocate window list");
916 n_log(
LOG_ERR,
"n_gui_new_ctx: failed to allocate widget hash table");
928 ctx->
cursor_shape = ALLEGRO_SYSTEM_MOUSE_CURSOR_DEFAULT;
975 if (ctx) ctx->
dirty = 1;
980 if (ctx->
dirty)
return 1;
998 if ((*ctx)->windows) {
1004 if (dwin && dwin->
native) {
1010 if ((*ctx)->widgets_by_id) {
1026 if (dw <= 0 || dh <= 0)
return;
1047 if (win->
w > 0 && win->
h > 0) {
1073 win->
title[0] =
'\0';
1083 n_log(
LOG_ERR,
"n_gui_add_window: failed to allocate widget list");
1194 win->
state &= ~N_GUI_WIN_OPEN;
1245 win->
state &= ~N_GUI_WIN_MINIMISED;
1288 win->
state &= ~N_GUI_WIN_MINIMISED;
1291 if (!al_set_display_flag(win->
native, ALLEGRO_MAXIMIZED, now_max ?
false :
true)) {
1292 n_log(
LOG_DEBUG,
"n_gui_maximize_window: window manager refused ALLEGRO_MAXIMIZED for window %d", window_id);
1296 ALLEGRO_MONITOR_INFO mi;
1298 al_set_window_position(win->
native, mi.x1, mi.y1);
1299 al_resize_display(win->
native, mi.x2 - mi.x1, mi.y2 - mi.y1);
1307 win->
state &= ~N_GUI_WIN_MAXIMISED;
1319 win->
state &= ~N_GUI_WIN_MAXIMISED;
1327 win->
state &= ~N_GUI_WIN_MINIMISED;
1375 if (!win || !win->
native)
return;
1376 ALLEGRO_DISPLAY* d = win->
native;
1381 al_get_window_position(d, &wx, &wy);
1384 win->
native_w = (float)al_get_display_width(d);
1385 win->
native_h = (float)al_get_display_height(d);
1395 al_unregister_event_source(ctx->
event_queue, al_get_display_event_source(d));
1397 al_destroy_display(d);
1402 al_set_target_backbuffer(ctx->
display);
1413 n_log(
LOG_ERR,
"n_gui_window_detach: no window with id %d", window_id);
1421 n_log(
LOG_ERR,
"n_gui_window_detach: no event queue set, call n_gui_set_event_queue first");
1433 float shown_h = own_chrome ? win->
h : (win->
h -
_win_tbh(win));
1434 if (shown_h < 1.0f) shown_h = win->
h;
1435 int dw = (int)(win->
w + 0.5f);
1436 int dh = (int)(shown_h + 0.5f);
1446 ALLEGRO_BITMAP* prev_target = al_get_target_bitmap();
1447 int prev_new_flags = al_get_new_display_flags();
1448 int new_flags = ALLEGRO_WINDOWED;
1454 new_flags |= ALLEGRO_FRAMELESS | ALLEGRO_RESIZABLE;
1456 al_set_new_display_flags(new_flags);
1461 if (win->
title[0]) al_set_new_window_title(win->
title);
1462 int prev_pos_x = 0, prev_pos_y = 0;
1463 al_get_new_window_position(&prev_pos_x, &prev_pos_y);
1467 ALLEGRO_DISPLAY* d = al_create_display(dw, dh);
1468 al_set_new_display_flags(prev_new_flags);
1469 al_set_new_window_position(prev_pos_x, prev_pos_y);
1470 al_set_new_window_title(
"");
1471 if (prev_target) al_set_target_bitmap(prev_target);
1473 n_log(
LOG_ERR,
"n_gui_window_detach: al_create_display(%d, %d) failed for window %d", dw, dh, window_id);
1476 if (win->
title[0]) al_set_window_title(d, win->
title);
1484 if (new_flags & ALLEGRO_RESIZABLE) {
1485 int cmin_w = (int)(win->
min_w + 0.5f);
1487 if (cmin_w < 1) cmin_w = 1;
1488 if (cmin_h < 1) cmin_h = 1;
1489 if (al_set_window_constraints(d, cmin_w, cmin_h, 0, 0)) {
1490 al_apply_window_constraints(d,
true);
1493 al_register_event_source(ctx->
event_queue, al_get_display_event_source(d));
1529 if (win->
w > 0.0f && win->
h > 0.0f) {
1535 n_log(
LOG_DEBUG,
"n_gui_window_detach: window %d ('%s') detached into a %dx%d native window", window_id, win->
title, dw, dh);
1546 n_log(
LOG_ERR,
"n_gui_window_attach: no window with id %d", window_id);
1562 if (win->
w > 0.0f && win->
h > 0.0f) {
1568 n_log(
LOG_DEBUG,
"n_gui_window_attach: window %d ('%s') is a pop-up again", window_id, win->
title);
1578 return (win && win->
native) ? 1 : 0;
1588 return win ? win->
native : NULL;
1614 if (win && win->
native) n++;
1625 if (num_icons < 1) {
1626 n_log(
LOG_ERR,
"n_gui_window_set_native_icons: num_icons must be >= 1");
1630 if (!win || !win->
native) {
1631 n_log(
LOG_ERR,
"n_gui_window_set_native_icons: window %d is not detached", window_id);
1635 al_set_display_icon(win->
native, icons[0]);
1637 al_set_display_icons(win->
native, num_icons, icons);
1647 if (!win || !win->
native)
return 0;
1649 return (al_get_display_flags(win->
native) & ALLEGRO_MINIMIZED) ? 1 : 0;
1787 for (
int i = 1; i < n; i++) {
1794 if (gj > gi || (gj == gi && gi == 1 && arr[j]->z_value > tmp->
z_value)) {
1795 arr[j + 1] = arr[j];
1811 for (
int i = 0; i < n; i++) {
1910 n_log(
LOG_ERR,
"n_gui_window_set_zorder: unknown z_mode %d for window %d (expected N_GUI_ZORDER_NORMAL, N_GUI_ZORDER_ALWAYS_ON_TOP, N_GUI_ZORDER_ALWAYS_BEHIND, N_GUI_ZORDER_FIXED, or N_GUI_ZORDER_POPUP), falling back to N_GUI_ZORDER_NORMAL", z_mode, window_id);
1970 if (win) win->
flags = flags;
1979 if (win)
return win->
flags;
1989 if (!win || !win->
widgets)
return;
1991 float max_right = 0.0f;
1992 float max_bottom = 0.0f;
1998 float r = wgt->
x + wgt->
w;
1999 float b = wgt->
y + wgt->
h;
2000 if (r > max_right) max_right = r;
2001 if (b > max_bottom) max_bottom = b;
2004 float new_w = max_right + pad;
2005 float new_h = max_bottom + pad +
_win_tbh(win);
2006 if (new_w < win->min_w) new_w = win->
min_w;
2007 if (new_h < win->min_h) new_h = win->
min_h;
2020 n_log(
LOG_ERR,
"n_gui_window_set_autofit: window %d not found", window_id);
2043 float max_right = 0.0f;
2044 float max_bottom = 0.0f;
2047 if (!wgt || !wgt->
visible)
continue;
2048 float r = wgt->
x + wgt->
w;
2049 float b = wgt->
y + wgt->
h;
2050 if (r > max_right) max_right = r;
2051 if (b > max_bottom) max_bottom = b;
2061 float needed_w = max_right + border * 2.0f;
2062 if (needed_w < win->min_w) needed_w = win->
min_w;
2066 win->
x -= (needed_w - win->
w);
2073 float needed_h = max_bottom + border * 2.0f + tbh;
2074 if (needed_h < win->min_h) needed_h = win->
min_h;
2078 win->
y -= (needed_h - win->
h);
2090 if (!win || !win->
widgets)
return;
2091 float max_right = 0.0f;
2092 float max_bottom = 0.0f;
2095 if (!wgt || !wgt->
visible)
continue;
2096 float r = wgt->
x + wgt->
w;
2097 float b = wgt->
y + wgt->
h;
2103 ALLEGRO_FONT* font = wgt->
font ? wgt->
font : default_font;
2106 float text_r = wgt->
x + tw + 8.0f;
2107 if (text_r > r) r = text_r;
2111 if (r > max_right) max_right = r;
2112 if (b > max_bottom) max_bottom = b;
2124int 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) {
2165int n_gui_add_button_bitmap(
N_GUI_CTX* ctx,
int window_id,
const char* label,
float x,
float y,
float w,
float h, ALLEGRO_BITMAP* normal, ALLEGRO_BITMAP* hover, ALLEGRO_BITMAP* active,
void (*on_click)(
int,
void*),
void* user_data) {
2167 if (
id < 0)
return -1;
2169 if (wgt && wgt->
data) {
2193int n_gui_add_toggle_button(
N_GUI_CTX* ctx,
int window_id,
const char* label,
float x,
float y,
float w,
float h,
int shape,
int initial_state,
void (*on_click)(
int,
void*),
void* user_data) {
2194 int id =
n_gui_add_button(ctx, window_id, label, x, y, w, h, shape, on_click, user_data);
2195 if (
id < 0)
return -1;
2197 if (wgt && wgt->
data) {
2200 bd->
toggled = initial_state ? 1 : 0;
2226 snprintf(bd->
label,
sizeof(bd->
label),
"%s", label);
2244 w->
tooltip = (text && text[0]) ? strdup(text) : NULL;
2253 for (dp = 0; dp < ncols; dp++) {
2255 if (width[dp] > 0.0f)
2258 for (dp = 0; dp < ncols; dp++) {
2260 for (cur = dp; cur < ncols; cur++)
2263 if (cur < ncols && cur != dp)
2280 if (p->
kind != wgt->
type)
continue;
2295 float ox = 0.0f, oy = 0.0f;
2429 for (
int i = 0; i < count; i++) {
2442int n_gui_add_slider(
N_GUI_CTX* ctx,
int window_id,
float x,
float y,
float w,
float h,
double min_val,
double max_val,
double initial,
int mode,
void (*on_change)(
int,
double,
void*),
void* user_data) {
2484int n_gui_add_vslider(
N_GUI_CTX* ctx,
int window_id,
float x,
float y,
float w,
float h,
double min_val,
double max_val,
double initial,
int mode,
void (*on_change)(
int,
double,
void*),
void* user_data) {
2485 int id =
n_gui_add_slider(ctx, window_id, x, y, w, h, min_val, max_val, initial,
mode, on_change, user_data);
2486 if (
id < 0)
return -1;
2488 if (wgt && wgt->
data) {
2498int n_gui_add_textarea(
N_GUI_CTX* ctx,
int window_id,
float x,
float y,
float w,
float h,
int multiline,
size_t char_limit,
void (*on_change)(
int,
const char*,
void*),
void* user_data) {
2509 memset(td, 0,
sizeof(*td));
2543int n_gui_add_checkbox(
N_GUI_CTX* ctx,
int window_id,
const char* label,
float x,
float y,
float w,
float h,
int initial_checked,
void (*on_toggle)(
int,
int,
void*),
void* user_data) {
2558 cd->
checked = initial_checked ? 1 : 0;
2577int n_gui_add_scrollbar(
N_GUI_CTX* ctx,
int window_id,
float x,
float y,
float w,
float h,
int orientation,
int shape,
double content_size,
double viewport_size,
void (*
on_scroll)(
int,
double,
void*),
void* user_data) {
2589 sb->
content_size = content_size > 0 ? content_size : 1;
2620int n_gui_add_listbox(
N_GUI_CTX* ctx,
int window_id,
float x,
float y,
float w,
float h,
int selection_mode,
void (*on_select)(
int,
int,
int,
void*),
void* user_data) {
2666int n_gui_add_splitpane(
N_GUI_CTX* ctx,
int window_id,
float x,
float y,
float w,
float h,
int orientation,
float ratio,
void (*on_change)(
int,
float,
void*),
void* user_data) {
2948 id->bitmap = bitmap;
2949 id->scale_mode = scale_mode;
3007int n_gui_add_label_link(
N_GUI_CTX* ctx,
int window_id,
const char* text,
const char* link,
float x,
float y,
float w,
float h,
int align,
void (*
on_link_click)(
int,
const char*,
void*),
void* user_data) {
3009 if (wid < 0)
return -1;
3011 if (wgt && wgt->
data) {
3031 snprintf(
key,
sizeof(
key),
"%d", widget_id);
3044 if (w) w->
theme = theme;
3057 if (!ctx || !ctx->
windows)
return;
3111 if (prev) prev->
state &= ~N_GUI_STATE_FOCUSED;
3114 if (widget_id < 0) {
3121 n_log(
LOG_ERR,
"n_gui_set_focus: widget %d not found", widget_id);
3138 if (!win || !win->
widgets)
continue;
3141 if (w && w->
id == widget_id) {
3226 if (!fmt || !fmt[0]) {
3338 if (max_scroll < 0) max_scroll = 0;
3354 sb->
content_size = content_size > 0 ? content_size : 1;
3357 if (max_scroll < 0) max_scroll = 0;
3377 item->
text[0] =
'\0';
3398 if (index < 0 || (
size_t)index >= ld->
nb_items)
return -1;
3399 if ((
size_t)index < ld->nb_items - 1) {
3400 memmove(&ld->
items[index], &ld->
items[index + 1],
3452 if (index >= 0 && (
size_t)index < ld->nb_items) {
3469 for (
size_t i = 0; i < ld->
nb_items; i++) {
3487 if (index >= 0 && (
size_t)index < ld->nb_items) {
3505 if (index < 0 || (
size_t)index >= ld->
nb_items)
return;
3524 if (max_offset < 0) max_offset = 0;
3525 if (offset < 0) offset = 0;
3526 if (offset > max_offset) offset = max_offset;
3554 if (ratio < sd->min_ratio) ratio = sd->
min_ratio;
3570 if (min_ratio < 0.0f) min_ratio = 0.0f;
3571 if (max_ratio > 1.0f) max_ratio = 1.0f;
3572 if (min_ratio > max_ratio) min_ratio = max_ratio;
3575 if (sd->
ratio < min_ratio) sd->
ratio = min_ratio;
3576 if (sd->
ratio > max_ratio) sd->
ratio = max_ratio;
3595 if (data && len > 0) {
3598 memcpy(hd->
data, data, len);
3639 if (text && text[0]) {
3640 size_t len = strlen(text);
3643 memcpy(yd->
text, text, len + 1);
3700 if ((
size_t)lo > yd->
len) lo = (int)yd->
len;
3701 if ((
size_t)hi > yd->
len) hi = (int)yd->
len;
3703 if (n <= 0)
return NULL;
3705 Malloc(out,
char, (
size_t)n + 1);
3706 if (!out)
return NULL;
3707 memcpy(out, yd->
text + lo, (
size_t)n);
3723 int len = (int)yd->
len;
3724 if (start < 0) start = 0;
3725 if (end < 0) end = 0;
3726 if (start > len) start = len;
3727 if (end > len) end = len;
3730 if (ctx && start != end)
3755 if (!yd->
text || yd->
len == 0)
return;
3756 if (byte_offset < 0) byte_offset = 0;
3757 if ((
size_t)byte_offset > yd->
len) byte_offset = (int)yd->
len;
3760 for (
int it = 0; it < byte_offset; it++) {
3761 if (yd->
text[it] ==
'\n') line++;
3767 float fh = (float)al_get_font_line_height(font);
3769 float row_h = fh + 2.0f;
3770 int visible = (int)((w->
h - pad * 2.0f) / row_h);
3771 if (visible < 1) visible = 1;
3773 int max_off = nb_lines - visible;
3774 if (max_off < 0) max_off = 0;
3775 int target = line - visible / 2;
3776 if (target > max_off) target = max_off;
3777 if (target < 0) target = 0;
3785 if (!s || !*s)
return 0;
3787 if (*s <
'0' || *s >
'9')
return 0;
3798 long la = atol(a), lb = atol(b);
3799 return (la < lb) ? -1 : (la > lb) ? 1
3802 return strcasecmp(a, b);
3809 if (gd->
nb_rows > 0)
return -1;
3815 if (!tmp)
return -1;
3853 if (!gd || gd->
rows_cap == 0)
return 0;
3866 if (gd->
nb_cols == 0)
return -1;
3871 if (!tmp)
return -1;
3879 unsigned char* ts = NULL;
3880 Malloc(ts,
unsigned char, nr);
3890 ALLEGRO_COLOR* tc = NULL;
3891 unsigned char* th = NULL;
3892 Malloc(tc, ALLEGRO_COLOR, nr);
3893 Malloc(th,
unsigned char, nr);
3912 for (c = 0; c < gd->
nb_cols; c++) {
3913 const char* v = (values && values[c]) ? values[c] :
"";
3948 if (row < 0 || (
size_t)row >= gd->
nb_rows || col < 0 || (
size_t)col >= gd->
nb_cols)
return NULL;
3949 return gd->
cells[(size_t)row * gd->
nb_cols + (
size_t)col];
3962 if (row < -1 || (
size_t)row >= gd->
nb_rows)
return;
3990 if (row < 0 || (
size_t)row >= gd->
nb_rows)
return 0;
4001 for (r = 0; r < gd->
nb_rows; r++) {
4003 if (out && n < max) out[n] = (int)r;
4029 if (row < 0 || (
size_t)row >= gd->
nb_rows)
return;
4032 gd->
row_sel[row] = selected ? 1 : 0;
4045 if (row < 0 || (
size_t)row >= gd->
nb_rows)
return;
4063 if (row < 0 || (
size_t)row >= gd->
nb_rows)
return 0;
4088 if (offset < 0) offset = 0;
4104 if (px < 0.0f) px = 0.0f;
4122 if (!gd || col < 0 || (
size_t)col >= gd->
nb_cols)
return "";
4128 if (!gd || col < 0 || (
size_t)col >= gd->
nb_cols)
return;
4134 if (!gd || col < 0 || (
size_t)col >= gd->
nb_cols)
return 0;
4140 if (!gd || col < 0 || (
size_t)col >= gd->
nb_cols)
return;
4141 gd->
cols[col].
width = width < 16.0f ? 16.0f : width;
4146 if (!gd || col < 0 || (
size_t)col >= gd->
nb_cols)
return 0.0f;
4152 if (!gd || display_pos < 0 || (
size_t)display_pos >= gd->
nb_cols)
return -1;
4158 size_t f, t, moved, i;
4160 if (from < 0 || (
size_t)from >= gd->
nb_cols || to < 0 || (
size_t)to >= gd->
nb_cols || from == to)
return;
4190 int d = (dir < 0) ? -1 : 1;
4192 Malloc(nc,
char*, n* cols);
4198 for (i = 0; i < n; i++) idx[i] = i;
4200 for (i = 1; i < n; i++) {
4201 size_t key = idx[i];
4202 const char* ka = gd->
cells[
key * cols + (size_t)col];
4204 while (j > 0 && d *
_cell_cmp(gd->
cells[idx[j - 1] * cols + (
size_t)col], ka) > 0) {
4205 idx[j] = idx[j - 1];
4210 for (i = 0; i < n; i++)
4211 for (j = 0; j < cols; j++)
4212 nc[i * cols + j] = gd->
cells[idx[i] * cols + j];
4219 ALLEGRO_COLOR* tc = NULL;
4220 unsigned char* th = NULL;
4221 Malloc(tc, ALLEGRO_COLOR, n);
4222 Malloc(th,
unsigned char, n);
4224 for (i = 0; i < n; i++) {
4355 item->
text[0] =
'\0';
4404 if (index >= -1 && (index == -1 || (
size_t)index < rd->nb_items)) {
4437 item->
text[0] =
'\0';
4465 if (index >= 0 && (
size_t)index < cd->nb_items) {
4482 if (index >= -1 && (index == -1 || (
size_t)index < cd->nb_items)) {
4549 size_t new_cap = (*cap == 0) ? 8 : (*cap) * 2;
4550 if (new_cap < *cap)
return 0;
4554 if (*entries && *nb > 0) {
4568int n_gui_add_dropmenu(
N_GUI_CTX* ctx,
int window_id,
const char* label,
float x,
float y,
float w,
float h,
void (*on_open)(
int,
void*),
void* on_open_user_data) {
4579 dd->
label[0] =
'\0';
4636 snprintf(dd->
label,
sizeof(dd->
label),
"%s", label);
4638 dd->
label[0] =
'\0';
4652 memset(e, 0,
sizeof(*e));
4676 n_log(
LOG_ERR,
"Invalid NULL widget for ctx %p widget_id %d", ctx, widget_id);
4682 n_log(
LOG_ERR,
"Widget has NULL data for ctx %p widget_id %d", ctx, widget_id);
4700 for (
size_t i = 0; i < dd->
nb_entries; i++) {
4715 if (dm_max < 0) dm_max = 0;
4738 if (index < 0 || (
size_t)index >= dd->
nb_entries)
return;
4781 if (sb < 10.0f) sb = 10.0f;
4782 if (!font)
return pw;
4785 if (tw > pw) pw = tw;
4800 n_log(
LOG_WARNING,
"n_gui_window_set_bitmaps: window %d not found", window_id);
4812void n_gui_slider_set_bitmaps(
N_GUI_CTX* ctx,
int widget_id, ALLEGRO_BITMAP* track, ALLEGRO_BITMAP* fill, ALLEGRO_BITMAP* handle, ALLEGRO_BITMAP* handle_hover, ALLEGRO_BITMAP* handle_active) {
4815 n_log(
LOG_WARNING,
"n_gui_slider_set_bitmaps: widget %d is not a slider", widget_id);
4833 n_log(
LOG_WARNING,
"n_gui_scrollbar_set_bitmaps: widget %d is not a scrollbar", widget_id);
4850 n_log(
LOG_WARNING,
"n_gui_checkbox_set_bitmaps: widget %d is not a checkbox", widget_id);
4866 n_log(
LOG_WARNING,
"n_gui_textarea_set_bitmap: widget %d is not a textarea", widget_id);
4880 n_log(
LOG_WARNING,
"n_gui_textarea_set_mask_char: widget %d is not a textarea", widget_id);
4893 n_log(
LOG_WARNING,
"n_gui_textarea_set_placeholder: widget %d is not a textarea", widget_id);
4898 if (text && text[0])
4909 n_log(
LOG_WARNING,
"n_gui_listbox_set_bitmaps: widget %d is not a listbox", widget_id);
4925 n_log(
LOG_WARNING,
"n_gui_radiolist_set_bitmaps: widget %d is not a radiolist", widget_id);
4941 n_log(
LOG_WARNING,
"n_gui_combobox_set_bitmaps: widget %d is not a combobox", widget_id);
4957 n_log(
LOG_WARNING,
"n_gui_dropmenu_set_bitmaps: widget %d is not a dropmenu", widget_id);
4972 n_log(
LOG_WARNING,
"n_gui_label_set_bitmap: widget %d is not a label", widget_id);
4983 float bw = (float)al_get_bitmap_width(bmp);
4984 float bh = (float)al_get_bitmap_height(bmp);
4986 al_draw_scaled_bitmap(bmp, 0, 0, bw, bh, dx, dy, dw, dh, 0);
4988 al_draw_bitmap(bmp, dx + (dw - bw) / 2.0f, dy + (dh - bh) / 2.0f, 0);
4993 float s = (sx < sy) ? sx : sy;
4996 al_draw_scaled_bitmap(bmp, 0, 0, bw, bh, dx + (dw - rw) / 2.0f, dy + (dh - rh) / 2.0f, rw, rh, 0);
5003static ALLEGRO_BITMAP*
_select_state_bitmap(
int state, ALLEGRO_BITMAP* normal_bmp, ALLEGRO_BITMAP* hover_bmp, ALLEGRO_BITMAP* active_bmp) {
5006 if (normal_bmp)
return normal_bmp;
5019 const ALLEGRO_TRANSFORM* tf = al_get_current_transform();
5023 cx[1] = (float)(wx + ww);
5026 cy[2] = (float)(wy + wh);
5027 cx[3] = (float)(wx + ww);
5028 cy[3] = (float)(wy + wh);
5029 for (
int i = 0; i < 4; i++)
5030 al_transform_coordinates(tf, &cx[i], &cy[i]);
5032 float min_x = cx[0], max_x = cx[0];
5033 float min_y = cy[0], max_y = cy[0];
5034 for (
int i = 1; i < 4; i++) {
5035 if (cx[i] < min_x) min_x = cx[i];
5036 if (cx[i] > max_x) max_x = cx[i];
5037 if (cy[i] < min_y) min_y = cy[i];
5038 if (cy[i] > max_y) max_y = cy[i];
5041 int new_x = (int)min_x;
5042 int new_y = (int)min_y;
5043 int new_w = (int)(max_x - min_x);
5044 int new_h = (int)(max_y - min_y);
5047 int pcx, pcy, pcw, pch;
5048 al_get_clipping_rectangle(&pcx, &pcy, &pcw, &pch);
5050 int right = new_x + new_w;
5051 int bottom = new_y + new_h;
5052 int prev_right = pcx + pcw;
5053 int prev_bottom = pcy + pch;
5055 if (new_x < pcx) new_x = pcx;
5056 if (new_y < pcy) new_y = pcy;
5057 if (right > prev_right) right = prev_right;
5058 if (bottom > prev_bottom) bottom = prev_bottom;
5060 new_w = right - new_x;
5061 new_h = bottom - new_y;
5062 if (new_w < 0) new_w = 0;
5063 if (new_h < 0) new_h = 0;
5065 al_set_clipping_rectangle(new_x, new_y, new_w, new_h);
5070static void _draw_text_truncated(ALLEGRO_FONT* font, ALLEGRO_COLOR color,
float x,
float y,
float max_w,
const char* text) {
5071 if (!font || !text || !text[0])
return;
5072 float tw =
_text_w(font, text);
5074 al_draw_text(font, color, x, y, 0, text);
5079 float ellipsis_w =
_text_w(font,
"...");
5080 float avail = max_w - ellipsis_w;
5081 if (avail < 0) avail = 0;
5082 size_t len = strlen(text);
5088 unsigned char lead = (
unsigned char)text[i];
5089 if ((lead & 0xE0) == 0xC0)
5091 else if ((lead & 0xF0) == 0xE0)
5093 else if ((lead & 0xF8) == 0xF0)
5095 if (i + step > len || i + step > (
size_t)(
N_GUI_TEXT_MAX - 5))
break;
5096 memcpy(buf + i, text + i, step);
5097 buf[i + step] =
'\0';
5098 float cw =
_text_w(font, buf);
5099 if (cw > avail)
break;
5106 buf[fit + 3] =
'\0';
5107 al_draw_text(font, color, x, y, 0, buf);
5114static void _draw_text_justified(ALLEGRO_FONT* font, ALLEGRO_COLOR color,
float x,
float y,
float max_w,
float max_h,
const char* text) {
5115 if (!font || !text || !text[0])
return;
5122 float word_widths[256];
5124 char* tok = strtok(buf,
" \t");
5125 while (tok && nwords < 256) {
5126 words[nwords] = tok;
5127 word_widths[nwords] =
_text_w(font, tok);
5129 tok = strtok(NULL,
" \t");
5131 if (nwords == 0)
return;
5137 float fh = (float)al_get_font_line_height(font);
5138 float space_w =
_text_w(font,
" ");
5142 while (line_start < nwords) {
5144 if (cy + fh > y + max_h + 0.5f)
break;
5147 float line_words_w = word_widths[line_start];
5148 int line_end = line_start + 1;
5149 for (
int i = line_start + 1; i < nwords; i++) {
5150 float test_w = line_words_w + space_w + word_widths[i];
5151 if (test_w > max_w)
break;
5152 line_words_w = test_w;
5156 int words_on_line = line_end - line_start;
5157 int is_last_line = (line_end >= nwords);
5159 if (words_on_line == 1) {
5161 if (word_widths[line_start] > max_w) {
5164 al_draw_text(font, color, x, cy, 0, words[line_start]);
5166 }
else if (is_last_line) {
5169 for (
int i = line_start; i < line_end; i++) {
5170 al_draw_text(font, color, cx, cy, 0, words[i]);
5171 cx += word_widths[i] + space_w;
5175 float total_word_w = 0;
5176 for (
int i = line_start; i < line_end; i++) total_word_w += word_widths[i];
5177 float total_space = max_w - total_word_w;
5178 if (total_space < 0) total_space = 0;
5179 float gap = total_space / (float)(words_on_line - 1);
5181 for (
int i = line_start; i < line_end; i++) {
5182 al_draw_text(font, color, cx, cy, 0, words[i]);
5183 cx += word_widths[i] + gap;
5187 line_start = line_end;
5194 if (c < 0x80)
return 1;
5195 if ((c & 0xE0) == 0xC0)
return 2;
5196 if ((c & 0xF0) == 0xE0)
return 3;
5197 if ((c & 0xF8) == 0xF0)
return 4;
5204 if (!font || td->
text_len == 0)
return 0;
5205 float fh = (float)al_get_font_line_height(font);
5208 for (
size_t i = 0; i < td->
text_len;) {
5209 if (td->
text[i] ==
'\n') {
5218 memcpy(ch, &td->
text[i], (
size_t)clen);
5221 if (cx + cw > widget_w - pad * 2) {
5244 float view_h = w->
h - pad * 2;
5246 float max_sy = ch - view_h;
5247 if (max_sy < 0) max_sy = 0;
5284 float fh = (float)al_get_font_line_height(font);
5285 float view_h = w->
h - pad * 2;
5291 float text_area_w = w->
w - sb_size;
5297 size_t target = (byte_offset <= td->
text_len) ? byte_offset : td->
text_len;
5298 for (
size_t i = 0; i < target && i < td->
text_len;) {
5299 if (td->
text[i] ==
'\n') {
5308 memcpy(ch, &td->
text[i], (
size_t)clen);
5311 if (cx + cw > text_area_w - pad * 2) {
5321 float max_sy = content_h - view_h;
5322 if (max_sy < 0) max_sy = 0;
5323 float ideal = cy - view_h / 2 + fh / 2;
5324 if (ideal < 0) ideal = 0;
5325 if (ideal > max_sy) ideal = max_sy;
5346static int _justified_char_at_pos(
const char* text, ALLEGRO_FONT* font,
float max_w,
float text_x,
float text_y,
float scroll_y,
float click_mx,
float click_my) {
5347 if (!font || !text || !text[0])
return -1;
5350 size_t text_len = strlen(text);
5355 int word_starts[256];
5357 float word_widths[256];
5361 while (i < text_len && nwords < 256) {
5363 while (i < text_len && (text[i] ==
' ' || text[i] ==
'\t')) i++;
5364 if (i >= text_len)
break;
5366 while (i < text_len && text[i] !=
' ' && text[i] !=
'\t') i++;
5367 int wlen = (int)(i - ws);
5368 word_starts[nwords] = (int)ws;
5369 word_lens[nwords] = wlen;
5371 memcpy(tmp, &text[ws], (
size_t)wlen);
5373 word_widths[nwords] =
_text_w(font, tmp);
5376 if (nwords == 0)
return 0;
5378 float fh = (float)al_get_font_line_height(font);
5379 float space_w =
_text_w(font,
" ");
5380 float cy = text_y - scroll_y;
5381 float click_y_content = click_my;
5385 while (line_start < nwords) {
5386 float line_words_w = word_widths[line_start];
5387 int line_end = line_start + 1;
5388 for (
int j = line_start + 1; j < nwords; j++) {
5389 float test_w = line_words_w + space_w + word_widths[j];
5390 if (test_w > max_w)
break;
5391 line_words_w = test_w;
5395 int words_on_line = line_end - line_start;
5396 int is_last_line = (line_end >= nwords);
5398 if (click_y_content >= cy && click_y_content < cy + fh) {
5400 float click_x_rel = click_mx - text_x;
5401 if (click_x_rel < 0)
return word_starts[line_start];
5404 float gap = space_w;
5405 if (!is_last_line && words_on_line > 1) {
5406 float total_word_w = 0;
5407 for (
int j = line_start; j < line_end; j++) total_word_w += word_widths[j];
5408 float total_space = max_w - total_word_w;
5409 if (total_space < 0) total_space = 0;
5410 gap = total_space / (float)(words_on_line - 1);
5415 for (
int j = line_start; j < line_end; j++) {
5417 if (click_x_rel >= cx && click_x_rel < cx + word_widths[j]) {
5421 float best_dist = click_x_rel - cx;
5422 if (best_dist < 0) best_dist = -best_dist;
5423 for (
int k = 0; k < word_lens[j];) {
5424 int clen =
_utf8_char_len((
unsigned char)text[word_starts[j] + k]);
5425 if (k + clen > word_lens[j]) clen = word_lens[j] - k;
5427 memcpy(ch, &text[word_starts[j] + k], (
size_t)clen);
5431 float dist = (click_x_rel - cx) - wx;
5432 if (dist < 0) dist = -dist;
5433 if (dist < best_dist) {
5435 best_off = k + clen;
5439 return word_starts[j] + best_off;
5442 if (j < line_end - 1 && click_x_rel >= cx + word_widths[j] && click_x_rel < cx + word_widths[j] + gap) {
5444 float mid = cx + word_widths[j] + gap / 2.0f;
5445 if (click_x_rel < mid)
5446 return word_starts[j] + word_lens[j];
5448 return word_starts[j + 1];
5450 cx += word_widths[j] + gap;
5453 return word_starts[line_end - 1] + word_lens[line_end - 1];
5457 line_start = line_end;
5460 return (
int)text_len;
5465static void _draw_justified_selection(ALLEGRO_FONT* font,
float x,
float y,
float max_w,
float max_h,
const char* text,
int sel_start,
int sel_end, ALLEGRO_COLOR sel_color) {
5466 if (!font || !text || !text[0] || sel_start == sel_end)
return;
5467 int slo = sel_start < sel_end ? sel_start : sel_end;
5468 int shi = sel_start < sel_end ? sel_end : sel_start;
5469 size_t text_len = strlen(text);
5470 if ((
size_t)slo > text_len) slo = (int)text_len;
5471 if ((
size_t)shi > text_len) shi = (
int)text_len;
5474 int word_starts[256], word_lens[256];
5475 float word_widths[256];
5478 while (i < text_len && nwords < 256) {
5479 while (i < text_len && (text[i] ==
' ' || text[i] ==
'\t')) i++;
5480 if (i >= text_len)
break;
5482 while (i < text_len && text[i] !=
' ' && text[i] !=
'\t') i++;
5483 int wlen = (int)(i - ws);
5484 word_starts[nwords] = (int)ws;
5485 word_lens[nwords] = wlen;
5487 memcpy(tmp, &text[ws], (
size_t)wlen);
5489 word_widths[nwords] =
_text_w(font, tmp);
5492 if (nwords == 0)
return;
5494 float fh = (float)al_get_font_line_height(font);
5495 float space_w =
_text_w(font,
" ");
5499 while (line_start < nwords) {
5500 if (cy + fh > y + max_h + 0.5f)
break;
5501 float line_words_w = word_widths[line_start];
5502 int line_end = line_start + 1;
5503 for (
int j = line_start + 1; j < nwords; j++) {
5504 float test_w = line_words_w + space_w + word_widths[j];
5505 if (test_w > max_w)
break;
5506 line_words_w = test_w;
5509 int words_on_line = line_end - line_start;
5510 int is_last_line = (line_end >= nwords);
5513 float gap = space_w;
5514 if (!is_last_line && words_on_line > 1) {
5515 float total_word_w = 0;
5516 for (
int j = line_start; j < line_end; j++) total_word_w += word_widths[j];
5517 float total_space = max_w - total_word_w;
5518 if (total_space < 0) total_space = 0;
5519 gap = total_space / (float)(words_on_line - 1);
5524 for (
int j = line_start; j < line_end; j++) {
5525 int ws2 = word_starts[j];
5526 int we = ws2 + word_lens[j];
5528 if (slo < we && shi > ws2) {
5530 float sx1 = 0, sx2 = word_widths[j];
5533 int off = slo - ws2;
5534 memcpy(tmp2, &text[ws2], (
size_t)off);
5540 int off = shi - ws2;
5541 memcpy(tmp2, &text[ws2], (
size_t)off);
5545 al_draw_filled_rectangle(cx + sx1, cy, cx + sx2, cy + fh, sel_color);
5548 if (j < line_end - 1) {
5550 int gap_end = word_starts[j + 1];
5551 if (slo < gap_end && shi > gap_start) {
5552 al_draw_filled_rectangle(cx + word_widths[j], cy,
5553 cx + word_widths[j] + gap, cy + fh, sel_color);
5556 cx += word_widths[j] + gap;
5560 line_start = line_end;
5567 if (!font || !text || !text[0])
return 0;
5568 float fh = (float)al_get_font_line_height(font);
5569 float space_w =
_text_w(font,
" ");
5574 float word_widths[256];
5576 const char* tok = strtok(buf,
" \t");
5577 while (tok && nwords < 256) {
5578 word_widths[nwords] =
_text_w(font, tok);
5580 tok = strtok(NULL,
" \t");
5582 if (nwords == 0)
return 0;
5583 if (nwords == 1)
return fh;
5587 while (line_start < nwords) {
5588 float line_words_w = word_widths[line_start];
5589 int line_end = line_start + 1;
5590 for (
int i = line_start + 1; i < nwords; i++) {
5591 float test_w = line_words_w + space_w + word_widths[i];
5592 if (test_w > max_w)
break;
5593 line_words_w = test_w;
5597 line_start = line_end;
5599 return (
float)nlines * fh;
5608 float sb_x = area_x + area_w - sb_size;
5611 al_draw_filled_rectangle(sb_x, area_y, sb_x + sb_size, area_y + view_h,
5615 float ratio = view_h / content_h;
5616 if (ratio > 1.0f) ratio = 1.0f;
5617 float thumb_h = ratio * view_h;
5619 float max_scroll = content_h - view_h;
5620 float pos_ratio = (max_scroll > 0) ? scroll_y / max_scroll : 0;
5621 float thumb_y = area_y + pos_ratio * (view_h - thumb_h);
5634 const ALLEGRO_TRANSFORM* tf = al_get_current_transform();
5636 float sx = hypotf(tf->m[0][0], tf->m[0][1]);
5637 float sy = hypotf(tf->m[1][0], tf->m[1][1]);
5639 float scale = (sx > sy) ? sx : sy;
5640 if (scale < 0.01f) scale = 0.01f;
5642 float min_t = 1.0f / scale;
5643 return (requested > min_t) ? requested : min_t;
5673 float ht = thickness * 0.5f;
5675 al_draw_filled_rounded_rectangle(x + ht, y + ht, x + w - ht, y + h - ht, t->
corner_rx, t->
corner_ry, bg);
5676 al_draw_rounded_rectangle(x + ht, y + ht, x + w - ht, y + h - ht, t->
corner_rx, t->
corner_ry, bd, thickness);
5678 al_draw_filled_rectangle(x, y, x + w, y + h, bg);
5679 al_draw_rectangle(x + ht, y + ht, x + w - ht, y + h - ht, bd, thickness);
5695 float ax = ox + wgt->
x;
5696 float ay = oy + wgt->
y;
5697 ALLEGRO_FONT* font = wgt->
font ? wgt->
font : default_font;
5700 int draw_state = wgt->
state;
5712 ALLEGRO_BITMAP* bmp = bd->
bitmap;
5717 al_draw_scaled_bitmap(bmp, 0, 0,
5718 (
float)al_get_bitmap_width(bmp), (
float)al_get_bitmap_height(bmp),
5719 ax, ay, wgt->
w, wgt->
h, 0);
5725 if (font && bd->
label[0]) {
5727 int bbx = 0, bby = 0, bbw = 0, bbh = 0;
5729 float tw = (float)bbw;
5730 float th = (float)bbh;
5732 float max_text_w = wgt->
w - pad * 2.0f;
5733 if (tw > max_text_w) {
5736 al_draw_text(font, tc, ax + (wgt->
w - tw) / 2.0f - (
float)bbx, ay + (wgt->
h - th) / 2.0f - (
float)bby, 0, bd->
label);
5744 float ax = ox + wgt->
x;
5745 float ay = oy + wgt->
y;
5746 ALLEGRO_FONT* font = wgt->
font ? wgt->
font : default_font;
5749 double ratio = (range > 0) ? (sd->
value - sd->
min_val) / range : 0;
5754 float track_x = ax + (wgt->
w - track_w) / 2.0f;
5758 track_x, ay, track_w, wgt->
h, 0);
5765 float fill_h = (float)(ratio * (
double)wgt->
h);
5769 track_x, ay + wgt->
h - fill_h, track_w, fill_h, 0);
5775 float hy = ay + wgt->
h - fill_h;
5780 float hd = handle_r * 2.0f;
5781 al_draw_scaled_bitmap(hbmp, 0, 0,
5782 (
float)al_get_bitmap_width(hbmp), (
float)al_get_bitmap_height(hbmp),
5783 ax + wgt->
w / 2.0f - handle_r, hy - handle_r, hd, hd, 0);
5787 al_draw_filled_circle(ax + wgt->
w / 2.0f, hy, handle_r, hc);
5796#pragma GCC diagnostic push
5797#pragma GCC diagnostic ignored "-Wformat-nonliteral"
5799#pragma GCC diagnostic pop
5801 snprintf(val_str,
sizeof(val_str),
"%.0f%%", sd->
value);
5803 snprintf(val_str,
sizeof(val_str),
"%.1f", sd->
value);
5805 int vbbx = 0, vbby = 0, vbbw = 0, vbbh = 0;
5806 _text_dims(font, val_str, &vbbx, &vbby, &vbbw, &vbbh);
5816 float track_y = ay + (wgt->
h - track_h) / 2.0f;
5820 ax, track_y, wgt->
w, track_h, 0);
5827 float fill_w = (float)(ratio * (
double)wgt->
w);
5831 ax, track_y, fill_w, track_h, 0);
5837 float hx = ax + fill_w;
5842 float hd = handle_r * 2.0f;
5843 al_draw_scaled_bitmap(hbmp, 0, 0,
5844 (
float)al_get_bitmap_width(hbmp), (
float)al_get_bitmap_height(hbmp),
5845 hx - handle_r, ay + wgt->
h / 2.0f - handle_r, hd, hd, 0);
5849 al_draw_filled_circle(hx, ay + wgt->
h / 2.0f, handle_r, hc);
5858#pragma GCC diagnostic push
5859#pragma GCC diagnostic ignored "-Wformat-nonliteral"
5861#pragma GCC diagnostic pop
5863 snprintf(val_str,
sizeof(val_str),
"%.0f%%", sd->
value);
5865 snprintf(val_str,
sizeof(val_str),
"%.1f", sd->
value);
5867 int sbbx = 0, sbby = 0, sbbw = 0, sbbh = 0;
5868 _text_dims(font, val_str, &sbbx, &sbby, &sbbw, &sbbh);
5869 float th = (float)sbbh;
5878 if (!font || td->
text_len == 0)
return 0;
5879 float fh = (float)al_get_font_line_height(font);
5882 float click_x = mx - (ax + pad) + td->
scroll_x;
5883 if (click_x < 0) click_x = 0;
5896 float best_dist = click_x;
5898 for (
size_t ci = 0; ci < td->
text_len;) {
5901 size_t pos = ci + (size_t)clen;
5904 float tw =
_text_w(font, ctmp);
5905 float dist = click_x - tw;
5906 if (dist < 0) dist = -dist;
5907 if (dist < best_dist) {
5919 float view_h = widget_h - pad * 2;
5921 float sb_size = (content_h > view_h) ? scrollbar_size : 0.0f;
5922 float text_area_w = widget_w - sb_size;
5923 float avail_w = text_area_w - pad * 2;
5924 float click_x_rel = mx - (ax + pad);
5925 float click_y_content = my - (ay + pad) + (
float)td->
scroll_y;
5926 if (click_x_rel < 0) click_x_rel = 0;
5927 if (click_y_content < 0) click_y_content = 0;
5928 int target_line = (int)(click_y_content / fh);
5932 size_t best_pos = 0;
5933 float best_dist = click_x_rel;
5934 int found_line = (target_line == 0) ? 1 : 0;
5936 for (
size_t ci = 0; ci < td->
text_len;) {
5937 if (cur_line > target_line)
break;
5938 if (td->
text[ci] ==
'\n') {
5939 if (cur_line == target_line)
break;
5942 if (cur_line == target_line) {
5945 best_dist = click_x_rel;
5953 memcpy(ch2, &td->
text[ci], (
size_t)clen);
5955 float cw =
_text_w(font, ch2);
5956 if (cur_cx + cw > avail_w) {
5957 if (cur_line == target_line)
break;
5960 if (cur_line == target_line) {
5963 best_dist = click_x_rel;
5966 if (cur_line == target_line) {
5967 float dist = click_x_rel - (cur_cx + cw);
5968 if (dist < 0) dist = -dist;
5969 if (dist < best_dist) {
5971 best_pos = ci + (size_t)clen;
5977 if (!found_line) best_pos = td->
text_len;
6000 float tr, tg, tb, br, bg, bb;
6006 dim = al_map_rgb_f((tr + br) * 0.5f, (tg + bg) * 0.5f, (tb + bb) * 0.5f);
6007 al_draw_text(font, dim, tx, ty, 0, td->
placeholder);
6013 float ax = ox + wgt->
x;
6014 float ay = oy + wgt->
y;
6015 ALLEGRO_FONT* font = wgt->
font ? wgt->
font : default_font;
6022 al_draw_scaled_bitmap(td->
bg_bitmap, 0, 0,
6023 (
float)al_get_bitmap_width(td->
bg_bitmap), (
float)al_get_bitmap_height(td->
bg_bitmap),
6024 ax, ay, wgt->
w, wgt->
h, 0);
6031 al_draw_filled_rectangle(ax, ay, ax + wgt->
w, ay + wgt->
h, bg);
6041 float fh = (float)al_get_font_line_height(font);
6045 int cursor_visible = 0;
6047 double now = al_get_time();
6050 if (period <= 0.0f) period = 1.0f;
6051 double phase = elapsed - (double)(
int)(elapsed / (double)period) * (double)period;
6052 cursor_visible = (phase < (double)period * 0.5) ? 1 : 0;
6057 float view_h = wgt->
h - pad * 2;
6061 int need_scrollbar = (content_h > view_h) ? 1 : 0;
6063 float text_area_w = wgt->
w - sb_size;
6064 if (need_scrollbar) {
6074 if (td->
text[i] ==
'\n') {
6083 memcpy(ch, &td->
text[i], (
size_t)clen);
6085 float cw2 =
_text_w(font, ch);
6086 if (cur_cx + cw2 > text_area_w - pad * 2) {
6094 if (cur_cy < (
float)td->
scroll_y) {
6097 if (cur_cy + fh > (
float)td->
scroll_y + view_h) {
6098 td->
scroll_y = (int)(cur_cy + fh - view_h);
6103 if (need_scrollbar) {
6104 float max_sy = content_h - view_h;
6105 if (max_sy < 0) max_sy = 0;
6113 int pcx, pcy, pcw, pch;
6114 al_get_clipping_rectangle(&pcx, &pcy, &pcw, &pch);
6117 size_t sel_lo = 0, sel_hi = 0;
6123 float cx = ax + pad;
6124 float cy = ay + pad - (float)td->
scroll_y;
6126 float cursor_cx = cx;
6127 float cursor_cy = cy;
6139 float run_x = cx, run_y = cy;
6141 for (
size_t i = 0; i < td->
text_len;) {
6146 if (td->
text[i] ==
'\n') {
6149 run[run_len] =
'\0';
6155 if (has_sel && i >= sel_lo && i < sel_hi && cy + fh > ay && cy < ay + wgt->h) {
6156 float space_w =
_text_w(font,
" ");
6157 al_draw_filled_rectangle(cx, cy, cx + space_w, cy + fh, sel_bg);
6167 memcpy(ch, &td->
text[i], (
size_t)clen);
6170 if (cx + cw > ax + text_area_w - pad) {
6174 run[run_len] =
'\0';
6186 int vis = (cy + fh > ay && cy < ay + wgt->
h);
6189 if (has_sel && i >= sel_lo && i < sel_hi) {
6190 al_draw_filled_rectangle(cx, cy, cx + cw, cy + fh, sel_bg);
6199 if (run_len + clen >= (
int)
sizeof(
run) - 1) {
6200 run[run_len] =
'\0';
6206 memcpy(
run + run_len, ch, (
size_t)clen);
6211 for (
int b = 1; b < clen; b++) {
6220 if (run_len > 0 && run_vis) {
6221 run[run_len] =
'\0';
6230 if (cursor_visible) {
6231 al_draw_filled_rectangle(cursor_cx, cursor_cy, cursor_cx + cursor_w, cursor_cy + fh, wgt->
theme.
text_active);
6233 al_set_clipping_rectangle(pcx, pcy, pcw, pch);
6236 if (need_scrollbar) {
6241 float ty = ay + (wgt->
h - fh) / 2.0f;
6242 float inner_w = wgt->
w - pad * 2;
6250 display_text[n] =
'\0';
6260 memcpy(tmp, display_text, cpos);
6262 float cursor_px =
_text_w(font, tmp);
6265 if (cursor_px - td->
scroll_x < 0) {
6268 if (cursor_px - td->
scroll_x > inner_w - cursor_w) {
6269 td->
scroll_x = cursor_px - inner_w + cursor_w;
6274 int pcx, pcy, pcw, pch;
6275 al_get_clipping_rectangle(&pcx, &pcy, &pcw, &pch);
6282 memcpy(stmp, display_text, sl);
6284 float sel_x1 =
_text_w(font, stmp);
6285 memcpy(stmp, display_text, sh);
6287 float sel_x2 =
_text_w(font, stmp);
6288 float sx1 = ax + pad + sel_x1 - td->
scroll_x;
6289 float sx2 = ax + pad + sel_x2 - td->
scroll_x;
6295 if (cursor_visible) {
6296 float cx = ax + pad + cursor_px - td->
scroll_x;
6297 al_draw_filled_rectangle(cx, ty, cx + cursor_w, ty + fh, wgt->
theme.
text_active);
6299 al_set_clipping_rectangle(pcx, pcy, pcw, pch);
6306 float ax = ox + wgt->
x;
6307 float ay = oy + wgt->
y;
6308 ALLEGRO_FONT* font = wgt->
font ? wgt->
font : default_font;
6311 float box_y = ay + (wgt->
h - box_size) / 2.0f;
6314 ALLEGRO_BITMAP* box_bmp = NULL;
6324 al_draw_scaled_bitmap(box_bmp, 0, 0,
6325 (
float)al_get_bitmap_width(box_bmp), (
float)al_get_bitmap_height(box_bmp),
6326 ax, box_y, box_size, box_size, 0);
6334 al_draw_line(ax + m, box_y + box_size / 2.0f,
6336 al_draw_line(ax + box_size / 2.0f, box_y + box_size - m,
6341 if (font && cd->
label[0]) {
6342 int cbbx = 0, cbby = 0, cbbw = 0, cbbh = 0;
6344 float fh = (float)cbbh;
6354 float ax = ox + wgt->
x;
6355 float ay = oy + wgt->
y;
6362 ax, ay, wgt->
w, wgt->
h, 0);
6369 if (ratio > 1.0) ratio = 1.0;
6371 if (max_scroll < 0) max_scroll = 0;
6372 double pos_ratio = (max_scroll > 0) ? sb->
scroll_pos / max_scroll : 0;
6374 float thumb_x, thumb_y, thumb_w, thumb_h;
6376 thumb_h = (float)(ratio * (
double)wgt->
h);
6380 float track_range = wgt->
h - thumb_h;
6381 thumb_y = ay + (float)(pos_ratio * (
double)track_range);
6383 thumb_w = (float)(ratio * (
double)wgt->
w);
6387 float track_range = wgt->
w - thumb_w;
6388 thumb_x = ax + (float)(pos_ratio * (
double)track_range);
6393 al_draw_scaled_bitmap(tbmp, 0, 0,
6394 (
float)al_get_bitmap_width(tbmp), (
float)al_get_bitmap_height(tbmp),
6395 thumb_x, thumb_y, thumb_w, thumb_h, 0);
6406 float sb_x = ax + w - sb_w;
6407 int max_off = nb_rows - visible;
6408 float ratio, thumb_h, track_range, pos_ratio, thumb_y;
6409 if (max_off < 0) max_off = 0;
6413 al_draw_line(sb_x, ay, sb_x, ay + h, theme->
border_normal, 1.0f);
6414 ratio = (nb_rows > 0) ? (
float)visible / (float)nb_rows : 1.0f;
6415 if (ratio > 1.0f) ratio = 1.0f;
6416 thumb_h = ratio * h;
6418 track_range = h - thumb_h;
6419 pos_ratio = (max_off > 0) ? (
float)scroll_offset / (float)max_off : 0.0f;
6420 thumb_y = ay + pos_ratio * track_range;
6429 float max_off = content_w - track_w;
6430 float ratio, thumb_w, track_range, pos_ratio, thumb_x;
6431 if (max_off < 0) max_off = 0;
6433 al_draw_line(ax, bar_y, ax + track_w, bar_y, theme->
border_normal, 1.0f);
6434 ratio = (content_w > 0) ? track_w / content_w : 1.0f;
6435 if (ratio > 1.0f) ratio = 1.0f;
6436 thumb_w = ratio * track_w;
6438 track_range = track_w - thumb_w;
6439 pos_ratio = (max_off > 0) ? h_scroll / max_off : 0.0f;
6440 thumb_x = ax + pos_ratio * track_range;
6450 float fh = font ? (float)al_get_font_line_height(font) : 16.0f;
6453 float data_h = wgt->
h - row_h;
6454 int visible = (int)(data_h / row_h);
6458 if (visible < 1) visible = 1;
6459 need_sb = ((int)gd->
nb_rows > visible) ? 1 : 0;
6460 for (c = 0; c < gd->
nb_cols; c++) {
6465 if (content_w) *content_w = cw;
6466 if (pane_w) *pane_w = pw;
6467 if (need_hsb) *need_hsb = (cw > pw + 1.0f) ? 1 : 0;
6473 float ax = ox + wgt->
x;
6474 float ay = oy + wgt->
y;
6475 ALLEGRO_FONT* font = wgt->
font ? wgt->
font : default_font;
6476 float fh = font ? (float)al_get_font_line_height(font) : 16.0f;
6478 float row_h = fh + 2.0f;
6480 int nb_rows = (int)((hd->
len + (
size_t)bpr - 1) / (size_t)bpr);
6481 int visible = (int)((wgt->
h - pad * 2.0f) / row_h);
6482 int need_sb, max_off, i, pcx, pcy, pcw, pch;
6485 al_draw_filled_rectangle(ax, ay, ax + wgt->
w, ay + wgt->
h, wgt->
theme.
bg_normal);
6487 if (visible < 1) visible = 1;
6488 need_sb = (nb_rows > visible) ? 1 : 0;
6490 max_off = nb_rows - visible;
6491 if (max_off < 0) max_off = 0;
6495 al_get_clipping_rectangle(&pcx, &pcy, &pcw, &pch);
6496 al_set_clipping_rectangle((
int)ax, (
int)ay, (
int)(wgt->
w - sb_w), (
int)wgt->
h);
6497 for (i = 0; i < visible; i++) {
6499 size_t base = (size_t)row * (
size_t)bpr;
6502 int n = 0, j, a = 0;
6503 float ty = ay + pad + (float)i * row_h;
6504 if (base >= hd->
len)
break;
6505 n += snprintf(line + n,
sizeof(line) - (
size_t)n,
"%08lX ", (
unsigned long)base);
6506 for (j = 0; j < bpr; j++) {
6507 if (base + (
size_t)j < hd->len) {
6508 unsigned char c = hd->
data[base + (size_t)j];
6509 n += snprintf(line + n,
sizeof(line) - (
size_t)n,
"%02X ", c);
6510 asc[a++] = (c >= 32 && c < 127) ? (
char)c :
'.';
6512 n += snprintf(line + n,
sizeof(line) - (
size_t)n,
" ");
6516 snprintf(line + n,
sizeof(line) - (
size_t)n,
" |%s|", asc);
6519 al_set_clipping_rectangle(pcx, pcy, pcw, pch);
6527 if (!s || !s[0])
return 0;
6530 if (*s ==
'\n') n++;
6537static void _syntax_run(ALLEGRO_FONT* font, ALLEGRO_COLOR col,
float* cx,
float y,
const char* s,
int len) {
6539 if (len <= 0)
return;
6540 if (len > (
int)
sizeof(buf) - 1) len = (int)
sizeof(buf) - 1;
6541 memcpy(buf, s, (
size_t)len);
6543 al_draw_text(font, col, *cx, y, 0, buf);
6550 static const char* kw[] = {
"await",
"case",
"delete",
"do",
"else",
"in",
6551 "instanceof",
"new",
"of",
"return",
"throw",
6552 "typeof",
"void",
"yield", NULL};
6553 for (
size_t it = 0; kw[it]; it++) {
6554 if ((
int)strlen(kw[it]) == n && strncmp(s, kw[it], (
size_t)n) == 0)
return 1;
6562 if (c == 0)
return 1;
6563 return strchr(
"(,=:[!&|?;{}<>+-*%~^", c) != NULL;
6568 static const char* kw[] = {
"async",
"await",
"break",
"case",
"catch",
"class",
"const",
6569 "continue",
"debugger",
"default",
"delete",
"do",
"else",
6570 "export",
"extends",
"false",
"finally",
"for",
"function",
6571 "if",
"import",
"in",
"instanceof",
"let",
"new",
"null",
6572 "of",
"return",
"static",
"super",
"switch",
"this",
"throw",
6573 "true",
"try",
"typeof",
"undefined",
"var",
"void",
"while",
6574 "with",
"yield", NULL};
6575 for (
size_t it = 0; kw[it]; it++) {
6576 if ((
int)strlen(kw[it]) == n && strncmp(s, kw[it], (
size_t)n) == 0)
return 1;
6585 if (line_idx == 0) {
6589 if (in_headers && n > 0) {
6591 while (c < n && s[c] !=
':') c++;
6592 if (c > 0 && c < n) {
6607 while (j < n && s[j] !=
'"') {
6608 if (s[j] ==
'\\' && j + 1 < n) j++;
6614 }
else if ((c >=
'0' && c <=
'9') || (c ==
'-' && i + 1 < n && s[i + 1] >=
'0' && s[i + 1] <=
'9')) {
6616 while (j < n && ((s[j] >=
'0' && s[j] <=
'9') || s[j] ==
'.' || s[j] ==
'e' || s[j] ==
'E' || s[j] ==
'+' || s[j] ==
'-')) j++;
6619 }
else if (c ==
'{' || c ==
'}' || c ==
'[' || c ==
']' || c ==
':' || c ==
',') {
6624 while (j < n && !(s[j] ==
'"' || (s[j] >=
'0' && s[j] <=
'9') || s[j] ==
'{' || s[j] ==
'}' || s[j] ==
'[' || s[j] ==
']' || s[j] ==
':' || s[j] ==
',')) j++;
6635 if (i + 4 <= n && memcmp(s + i,
"<!--", 4) == 0) {
6638 while (j + 3 <= n && memcmp(s + j,
"-->", 3) != 0) j++;
6639 j = (j + 3 <= n) ? j + 3 : n;
6646 while (j < n && (s[j] ==
'/' || s[j] ==
'!' || s[j] ==
'?')) j++;
6650 while (j < n && (isalnum((
unsigned char)s[j]) || s[j] ==
':' || s[j] ==
'-' || s[j] ==
'_')) j++;
6654 while (i < n && s[i] !=
'>') {
6656 if (q ==
'"' || q ==
'\'') {
6658 while (j < n && s[j] != q) j++;
6664 while (j < n && s[j] !=
'>' && s[j] !=
'"' && s[j] !=
'\'') j++;
6675 while (j < n && s[j] !=
'<') j++;
6685 while (i < n && (s[i] ==
' ' || s[i] ==
'\t')) i++;
6687 while (i < n && s[i] ==
'-' && (i + 1 >= n || s[i + 1] ==
' ')) {
6695 if (i < n && s[i] ==
'#') {
6703 for (
int j = i; j < n; j++) {
6705 if (s[j] == q) q = 0;
6708 if (s[j] ==
'"' || s[j] ==
'\'') {
6712 if (s[j] ==
'#')
break;
6713 if (s[j] ==
':' && (j + 1 >= n || s[j + 1] ==
' ')) {
6727 if (c ==
'"' || c ==
'\'') {
6729 while (j < n && s[j] != c) j++;
6733 }
else if (c ==
'#') {
6738 while (j < n && s[j] !=
'"' && s[j] !=
'\'' && s[j] !=
'#') j++;
6751 if (c ==
'/' && i + 1 < n && s[i + 1] ==
'/') {
6755 if (c ==
'/' && i + 1 < n && s[i + 1] ==
'*') {
6757 while (j + 2 <= n && memcmp(s + j,
"*/", 2) != 0) j++;
6758 j = (j + 2 <= n) ? j + 2 : n;
6767 if (s[j] ==
'\\' && j + 1 < n) {
6772 if (s[j] ==
']') in_class = 0;
6773 }
else if (s[j] ==
'[') {
6775 }
else if (s[j] ==
'/') {
6783 while (j < n && isalpha((
unsigned char)s[j])) j++;
6789 }
else if (c ==
'"' || c ==
'\'' || c ==
'`') {
6791 while (j < n && s[j] != c) {
6792 if (s[j] ==
'\\' && j + 1 < n) j++;
6800 }
else if (c >=
'0' && c <=
'9') {
6802 while (j < n && (isalnum((
unsigned char)s[j]) || s[j] ==
'.')) j++;
6804 last_sig = s[j - 1];
6807 }
else if (isalpha((
unsigned char)c) || c ==
'_' || c ==
'$') {
6809 while (j < n && (isalnum((
unsigned char)s[j]) || s[j] ==
'_' || s[j] ==
'$')) j++;
6811 last_sig = s[j - 1];
6814 }
else if (c ==
'{' || c ==
'}' || c ==
'[' || c ==
']' || c ==
'(' || c ==
')' || c ==
';' || c ==
',' || c ==
':') {
6821 if (c !=
' ' && c !=
'\t') {
6836 if (!font || !s || n <= 0)
return 0.0f;
6837 if (n > (
int)
sizeof(buf) - 1) n = (int)
sizeof(buf) - 1;
6838 memcpy(buf, s, (
size_t)n);
6849 if (!yd || !yd->
text || !font)
return 0;
6850 float fh = (float)al_get_font_line_height(font);
6851 float row_h = fh + 2.0f;
6852 int row = (int)((my - ay - pad) / row_h);
6853 if (row < 0) row = 0;
6855 const char* p = yd->
text;
6857 while (ln < target_line && *p) {
6858 const char* nl = strchr(p,
'\n');
6866 size_t line_start = (size_t)(p - yd->
text);
6867 const char* nl = strchr(p,
'\n');
6868 int dlen = nl ? (int)(nl - p) : (int)strlen(p);
6869 if (dlen > 0 && p[dlen - 1] ==
'\r') dlen--;
6870 float target = mx - (ax + pad);
6871 if (target <= 0.0f)
return (
int)line_start;
6874 for (col = 1; col <= dlen; col++) {
6877 return (
int)line_start + ((target - prevw < ww - target) ? (col - 1) : col);
6880 return (
int)line_start + dlen;
6906 int headers_end = 0x7fffffff;
6907 const char* s = yd->
text;
6911 for (
const char* t = s; *t; t++)
6912 if (*t ==
'\n') nb++;
6917 const char* nl = strchr(q,
'\n');
6918 int len = nl ? (int)(nl - q) : (int)strlen(q);
6919 if (len == 0 || (len == 1 && q[0] ==
'\r')) {
6935 float ax = ox + wgt->
x;
6936 float ay = oy + wgt->
y;
6937 ALLEGRO_FONT* font = wgt->
font ? wgt->
font : default_font;
6938 float fh = font ? (float)al_get_font_line_height(font) : 16.0f;
6940 float row_h = fh + 2.0f;
6943 int visible = (int)((wgt->
h - pad * 2.0f) / row_h);
6944 int need_sb, max_off, headers_end, line_no, drawn, pcx, pcy, pcw, pch;
6945 int has_sel, sel_lo = 0, sel_hi = 0;
6949 al_draw_filled_rectangle(ax, ay, ax + wgt->
w, ay + wgt->
h, wgt->
theme.
bg_normal);
6951 if (visible < 1) visible = 1;
6952 need_sb = (nb_lines > visible) ? 1 : 0;
6954 max_off = nb_lines - visible;
6955 if (max_off < 0) max_off = 0;
6958 if (!yd->
text)
return;
6968 if ((
size_t)sel_lo > yd->
len) sel_lo = (
int)yd->
len;
6969 if ((
size_t)sel_hi > yd->
len) sel_hi = (
int)yd->
len;
6972 al_get_clipping_rectangle(&pcx, &pcy, &pcw, &pch);
6973 al_set_clipping_rectangle((
int)ax, (
int)ay, (
int)(wgt->
w - sb_w), (
int)wgt->
h);
6977 while (line_no < yd->scroll_offset && p) {
6978 const char* nl = strchr(p,
'\n');
6992 for (
int sdrawn = 0; sp && *sp && sdrawn < visible; sdrawn++) {
6993 const char* nl = strchr(sp,
'\n');
6994 int len = nl ? (int)(nl - sp) : (int)strlen(sp);
6995 float ty = ay + pad + (float)sdrawn * row_h;
6996 if (len > 0 && sp[len - 1] ==
'\r') len--;
6997 int ls = (int)(sp - yd->
text);
6999 int a = sel_lo > ls ? sel_lo : ls;
7000 int b = sel_hi < le ? sel_hi : le;
7013 al_hold_bitmap_drawing(
true);
7014 for (drawn = 0; p && *p && drawn < visible; drawn++, line_no++) {
7015 const char* nl = strchr(p,
'\n');
7016 int len = nl ? (int)(nl - p) : (int)strlen(p);
7017 int in_headers = (line_no <= headers_end);
7018 float ty = ay + pad + (float)drawn * row_h;
7019 if (len > 0 && p[len - 1] ==
'\r') len--;
7024 al_hold_bitmap_drawing(
false);
7025 al_set_clipping_rectangle(pcx, pcy, pcw, pch);
7033 float ax = ox + wgt->
x;
7034 float ay = oy + wgt->
y;
7035 ALLEGRO_FONT* font = wgt->
font ? wgt->
font : default_font;
7042 al_draw_filled_rounded_rectangle(ax, ay, ax + wgt->
w, ay + wgt->
h, r, r, wgt->
theme.
bg_normal);
7044 fillw = pd->
value * wgt->
w;
7048 al_draw_filled_rounded_rectangle(ax, ay, ax + fillw, ay + wgt->
h, r, r, wgt->
theme.
bg_active);
7051 al_draw_rounded_rectangle(ax, ay, ax + wgt->
w, ay + wgt->
h, r, r, wgt->
theme.
border_normal, 1.0f);
7053 if (font && pd->
text[0]) {
7054 float th = (float)al_get_font_line_height(font);
7055 al_draw_text(font, wgt->
theme.
text_normal, ax + wgt->
w / 2.0f, ay + (wgt->
h - th) / 2.0f, ALLEGRO_ALIGN_CENTER, pd->
text);
7061 float ax = ox + wgt->
x;
7062 float ay = oy + wgt->
y;
7063 ALLEGRO_FONT* font = wgt->
font ? wgt->
font : default_font;
7064 float fh = font ? (float)al_get_font_line_height(font) : 16.0f;
7067 float header_h = row_h;
7068 float data_y = ay + header_h;
7069 float data_h = wgt->
h - header_h;
7070 int visible = (int)(data_h / row_h);
7071 int nb_rows = (int)gd->
nb_rows;
7072 int need_sb, max_off, i, pcx, pcy, pcw, pch, need_hsb = 0;
7073 float sb_w, sb_h = 0.0f, cx, content_w = 0.0f, pane_w = 0.0f, maxh;
7076 al_draw_filled_rectangle(ax, ay, ax + wgt->
w, ay + wgt->
h, wgt->
theme.
bg_normal);
7077 if (visible < 1) visible = 1;
7078 need_sb = (nb_rows > visible) ? 1 : 0;
7086 visible = (int)(data_h / row_h);
7087 if (visible < 1) visible = 1;
7089 maxh = content_w - pane_w;
7090 if (maxh < 0) maxh = 0;
7093 max_off = nb_rows - visible;
7094 if (max_off < 0) max_off = 0;
7099 al_draw_filled_rectangle(ax, ay, ax + wgt->
w, ay + header_h, wgt->
theme.
bg_active);
7100 al_get_clipping_rectangle(&pcx, &pcy, &pcw, &pch);
7101 al_set_clipping_rectangle((
int)ax, (
int)ay, (
int)(wgt->
w - sb_w), (
int)header_h);
7103 al_hold_bitmap_drawing(
true);
7104 for (c = 0; c < gd->
nb_cols; c++) {
7107 const char* ind =
"";
7110 snprintf(title,
sizeof(title),
"%s%s", gd->
cols[pc].
title, ind);
7114 al_hold_bitmap_drawing(
false);
7115 al_set_clipping_rectangle(pcx, pcy, pcw, pch);
7118 al_get_clipping_rectangle(&pcx, &pcy, &pcw, &pch);
7119 al_set_clipping_rectangle((
int)ax, (
int)data_y, (
int)(wgt->
w - sb_w), (
int)data_h);
7122 for (i = 0; i < visible; i++) {
7124 float ry = data_y + (float)i * row_h;
7126 if (row >= nb_rows)
break;
7131 al_draw_filled_rectangle(ax, ry, ax + wgt->
w - sb_w, ry + row_h, t);
7137 al_draw_filled_rectangle(ax, ry, ax + wgt->
w - sb_w, ry + row_h, al_map_rgba_f(0.0f, 0.0f, 0.0f, 0.35f));
7138 al_draw_rectangle(ax + 1.0f, ry + 1.0f, ax + wgt->
w - sb_w - 1.0f, ry + row_h - 1.0f, wgt->
theme.
border_active, 2.0f);
7140 al_draw_filled_rectangle(ax, ry, ax + wgt->
w - sb_w, ry + row_h, wgt->
theme.
bg_hover);
7147 al_hold_bitmap_drawing(
true);
7148 for (i = 0; i < visible; i++) {
7150 float ry = data_y + (float)i * row_h;
7153 if (row >= nb_rows)
break;
7160 float lum = 0.299f * t.r + 0.587f * t.g + 0.114f * t.b;
7161 tint_text = (lum > 0.55f) ? al_map_rgb(0, 0, 0) : al_map_rgb(255, 255, 255);
7162 if (sel) tint_text = al_map_rgb(255, 255, 255);
7165 for (c = 0; c < gd->
nb_cols; c++) {
7167 const char* cell = gd->
cells[(size_t)row * gd->
nb_cols + pc];
7174 al_hold_bitmap_drawing(
false);
7175 al_set_clipping_rectangle(pcx, pcy, pcw, pch);
7183 ALLEGRO_COLOR sep = al_map_rgba_f(0.0f, 0.0f, 0.0f, 0.35f);
7186 for (vc = 0; vc < gd->
nb_cols; vc++) {
7190 if (vx >= ax + wgt->
w - sb_w)
break;
7191 if (vx <= ax)
continue;
7192 al_draw_line(vx, ay, vx, ay + wgt->
h - sb_h, sep, 1.0f);
7195 al_draw_line(ax, ay + header_h, ax + wgt->
w - sb_w, ay + header_h, wgt->
theme.
border_normal, 1.0f);
7207 float ax = ox + wgt->
x;
7208 float ay = oy + wgt->
y;
7213 float dx = ax + sd->
ratio * wgt->
w - th * 0.5f;
7214 float gx = dx + th * 0.5f;
7215 al_draw_filled_rectangle(dx, ay, dx + th, ay + wgt->
h, wgt->
theme.
bg_normal);
7216 al_draw_line(gx, ay + wgt->
h * 0.5f - th * 1.5f, gx, ay + wgt->
h * 0.5f + th * 1.5f, bar, 2.0f);
7218 float dy = ay + sd->
ratio * wgt->
h - th * 0.5f;
7219 float gy = dy + th * 0.5f;
7220 al_draw_filled_rectangle(ax, dy, ax + wgt->
w, dy + th, wgt->
theme.
bg_normal);
7221 al_draw_line(ax + wgt->
w * 0.5f - th * 1.5f, gy, ax + wgt->
w * 0.5f + th * 1.5f, gy, bar, 2.0f);
7228 float ax = ox + wgt->
x;
7229 float ay = oy + wgt->
y;
7230 ALLEGRO_FONT* font = wgt->
font ? wgt->
font : default_font;
7234 al_draw_scaled_bitmap(ld->
bg_bitmap, 0, 0,
7235 (
float)al_get_bitmap_width(ld->
bg_bitmap), (
float)al_get_bitmap_height(ld->
bg_bitmap),
7236 ax, ay, wgt->
w, wgt->
h, 0);
7238 al_draw_filled_rectangle(ax, ay, ax + wgt->
w, ay + wgt->
h, wgt->
theme.
bg_normal);
7249 float fh = (float)al_get_font_line_height(font);
7258 int visible_count = (int)(wgt->
h / ih);
7262 int max_off = (int)ld->
nb_items - visible_count;
7263 if (max_off < 0) max_off = 0;
7267 int need_scrollbar = ((int)ld->
nb_items > visible_count) ? 1 : 0;
7269 float item_area_w = wgt->
w - sb_w;
7275 float iy = ay + (float)i * ih;
7278 int row_hovered = (ld->
hover_row == idx) ? 1 : 0;
7283 }
else if (item->selected) {
7285 }
else if (row_hovered) {
7299 float item_max_w = item_area_w - pad * 2.0f;
7300 al_hold_bitmap_drawing(
true);
7303 float iy = ay + (float)i * ih;
7306 ax + pad, iy + (ih - fh) / 2.0f, item_max_w, item->text);
7308 al_hold_bitmap_drawing(
false);
7312 if (need_scrollbar) {
7313 float sb_x = ax + wgt->
w - sb_w;
7315 al_draw_filled_rectangle(sb_x, ay, ax + wgt->
w, ay + wgt->
h, wgt->
theme.
bg_normal);
7318 float ratio = (float)visible_count / (
float)ld->
nb_items;
7319 float thumb_h = ratio * wgt->
h;
7321 float track_range = wgt->
h - thumb_h;
7322 float pos_ratio = (max_off > 0) ? (
float)ld->
scroll_offset / (float)max_off : 0;
7323 float thumb_y = ay + pos_ratio * track_range;
7325 al_draw_filled_rounded_rectangle(sb_x + thumb_pad, thumb_y, ax + wgt->
w - thumb_pad, thumb_y + thumb_h,
7336 float ax = ox + wgt->
x;
7337 float ay = oy + wgt->
y;
7338 ALLEGRO_FONT* font = wgt->
font ? wgt->
font : default_font;
7346 al_draw_scaled_bitmap(rd->
bg_bitmap, 0, 0,
7347 (
float)al_get_bitmap_width(rd->
bg_bitmap), (
float)al_get_bitmap_height(rd->
bg_bitmap),
7348 ax, ay, wgt->
w, wgt->
h, 0);
7351 al_draw_filled_rectangle(ax, ay, ax + wgt->
w, ay + wgt->
h, bg);
7357 float fh = (float)al_get_font_line_height(font);
7359 int visible_count = (int)(wgt->
h / ih);
7365 int max_off = (int)rd->
nb_items - visible_count;
7366 if (max_off < 0) max_off = 0;
7370 int need_scrollbar = ((int)rd->
nb_items > visible_count) ? 1 : 0;
7376 float iy = ay + (float)i * ih;
7377 float cy = iy + ih / 2.0f;
7378 float cx = ax + pad + radio_r;
7384 ax, iy, wgt->
w, ih, 0);
7388 ax, iy, wgt->
w, ih, 0);
7400 al_hold_bitmap_drawing(
true);
7403 float iy = ay + (float)i * ih;
7404 float cx = ax + pad + radio_r;
7406 cx + radio_r + pad, iy + (ih - fh) / 2.0f, 0, rd->
items[idx].
text);
7408 al_hold_bitmap_drawing(
false);
7411 if (need_scrollbar) {
7413 float sb_x = ax + wgt->
w - sb_w;
7414 al_draw_filled_rectangle(sb_x, ay, ax + wgt->
w, ay + wgt->
h, wgt->
theme.
bg_normal);
7416 float ratio = (float)visible_count / (
float)rd->
nb_items;
7417 float thumb_h = ratio * wgt->
h;
7419 float track_range = wgt->
h - thumb_h;
7420 float pos_ratio = (max_off > 0) ? (
float)rd->
scroll_offset / (float)max_off : 0;
7421 float thumb_y = ay + pos_ratio * track_range;
7423 al_draw_filled_rounded_rectangle(sb_x + thumb_pad, thumb_y, ax + wgt->
w - thumb_pad, thumb_y + thumb_h,
7431 float ax = ox + wgt->
x;
7432 float ay = oy + wgt->
y;
7433 ALLEGRO_FONT* font = wgt->
font ? wgt->
font : default_font;
7436 al_draw_scaled_bitmap(cd->
bg_bitmap, 0, 0,
7437 (
float)al_get_bitmap_width(cd->
bg_bitmap), (
float)al_get_bitmap_height(cd->
bg_bitmap),
7438 ax, ay, wgt->
w, wgt->
h, 0);
7448 const char* display_text =
"";
7452 int cbbbx = 0, cbbby = 0, cbbbw = 0, cbbbh = 0;
7453 _text_dims(font, display_text[0] ? display_text :
"Ay", &cbbbx, &cbbby, &cbbbw, &cbbbh);
7454 float fh = (float)cbbbh;
7457 ax + pad, ay + (wgt->
h - fh) / 2.0f - (
float)cbbby, max_text_w, display_text);
7461 float arrow_y = ay + wgt->
h / 2.0f;
7479 float ay_down = widget_bottom;
7480 float ay_up = widget_top - panel_h;
7481 int fits_down = (ctx->
display_h <= 0) || (ay_down + panel_h <= (
float)ctx->
display_h);
7482 int fits_up = (ay_up >= 0.0f);
7484 return fits_up ? ay_up : (fits_down ? ay_down : ay_up);
7486 if (!fits_down && fits_up)
return ay_up;
7487 if (!fits_down && !fits_up) {
7489 float space_down = (ctx->
display_h > 0) ? ((
float)ctx->
display_h - widget_bottom) : panel_h;
7490 float space_up = widget_top;
7491 return (space_up > space_down) ? ay_up : ay_down;
7499 if (!wgt || !wgt->
data)
return;
7504 float ox = 0, oy = 0;
7513 float ax = ox + wgt->
x;
7514 float fh = (float)al_get_font_line_height(font);
7518 float dropdown_h = (float)vis * ih;
7524 float dropdown_w = wgt->
w;
7526 float max_item_w = 0;
7527 for (
size_t i = 0; i < cd->
nb_items; i++) {
7529 if (tw > max_item_w) max_item_w = tw;
7531 float needed = max_item_w + pad * 2;
7532 if (needed > dropdown_w) dropdown_w = needed;
7536 if (dropdown_w > cap) dropdown_w = cap;
7539 dropdown_w = (float)ctx->
display_w - ax;
7540 if (dropdown_w < wgt->w) dropdown_w = wgt->
w;
7547 if (sb_size < 10.0f) sb_size = 10.0f;
7548 float item_area_w = need_scrollbar ? dropdown_w - sb_size : dropdown_w;
7552 al_draw_scaled_bitmap(cd->
bg_bitmap, 0, 0,
7553 (
float)al_get_bitmap_width(cd->
bg_bitmap), (
float)al_get_bitmap_height(cd->
bg_bitmap),
7554 ax, ay, dropdown_w, dropdown_h, 0);
7556 al_draw_filled_rectangle(ax, ay, ax + dropdown_w, ay + dropdown_h, wgt->
theme.
bg_normal);
7564 int prev_cx = 0, prev_cy = 0, prev_cw = 0, prev_ch = 0;
7565 al_get_clipping_rectangle(&prev_cx, &prev_cy, &prev_cw, &prev_ch);
7566 al_set_clipping_rectangle((
int)ax, (
int)ay, (
int)dropdown_w, (
int)dropdown_h);
7570 float max_text_w = item_area_w - pad * 2;
7573 float iy = ay + (float)i * ih;
7585 }
else if (hovered) {
7595 al_hold_bitmap_drawing(
true);
7598 float iy = ay + (float)i * ih;
7602 al_hold_bitmap_drawing(
false);
7604 al_set_clipping_rectangle(prev_cx, prev_cy, prev_cw, prev_ch);
7607 if (need_scrollbar) {
7608 float sb_x = ax + dropdown_w - sb_size;
7610 al_draw_filled_rectangle(sb_x, ay, sb_x + sb_size, ay + dropdown_h,
7614 if (ratio > 1.0f) ratio = 1.0f;
7615 float thumb_h = ratio * dropdown_h;
7617 if (thumb_min < 12.0f) thumb_min = 12.0f;
7618 if (thumb_h < thumb_min) thumb_h = thumb_min;
7620 float pos_ratio = (max_offset > 0) ? (
float)cd->
scroll_offset / (float)max_offset : 0.0f;
7621 float thumb_y = ay + pos_ratio * (dropdown_h - thumb_h);
7624 al_draw_filled_rounded_rectangle(sb_x + thumb_pad, thumb_y,
7625 sb_x + sb_size - thumb_pad,
7638 float ax = ox + wgt->
x;
7639 float ay = oy + wgt->
y;
7640 ALLEGRO_FONT* font = wgt->
font ? wgt->
font : default_font;
7642 int draw_state = wgt->
state;
7648 if (font && dd->
label[0]) {
7650 int dbbx = 0, dbby = 0, dbbw = 0, dbbh = 0;
7652 float fh = (float)dbbh;
7661 float arrow_y = ay + wgt->
h / 2.0f;
7672 if (!wgt || !wgt->
data)
return;
7677 float ox = 0, oy = 0;
7686 float ax = ox + wgt->
x;
7687 float fh = (float)al_get_font_line_height(font);
7691 float panel_h = (float)vis * ih;
7701 if (sb_size < 10.0f) sb_size = 10.0f;
7702 float item_area_w = need_scrollbar ? panel_w - sb_size : panel_w;
7711 ax, ay, panel_w, panel_h, 0);
7712 }
else if (panel_rounded) {
7713 al_draw_filled_rounded_rectangle(ax, ay, ax + panel_w, ay + panel_h, prx, pry, wgt->
theme.
bg_normal);
7715 al_draw_filled_rectangle(ax, ay, ax + panel_w, ay + panel_h, wgt->
theme.
bg_normal);
7723 float max_text_w = item_area_w - pad * 2.0f;
7726 float iy = ay + (float)i * ih;
7740 al_hold_bitmap_drawing(
true);
7743 float iy = ay + (float)i * ih;
7748 al_hold_bitmap_drawing(
false);
7751 if (need_scrollbar) {
7752 float sb_x = ax + panel_w - sb_size;
7754 al_draw_filled_rectangle(sb_x, ay, sb_x + sb_size, ay + panel_h,
7758 if (ratio > 1.0f) ratio = 1.0f;
7759 float thumb_h = ratio * panel_h;
7761 if (thumb_min < 12.0f) thumb_min = 12.0f;
7762 if (thumb_h < thumb_min) thumb_h = thumb_min;
7764 float pos_ratio = (max_offset > 0) ? (
float)dd->
scroll_offset / (float)max_offset : 0.0f;
7765 float thumb_y = ay + pos_ratio * (panel_h - thumb_h);
7768 al_draw_filled_rounded_rectangle(sb_x + thumb_pad, thumb_y,
7769 sb_x + sb_size - thumb_pad,
7785 float ax = ox + wgt->
x;
7786 float ay = oy + wgt->
y;
7792 float bw = (float)al_get_bitmap_width(id->
bitmap);
7793 float bh = (float)al_get_bitmap_height(id->
bitmap);
7796 al_draw_scaled_bitmap(id->
bitmap, 0, 0, bw, bh, ax, ay, wgt->
w, wgt->
h, 0);
7798 float dx = ax + (wgt->
w - bw) / 2.0f;
7799 float dy = ay + (wgt->
h - bh) / 2.0f;
7800 al_draw_bitmap(id->
bitmap, dx, dy, 0);
7803 float scale_x = wgt->
w / bw;
7804 float scale_y = wgt->
h / bh;
7805 float scale = (scale_x < scale_y) ? scale_x : scale_y;
7806 float dw = bw * scale;
7807 float dh = bh * scale;
7808 float dx = ax + (wgt->
w - dw) / 2.0f;
7809 float dy = ay + (wgt->
h - dh) / 2.0f;
7810 al_draw_scaled_bitmap(id->
bitmap, 0, 0, bw, bh, dx, dy, dw, dh, 0);
7820 if (!font || !lb->
text[0])
return -1;
7821 if (click_x <= 0)
return 0;
7822 size_t len = strlen(lb->
text);
7825 float best_dist = click_x;
7826 for (
size_t i = 0; i < len;) {
7828 if (i + (
size_t)clen > len) clen = (int)(len - i);
7829 size_t pos = i + (size_t)clen;
7830 memcpy(tmp, lb->
text, pos);
7832 float tw =
_text_w(font, tmp);
7833 float dist = click_x - tw;
7834 if (dist < 0) dist = -dist;
7835 if (dist < best_dist) {
7839 if (tw > click_x)
break;
7849 float effective_w = wgt_w;
7851 float max_from_win = win_w - wgt_x;
7852 if (max_from_win > effective_w) effective_w = max_from_win;
7854 int lbbx = 0, lbby = 0, lbbw = 0, lbbh = 0;
7856 float tw = (float)lbbw;
7857 float max_text_w = effective_w - label_padding * 2;
7859 if (tw > max_text_w)
return ax + label_padding;
7860 return ax + (effective_w - tw) / 2.0f - (
float)lbbx;
7863 if (tw > max_text_w)
return ax + label_padding;
7864 return ax + effective_w - tw - label_padding - (float)lbbx;
7867 return ax + label_padding;
7872 float ax = ox + wgt->
x;
7873 float ay = oy + wgt->
y;
7874 ALLEGRO_FONT* font = wgt->
font ? wgt->
font : default_font;
7878 al_draw_scaled_bitmap(lb->
bg_bitmap, 0, 0,
7879 (
float)al_get_bitmap_width(lb->
bg_bitmap), (
float)al_get_bitmap_height(lb->
bg_bitmap),
7880 ax, ay, wgt->
w, wgt->
h, 0);
7883 if (!font || !lb->
text[0])
return;
7885 int lbbbx = 0, lbbby = 0, lbbbw = 0, lbbbh = 0;
7887 float fh = (float)lbbbh;
7890 float effective_w = wgt->
w;
7892 float max_from_win = win_w - wgt->
x;
7893 if (max_from_win > effective_w) effective_w = max_from_win;
7896 int is_link = (lb->
link[0] !=
'\0') ? 1 : 0;
7909 float tw = (float)lbbbw;
7915 float view_h = wgt->
h - lpad;
7917 int need_scrollbar = (content_h > view_h) ? 1 : 0;
7919 float text_w = max_text_w - sb_size;
7922 if (need_scrollbar) {
7923 float max_sy = content_h - view_h;
7924 if (max_sy < 0) max_sy = 0;
7932 int pcx, pcy, pcw, pch;
7933 al_get_clipping_rectangle(&pcx, &pcy, &pcw, &pch);
7936 float text_y = ay + lpad / 2.0f - lb->
scroll_y;
7947 float draw_w = tw < text_w ? tw : text_w;
7951 al_set_clipping_rectangle(pcx, pcy, pcw, pch);
7954 if (need_scrollbar) {
7960 float ty = ay + (wgt->
h - fh) / 2.0f - (
float)lbbby;
7963 if (tw > max_text_w) {
7967 tx = ax + (effective_w - tw) / 2.0f - (
float)lbbbx;
7968 al_draw_text(font, tc, tx, ty, 0, lb->
text);
7971 if (tw > max_text_w) {
7975 tx = ax + effective_w - tw - style->
label_padding - (float)lbbbx;
7976 al_draw_text(font, tc, tx, ty, 0, lb->
text);
7981 if (tw > max_text_w) {
7984 al_draw_text(font, tc, tx, ty, 0, lb->
text);
7992 size_t tlen = strlen(lb->
text);
7993 if ((
size_t)slo > tlen) slo = (int)tlen;
7994 if ((
size_t)shi > tlen) shi = (
int)tlen;
7996 memcpy(stmp, lb->
text, (
size_t)slo);
7998 float sx1 =
_text_w(font, stmp);
7999 memcpy(stmp, lb->
text, (
size_t)shi);
8001 float sx2 =
_text_w(font, stmp);
8007 float draw_w = tw < max_text_w ? tw : max_text_w;
8019 if (!cd || !cd->
draw)
return;
8024 if (!wgt || !wgt->
visible)
return;
8027 int saved_state = wgt->
state;
8032 switch (wgt->
type) {
8061 _draw_label(wgt, ox, oy, default_font, win_w, style);
8090 wgt->
state = saved_state;
8091 float dx = ox + wgt->
x;
8092 float dy = oy + wgt->
y;
8093 al_draw_filled_rectangle(dx, dy, dx + wgt->
w, dy + wgt->
h,
8094 al_map_rgba(0, 0, 0, 120));
8113 if (count == 0)
return 0.0f;
8130 if (!(win->
flags & flag))
return 0;
8147 *out_x = right_edge - sz - (float)pos * (sz + style->
tb_btn_spacing);
8157 for (
int i = 0; i < 3; i++) {
8158 int bt = btn_types[i];
8159 float bx, by, bw, bh;
8173 ALLEGRO_BITMAP* bmp = NULL;
8198 al_draw_scaled_bitmap(bmp, 0, 0,
8199 (
float)al_get_bitmap_width(bmp), (
float)al_get_bitmap_height(bmp),
8207 float cx = bx + bw / 2.0f;
8208 float cy = by + bh / 2.0f;
8209 float g = bw * 0.22f;
8214 al_draw_line(cx - g, cy + g * 0.5f, cx + g, cy + g * 0.5f, gc, thick);
8218 float off = g * 0.4f;
8219 al_draw_rectangle(cx - g + off, cy - g, cx + g, cy + g - off, gc, thick);
8220 al_draw_rectangle(cx - g, cy - g + off, cx + g - off, cy + g, gc, thick);
8223 al_draw_rectangle(cx - g, cy - g, cx + g, cy + g, gc, thick);
8226 al_draw_line(cx - g, cy - g, cx + g, cy + g, gc, thick);
8227 al_draw_line(cx + g, cy - g, cx - g, cy + g, gc, thick);
8237 ALLEGRO_FONT* font = win->
font ? win->
font : default_font;
8239 float tbh = frameless ? 0.0f : win->
titlebar_h;
8246 win->
x, win->
y, win->
w, tbh, 0);
8249 al_draw_filled_rounded_rectangle(win->
x, win->
y, win->
x + win->
w, win->
y + tbh,
8252 if (font && win->
title[0]) {
8253 int tbbx = 0, tbby = 0, tbbw = 0, tbbh = 0;
8255 float fh = (float)tbbh;
8259 win->
x + style->
title_padding, win->
y + (tbh - fh) / 2.0f - (
float)tbby, max_title_w, win->
title);
8268 float body_y = win->
y + tbh;
8269 float body_h = win->
h - tbh;
8272 int need_vscroll = 0;
8273 int need_hscroll = 0;
8278 if (win->
content_h > body_h) need_vscroll = 1;
8279 if (win->
content_w > win->
w) need_hscroll = 1;
8281 if (need_vscroll && win->
content_w > (win->
w - scrollbar_size)) need_hscroll = 1;
8282 if (need_hscroll && win->
content_h > (body_h - scrollbar_size)) need_vscroll = 1;
8291 float content_area_w = win->
w - (need_vscroll ? scrollbar_size : 0);
8292 float content_area_h = body_h - (need_hscroll ? scrollbar_size : 0);
8296 float max_sy = win->
content_h - content_area_h;
8297 if (max_sy < 0) max_sy = 0;
8304 float max_sx = win->
content_w - content_area_w;
8305 if (max_sx < 0) max_sx = 0;
8320 float bg_top = frameless ? body_y : body_y - 1.0f;
8324 al_draw_filled_rectangle(win->
x, bg_top, win->
x + win->
w, win->
y + win->
h,
8327 al_draw_rounded_rectangle(win->
x, win->
y, win->
x + win->
w, win->
y + win->
h,
8336 int prev_cx, prev_cy, prev_cw, prev_ch;
8337 al_get_clipping_rectangle(&prev_cx, &prev_cy, &prev_cw, &prev_ch);
8343 (
int)content_area_w - clip_pad, (
int)content_area_h);
8350 float label_win_w = 0;
8354 label_win_w = win->
w;
8360 al_set_clipping_rectangle(prev_cx, prev_cy, prev_cw, prev_ch);
8364 float sb_x = win->
x + win->
w - scrollbar_size;
8365 float sb_y = body_y;
8366 float sb_h = content_area_h;
8371 al_draw_filled_rectangle(sb_x, sb_y, sb_x + scrollbar_size, sb_y + sb_h,
8375 float ratio = content_area_h / win->
content_h;
8376 if (ratio > 1.0f) ratio = 1.0f;
8377 float thumb_h = ratio * sb_h;
8379 float max_scroll = win->
content_h - content_area_h;
8380 float pos_ratio = (max_scroll > 0) ? win->
scroll_y / max_scroll : 0;
8381 float thumb_y = sb_y + pos_ratio * (sb_h - thumb_h);
8387 float sb_x = win->
x;
8388 float sb_y = win->
y + win->
h - scrollbar_size;
8389 float sb_w = content_area_w;
8394 al_draw_filled_rectangle(sb_x, sb_y, sb_x + sb_w, sb_y + scrollbar_size,
8398 float ratio = content_area_w / win->
content_w;
8399 if (ratio > 1.0f) ratio = 1.0f;
8400 float thumb_w = ratio * sb_w;
8402 float max_scroll = win->
content_w - content_area_w;
8403 float pos_ratio = (max_scroll > 0) ? win->
scroll_x / max_scroll : 0;
8404 float thumb_x = sb_x + pos_ratio * (sb_w - thumb_w);
8412 float rx = win->
x + win->
w;
8413 float ry = win->
y + win->
h;
8415 ALLEGRO_COLOR grip_color = style->
grip_color;
8418 al_draw_line(rx - grip_size, ry - 2, rx - 2, ry - grip_size, grip_color, grip_thick);
8419 al_draw_line(rx - grip_size + 4, ry - 2, rx - 2, ry - grip_size + 4, grip_color, grip_thick);
8420 al_draw_line(rx - grip_size + 8, ry - 2, rx - 2, ry - grip_size + 8, grip_color, grip_thick);
8423 al_draw_rounded_rectangle(win->
x, win->
y, win->
x + win->
w, win->
y + tbh,
8431 float max_r = 0, max_b = 0;
8438 float r = win->
x + win->
w;
8439 float b = win->
y + win->
h;
8440 if (r > max_r) max_r = r;
8441 if (b > max_b) max_b = b;
8474 float ox = 0.0f, oy = 0.0f;
8476 ALLEGRO_DISPLAY* owner = tip_win ? tip_win->
native : NULL;
8482 float disp_w = (owner ? (float)al_get_display_width(owner) : (float)ctx->
display_w);
8483 float disp_h = (owner ? (float)al_get_display_height(owner) : (float)ctx->
display_h);
8486 float cl = 0.0f, ct = 0.0f, cr = disp_w, cb = disp_h;
8488 if (tip_win->
x > cl) cl = tip_win->
x;
8489 if (tip_win->
y > ct) ct = tip_win->
y;
8490 if (disp_w > 0.0f && tip_win->
x + tip_win->
w < cr) cr = tip_win->
x + tip_win->
w;
8491 if (disp_h > 0.0f && tip_win->
y + tip_win->
h < cb) cb = tip_win->
y + tip_win->
h;
8492 if (cr - cl < 8.0f || cb - ct < 8.0f) {
8500 float line_h = (float)al_get_font_line_height(ctx->
default_font) + 2.0f;
8501 float max_text_w = (cr - cl) - 4.0f - 16.0f;
8502 float natural_w, text_w, bw, bh, bx, by;
8504 if (max_text_w < 1.0f) max_text_w = 1.0f;
8506 if (natural_w <= max_text_w) {
8509 text_w = max_text_w;
8512 if (nlines < 1) nlines = 1;
8514 bw = text_w + 16.0f;
8515 bh = (float)nlines * line_h + 10.0f;
8516 bx = (float)ctx->
mouse_x + 14.0f;
8517 by = (float)ctx->
mouse_y + 20.0f;
8520 if (bx + bw > cr) bx = cr - bw;
8521 if (bx < cl) bx = cl;
8522 if (by + bh > cb) by = (float)ctx->
mouse_y - bh - 6.0f;
8523 if (by + bh > cb) by = cb - bh;
8524 if (by < ct) by = ct;
8525 al_draw_filled_rounded_rectangle(bx, by, bx + bw, by + bh, 4.0f, 4.0f, ctx->
style.
tooltip_bg);
8526 al_draw_rounded_rectangle(bx, by, bx + bw, by + bh, 4.0f, 4.0f, ctx->
style.
tooltip_border, 1.0f);
8554 int need_global_vscroll = 0;
8555 int need_global_hscroll = 0;
8562 if (eff_w > 0 && eff_h > 0) {
8563 if (ctx->
gui_bounds_h > eff_h) need_global_vscroll = 1;
8564 if (ctx->
gui_bounds_w > eff_w) need_global_hscroll = 1;
8566 if (need_global_vscroll && ctx->
gui_bounds_w > (eff_w - scrollbar_size)) need_global_hscroll = 1;
8567 if (need_global_hscroll && ctx->
gui_bounds_h > (eff_h - scrollbar_size)) need_global_vscroll = 1;
8570 float view_w = eff_w - (need_global_vscroll ? scrollbar_size : 0);
8571 float view_h = eff_h - (need_global_hscroll ? scrollbar_size : 0);
8572 if (need_global_vscroll) {
8574 if (max_sy < 0) max_sy = 0;
8580 if (need_global_hscroll) {
8582 if (max_sx < 0) max_sx = 0;
8591 ALLEGRO_TRANSFORM global_tf, prev_tf;
8592 al_copy_transform(&prev_tf, al_get_current_transform());
8593 al_identity_transform(&global_tf);
8599 al_compose_transform(&global_tf, &prev_tf);
8600 al_use_transform(&global_tf);
8603 int prev_cx, prev_cy, prev_cw, prev_ch;
8605 if (need_global_vscroll || need_global_hscroll) {
8606 al_get_clipping_rectangle(&prev_cx, &prev_cy, &prev_cw, &prev_ch);
8608 float clip_vw = eff_w - (need_global_vscroll ? scrollbar_size : 0);
8609 float clip_vh = eff_h - (need_global_hscroll ? scrollbar_size : 0);
8615 al_set_clipping_rectangle(0, 0, (
int)clip_vw, (
int)clip_vh);
8645 al_set_clipping_rectangle(prev_cx, prev_cy, prev_cw, prev_ch);
8650 if (need_global_vscroll || need_global_hscroll) {
8651 ALLEGRO_TRANSFORM sb_tf;
8652 al_identity_transform(&sb_tf);
8657 al_compose_transform(&sb_tf, &prev_tf);
8658 al_use_transform(&sb_tf);
8661 if (need_global_vscroll) {
8662 float sb_x = eff_w - scrollbar_size;
8664 float sb_h = eff_h - (need_global_hscroll ? scrollbar_size : 0);
8665 float view_h = sb_h;
8668 al_draw_filled_rectangle(sb_x, sb_y, sb_x + scrollbar_size, sb_y + sb_h,
8673 if (ratio > 1.0f) ratio = 1.0f;
8674 float thumb_h = ratio * sb_h;
8677 float pos_ratio = (max_scroll > 0) ? ctx->
global_scroll_y / max_scroll : 0;
8678 float thumb_y = sb_y + pos_ratio * (sb_h - thumb_h);
8686 if (need_global_hscroll) {
8688 float sb_y = eff_h - scrollbar_size;
8689 float sb_w = eff_w - (need_global_vscroll ? scrollbar_size : 0);
8690 float view_w = sb_w;
8693 al_draw_filled_rectangle(sb_x, sb_y, sb_x + sb_w, sb_y + scrollbar_size,
8698 if (ratio > 1.0f) ratio = 1.0f;
8699 float thumb_w = ratio * sb_w;
8702 float pos_ratio = (max_scroll > 0) ? ctx->
global_scroll_x / max_scroll : 0;
8703 float thumb_x = sb_x + pos_ratio * (sb_w - thumb_w);
8716 al_use_transform(&prev_tf);
8741 ALLEGRO_BITMAP* prev_target = al_get_target_bitmap();
8781 if (!win || !win->
native)
continue;
8788 if (al_get_display_flags(win->
native) & ALLEGRO_MINIMIZED)
continue;
8790 al_set_target_backbuffer(win->
native);
8792 ALLEGRO_TRANSFORM id_tf, prev_tf;
8793 al_copy_transform(&prev_tf, al_get_current_transform());
8794 al_identity_transform(&id_tf);
8795 al_use_transform(&id_tf);
8814 al_use_transform(&prev_tf);
8818 if (prev_target) al_set_target_bitmap(prev_target);
8833 if ((w > 0) != (h > 0)) {
8834 n_log(
LOG_ERR,
"n_gui_set_virtual_size: both dimensions must be > 0 (got w=%.1f, h=%.1f); virtual canvas not changed", w, h);
8980 if (new_w <= 0 || new_h <= 0)
return;
8986 if (win->
native)
continue;
9081 if (scale < 0.25f) scale = 0.25f;
9082 if (scale > 8.0f) scale = 8.0f;
9122 int logical_w = al_get_display_width(
display);
9123 int logical_h = al_get_display_height(
display);
9124 ALLEGRO_BITMAP* backbuffer = al_get_backbuffer(
display);
9125 if (backbuffer && logical_w > 0 && logical_h > 0) {
9126 int physical_w = al_get_bitmap_width(backbuffer);
9127 int physical_h = al_get_bitmap_height(backbuffer);
9128 float scale_x = (float)physical_w / (
float)logical_w;
9129 float scale_y = (float)physical_h / (
float)logical_h;
9130 scale = (scale_x > scale_y) ? scale_x : scale_y;
9131 if (scale < 0.5f) scale = 1.0f;
9134#ifdef ALLEGRO_ANDROID
9137 int dpi = al_get_display_option(
display, ALLEGRO_DEFAULT_DISPLAY_ADAPTER);
9141 float android_scale = (float)dpi / 160.0f;
9142 if (android_scale >= 0.5f) scale = android_scale;
9146 if (scale < 0.25f) scale = 0.25f;
9147 if (scale > 8.0f) scale = 8.0f;
9157 if (wgt->
w <= 0)
return;
9158 if (wgt->
h <= 0)
return;
9162 float ay = win_content_y + wgt->
y;
9163 float local_y = my - ay;
9165 ratio = 1.0 - (double)local_y / (
double)wgt->
h;
9167 float ax = win_x + wgt->
x;
9168 float local_x = mx - ax;
9169 ratio = (double)local_x / (
double)wgt->
w;
9171 if (ratio < 0.0) ratio = 0.0;
9172 if (ratio > 1.0) ratio = 1.0;
9178 if (new_val != sd->
value) {
9179 sd->
value = new_val;
9189 float ax = win_x + wgt->
x;
9190 float ay = win_content_y + wgt->
y;
9193 if (ratio_viewport > 1.0) ratio_viewport = 1.0;
9195 if (max_scroll < 0) max_scroll = 0;
9199 float thumb_h = (float)(ratio_viewport * (
double)wgt->
h);
9201 float track_range = wgt->
h - thumb_h;
9202 if (track_range <= 0)
return;
9203 pos_ratio = (double)(my - ay - thumb_h / 2.0f) / (double)track_range;
9205 float thumb_w = (float)(ratio_viewport * (
double)wgt->
w);
9207 float track_range = wgt->
w - thumb_w;
9208 if (track_range <= 0)
return;
9209 pos_ratio = (double)(mx - ax - thumb_w / 2.0f) / (double)track_range;
9211 if (pos_ratio < 0.0) pos_ratio = 0.0;
9212 if (pos_ratio > 1.0) pos_ratio = 1.0;
9226 out[0] = (char)(0xC0 | (cp >> 6));
9227 out[1] = (char)(0x80 | (cp & 0x3F));
9231 out[0] = (char)(0xE0 | (cp >> 12));
9232 out[1] = (char)(0x80 | ((cp >> 6) & 0x3F));
9233 out[2] = (char)(0x80 | (cp & 0x3F));
9236 if (cp < 0x110000) {
9237 out[0] = (char)(0xF0 | (cp >> 18));
9238 out[1] = (char)(0x80 | ((cp >> 12) & 0x3F));
9239 out[2] = (char)(0x80 | ((cp >> 6) & 0x3F));
9240 out[3] = (char)(0x80 | (cp & 0x3F));
9258 size_t del_len = hi - lo;
9271 size_t len = hi - lo;
9273 Malloc(tmp,
char, len + 1);
9275 memcpy(tmp, &td->
text[lo], len);
9291 size_t clip_len = strlen(clip);
9296 for (
size_t ci = 0; ci < clip_len && flen <
N_GUI_TEXT_MAX - 1; ci++) {
9297 if (clip[ci] ==
'\r') {
9299 }
else if (clip[ci] ==
'\n') {
9300 if (td->
multiline) filtered[flen++] =
'\n';
9301 }
else if ((
unsigned char)clip[ci] >= 32 || ((
unsigned char)clip[ci] & 0xC0) == 0x80) {
9302 filtered[flen++] = clip[ci];
9303 }
else if (((
unsigned char)clip[ci] & 0xC0) == 0xC0) {
9304 filtered[flen++] = clip[ci];
9307 filtered[flen] =
'\0';
9308 if (flen > 0 && td->
text_len + flen <= td->char_limit) {
9338 size_t tlen = strlen(lb->
text);
9339 if ((
size_t)slo > tlen) slo = (int)tlen;
9340 if ((
size_t)shi > tlen) shi = (
int)tlen;
9341 int len = shi - slo;
9343 Malloc(sel,
char, (
size_t)len + 1);
9345 memcpy(sel, &lb->
text[slo], (
size_t)len);
9360 size_t len = hi - lo;
9361 Malloc(sel,
char, len + 1);
9363 memcpy(sel, &td->
text[lo], len);
9387 int shift = (ev->keyboard.modifiers & ALLEGRO_KEYMOD_SHIFT) ? 1 : 0;
9388 int ctrl = (ev->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL) ? 1 : 0;
9391 if (ctrl && ev->keyboard.keycode == ALLEGRO_KEY_A) {
9400 if (ctrl && ev->keyboard.keycode == ALLEGRO_KEY_C) {
9408 if (ctrl && ev->keyboard.keycode == ALLEGRO_KEY_X) {
9417 if (ctrl && ev->keyboard.keycode == ALLEGRO_KEY_V) {
9428 if (ev->keyboard.keycode == ALLEGRO_KEY_BACKSPACE) {
9437 }
while (erase_start > 0 && cont_count <= 3 && ((
unsigned char)td->
text[erase_start] & 0xC0) == 0x80);
9438 size_t erase_len = td->
cursor_pos - erase_start;
9447 if (ev->keyboard.keycode == ALLEGRO_KEY_DELETE) {
9460 if (ev->keyboard.keycode == ALLEGRO_KEY_LEFT) {
9482 if (ev->keyboard.keycode == ALLEGRO_KEY_RIGHT) {
9503 if (ev->keyboard.keycode == ALLEGRO_KEY_HOME) {
9514 if (ev->keyboard.keycode == ALLEGRO_KEY_END) {
9527 if (ev->keyboard.keycode == ALLEGRO_KEY_UP || ev->keyboard.keycode == ALLEGRO_KEY_DOWN) {
9535 float base_wrap_w = wgt->
w - pad * 2;
9536 float text_area_h = wgt->
h - pad * 2;
9538 float wrap_w = (content_h > text_area_h)
9539 ? (wgt->
w - sb_size - pad * 2)
9545 int cursor_line = 0;
9548 for (
size_t i = 0; i < td->
text_len;) {
9553 if (td->
text[i] ==
'\n') {
9562 memcpy(ch, &td->
text[i], (
size_t)clen);
9565 if (cx + cw > wrap_w) {
9580 int total_lines = line;
9584 if (ev->keyboard.keycode == ALLEGRO_KEY_UP) {
9585 if (cursor_line <= 0) {
9589 target_line = cursor_line - 1;
9591 if (cursor_line >= total_lines) {
9595 target_line = cursor_line + 1;
9601 size_t best_pos = 0;
9602 float best_dist = 1e9f;
9605 if (line == target_line) {
9606 best_dist = (cursor_x >= 0) ? cursor_x : -cursor_x;
9610 for (
size_t i = 0; i < td->
text_len;) {
9611 if (td->
text[i] ==
'\n') {
9612 if (line >= target_line)
break;
9615 if (line == target_line) {
9616 float dist = (cursor_x >= cx) ? (cursor_x - cx) : (cx - cursor_x);
9617 if (dist < best_dist) {
9628 memcpy(ch, &td->
text[i], (
size_t)clen);
9631 if (cx + cw > wrap_w) {
9632 if (line >= target_line)
break;
9635 if (line == target_line) {
9636 float dist = (cursor_x >= cx) ? (cursor_x - cx) : (cx - cursor_x);
9637 if (dist < best_dist) {
9645 if (line == target_line) {
9646 float dist = (cursor_x >= cx) ? (cursor_x - cx) : (cx - cursor_x);
9647 if (dist < best_dist) {
9649 best_pos = i + (size_t)clen;
9664 if (ev->keyboard.keycode == ALLEGRO_KEY_ENTER) {
9683 if (ev->keyboard.unichar >= 32) {
9689 int utf8_len =
_utf8_encode(ev->keyboard.unichar, utf8);
9690 if (utf8_len > 0 && td->
text_len + (
size_t)utf8_len <= td->char_limit) {
9751 if (!highlight || !scroll || nb <= 0)
9761 hi = (delta >= 0) ? -1 : nb;
9772 else if (max_visible > 0 && hi >= *scroll + max_visible)
9773 *scroll = hi - max_visible + 1;
9796 float ax, ay, fh, row_h;
9803 fh = font ? (float)al_get_font_line_height(font) : 16.0f;
9808 if (py < ay + row_h) {
9810 for (
size_t c = 0; c < gd->
nb_cols; c++) {
9815 if (px >= right - 4.0f && px <= right + 4.0f) {
9839 int event_consumed = 0;
9853 if (src && src != ctx->
display) {
9856 if (pwin && pwin->
native == src) {
9872 switch (event.type) {
9873 case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
9874 case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
9875 case ALLEGRO_EVENT_KEY_DOWN:
9876 case ALLEGRO_EVENT_KEY_CHAR:
9877 case ALLEGRO_EVENT_KEY_UP:
9878 case ALLEGRO_EVENT_MOUSE_WARPED:
9879 case ALLEGRO_EVENT_DISPLAY_RESIZE:
9880 case ALLEGRO_EVENT_DISPLAY_EXPOSE:
9881 case ALLEGRO_EVENT_DISPLAY_CLOSE:
9882 case ALLEGRO_EVENT_DISPLAY_SWITCH_IN:
9883 case ALLEGRO_EVENT_DISPLAY_SWITCH_OUT:
9884 case ALLEGRO_EVENT_DISPLAY_HALT_DRAWING:
9885 case ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING:
9904 if (nwin && event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
9915 nwin->
state &= ~N_GUI_WIN_OPEN;
9919 nwin->
state &= ~N_GUI_WIN_OPEN;
9929 if (nwin && event.type == ALLEGRO_EVENT_DISPLAY_HALT_DRAWING) {
9931 al_acknowledge_drawing_halt(nwin->
native);
9935 if (nwin && event.type == ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING) {
9936 al_acknowledge_drawing_resume(nwin->
native);
9941 if (nwin && event.type == ALLEGRO_EVENT_DISPLAY_RESIZE) {
9942 al_acknowledge_resize(nwin->
native);
9943 float new_w = (float)al_get_display_width(nwin->
native);
9944 float new_h = (float)al_get_display_height(nwin->
native);
9957 if (new_w > 0.0f && new_h > 0.0f) {
9986 if (event.type == ALLEGRO_EVENT_DISPLAY_SWITCH_OUT) {
10004 if (event.type == ALLEGRO_EVENT_MOUSE_AXES) {
10005 ctx->
mouse_x =
event.mouse.x;
10006 ctx->
mouse_y =
event.mouse.y;
10054 ? ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_E
10055 : ALLEGRO_SYSTEM_MOUSE_CURSOR_DEFAULT;
10057 al_set_system_mouse_cursor(
_ctx_io_display(ctx), (ALLEGRO_SYSTEM_MOUSE_CURSOR)want);
10062 if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN && event.mouse.button == 1) {
10066 ctx->
mouse_x =
event.mouse.x;
10067 ctx->
mouse_y =
event.mouse.y;
10069 if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP && event.mouse.button == 1) {
10087 if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN && event.mouse.button == 2) {
10091 ctx->
mouse_x =
event.mouse.x;
10092 ctx->
mouse_y =
event.mouse.y;
10097 (event.type == ALLEGRO_EVENT_MOUSE_AXES || event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN)) {
10099 if (drag_wgt && drag_wgt->
data) {
10100 float d_ox = 0, d_oy = 0;
10104 float d_fh = d_font ? (float)al_get_font_line_height(d_font) : 16.0f;
10105 float d_my = (float)ctx->
mouse_y;
10106 float d_mx = (float)ctx->
mouse_x;
10107 switch (drag_wgt->
type) {
10112 float d_ay = d_oy + drag_wgt->
y + drag_wgt->
h;
10122 float d_ay = d_oy + drag_wgt->
y + drag_wgt->
h;
10131 float d_ay = d_oy + drag_wgt->
y;
10132 int visible = (int)(drag_wgt->
h / ih);
10139 float d_ay = d_oy + drag_wgt->
y;
10140 int visible = (int)(drag_wgt->
h / ih);
10148 float ta_view_h = drag_wgt->
h - ta_pad * 2;
10150 float ta_text_w = drag_wgt->
w - ta_sb_w;
10152 float d_ay = d_oy + drag_wgt->
y + ta_pad;
10154 d_my, d_ay, ta_view_h,
10155 ta_view_h, ta_content_h,
10162 float d_ax = d_ox + drag_wgt->
x;
10163 float d_ay = d_oy + drag_wgt->
y;
10166 r = (drag_wgt->
w > 0) ? ((
float)ctx->
mouse_x - d_ax) / drag_wgt->
w : spd->
ratio;
10168 r = (drag_wgt->
h > 0) ? (d_my - d_ay) / drag_wgt->
h : spd->
ratio;
10169 if (r < spd->min_ratio) r = spd->
min_ratio;
10177 float row_h = d_fh + 2.0f;
10179 int nb_rows = (int)((hd->
len + (
size_t)bpr - 1) / (size_t)bpr);
10181 float d_ay = d_oy + drag_wgt->
y;
10182 if (visible < 1) visible = 1;
10188 float row_h = d_fh + 2.0f;
10191 float d_ay = d_oy + drag_wgt->
y;
10192 if (visible < 1) visible = 1;
10199 float header_h = row_h;
10200 float data_h = drag_wgt->
h - header_h;
10201 int visible = (int)(data_h / row_h);
10202 float d_ay = d_oy + drag_wgt->
y + header_h;
10203 if (visible < 1) visible = 1;
10207 if (nw < 16.0f) nw = 16.0f;
10212 float d_ax = d_ox + drag_wgt->
x;
10213 float dg_content_w = 0.0f, dg_pane_w = 0.0f;
10230 float screen_mx = (float)ctx->
mouse_x;
10231 float screen_my = (float)ctx->
mouse_y;
10237 float virtual_mx = screen_mx;
10238 float virtual_my = screen_my;
10244 float mx = virtual_mx;
10245 float my = virtual_my;
10251 event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN)
10255 event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP)
10259 int just_right_pressed = (
event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN &&
10260 event.mouse.button == 2)
10265 int just_middle_pressed = (
event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN &&
10266 event.mouse.button == 3)
10287 if (ctx->
mouse_b1 && (event.type == ALLEGRO_EVENT_MOUSE_AXES || event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN)) {
10291 int need_hscroll = (ctx->
gui_bounds_w > eff_w) ? 1 : 0;
10292 float sb_h = eff_h - (need_hscroll ? scrollbar_size : 0);
10293 float view_h = sb_h;
10295 if (ratio > 1.0f) ratio = 1.0f;
10296 float thumb_h = ratio * sb_h;
10299 float track_range = sb_h - thumb_h;
10300 if (track_range > 0 && max_scroll > 0) {
10301 float pos_ratio = (virtual_my - thumb_h / 2.0f) / track_range;
10302 if (pos_ratio < 0) pos_ratio = 0;
10303 if (pos_ratio > 1) pos_ratio = 1;
10308 int need_vscroll = (ctx->
gui_bounds_h > eff_h) ? 1 : 0;
10309 float sb_w = eff_w - (need_vscroll ? scrollbar_size : 0);
10310 float view_w = sb_w;
10312 if (ratio > 1.0f) ratio = 1.0f;
10313 float thumb_w = ratio * sb_w;
10316 float track_range = sb_w - thumb_w;
10317 if (track_range > 0 && max_scroll > 0) {
10318 float pos_ratio = (virtual_mx - thumb_w / 2.0f) / track_range;
10319 if (pos_ratio < 0) pos_ratio = 0;
10320 if (pos_ratio > 1) pos_ratio = 1;
10326 if (just_released) {
10334 if (just_pressed && eff_w > 0 && eff_h > 0) {
10337 int need_vscroll = (ctx->
gui_bounds_h > eff_h) ? 1 : 0;
10338 int need_hscroll = (ctx->
gui_bounds_w > eff_w) ? 1 : 0;
10339 if (need_vscroll && ctx->
gui_bounds_w > (eff_w - scrollbar_size)) need_hscroll = 1;
10340 if (need_hscroll && ctx->
gui_bounds_h > (eff_h - scrollbar_size)) need_vscroll = 1;
10342 if (need_vscroll) {
10343 float sb_x = eff_w - scrollbar_size;
10344 float sb_h = eff_h - (need_hscroll ? scrollbar_size : 0);
10345 if (
_point_in_rect(virtual_mx, virtual_my, sb_x, 0, scrollbar_size, sb_h)) {
10350 if (need_hscroll) {
10351 float sb_y = eff_h - scrollbar_size;
10352 float sb_w = eff_w - (need_vscroll ? scrollbar_size : 0);
10353 if (
_point_in_rect(virtual_mx, virtual_my, 0, sb_y, sb_w, scrollbar_size)) {
10364 (just_pressed || event.type == ALLEGRO_EVENT_MOUSE_AXES)) {
10366 if (cb_wgt && cb_wgt->
data) {
10370 float cb_ox = 0, cb_oy = 0;
10374 float cb_fh = cb_font ? (float)al_get_font_line_height(cb_font) : 16.0f;
10376 float cb_ax = cb_ox + cb_wgt->
x;
10380 float cb_dd_h = (float)cb_vis * cb_ih;
10385 float cb_dd_w = cb_wgt->
w;
10387 float cb_max_tw = 0;
10388 for (
size_t ci = 0; ci < cbd->
nb_items; ci++) {
10390 if (tw > cb_max_tw) cb_max_tw = tw;
10392 float cb_needed = cb_max_tw + cb_pad * 2;
10393 if (cb_needed > cb_dd_w) cb_dd_w = cb_needed;
10396 if (cb_dd_w > cb_cap) cb_dd_w = cb_cap;
10398 cb_dd_w = (float)ctx->
display_w - cb_ax;
10399 if (cb_dd_w < cb_wgt->w) cb_dd_w = cb_wgt->
w;
10403 if (!just_pressed) {
10408 if (event.type == ALLEGRO_EVENT_MOUSE_AXES && event.mouse.dz != 0) {
10413 int cb_hi = cbd->
scroll_offset + (int)((my - cb_ay) / cb_ih);
10418 }
else if (
_point_in_rect(mx, my, cb_ax, cb_ay, cb_dd_w, cb_dd_h)) {
10422 if (cb_sb_size < 10.0f) cb_sb_size = 10.0f;
10423 float cb_item_w = cb_need_sb ? cb_dd_w - cb_sb_size : cb_dd_w;
10425 if (cb_need_sb && mx >= cb_ax + cb_item_w) {
10433 int clicked_idx = cbd->
scroll_offset + (int)((my - cb_ay) / cb_ih);
10434 if (clicked_idx >= 0 && (
size_t)clicked_idx < cbd->
nb_items) {
10458 (just_pressed || event.type == ALLEGRO_EVENT_MOUSE_AXES)) {
10460 if (dm_wgt && dm_wgt->
data) {
10464 float dm_ox = 0, dm_oy = 0;
10468 float dm_fh = dm_font ? (float)al_get_font_line_height(dm_font) : 16.0f;
10470 float dm_ax = dm_ox + dm_wgt->
x;
10473 float dm_panel_h = (float)dm_vis * dm_ih;
10478 int over_panel =
_point_in_rect(mx, my, dm_ax, dm_ay, dm_panel_w, dm_panel_h);
10480 if (!just_pressed) {
10487 if (event.type == ALLEGRO_EVENT_MOUSE_AXES && event.mouse.dz != 0) {
10490 -event.mouse.dz, -1);
10492 int dm_hi = dmd->
scroll_offset + (int)((my - dm_ay) / dm_ih);
10497 }
else if (over_panel) {
10501 if (dm_sb_size < 10.0f) dm_sb_size = 10.0f;
10502 float dm_item_w = dm_need_sb ? dm_panel_w - dm_sb_size : dm_panel_w;
10504 if (dm_need_sb && mx >= dm_ax + dm_item_w) {
10512 int clicked_idx = dmd->
scroll_offset + (int)((my - dm_ay) / dm_ih);
10513 if (clicked_idx >= 0 && (
size_t)clicked_idx < dmd->
nb_entries) {
10527 float dm_btn_ax = dm_ox + dm_wgt->
x;
10528 float dm_btn_ay = dm_oy + dm_wgt->
y;
10541 if (event.type == ALLEGRO_EVENT_MOUSE_AXES ||
10542 event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN ||
10543 event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) {
10553 if (!wgt)
continue;
10554 wgt->
state &= ~N_GUI_STATE_HOVER;
10572 captured_wnode = wnode;
10595 event_consumed = 1;
10599 if (!captured_wnode) {
10601 if (just_pressed) {
10605 if (!win)
return 1;
10611 if (prev_fw) prev_fw->
state &= ~N_GUI_STATE_FOCUSED;
10617 int auto_scrollbar_hit = 0;
10622 int need_vscroll = 0, need_hscroll = 0;
10624 if (win->
content_h > body_h) need_vscroll = 1;
10625 if (win->
content_w > win->
w) need_hscroll = 1;
10626 if (need_vscroll && win->
content_w > (win->
w - scrollbar_size)) need_hscroll = 1;
10627 if (need_hscroll && win->
content_h > (body_h - scrollbar_size)) need_vscroll = 1;
10628 float content_area_w = win->
w - (need_vscroll ? scrollbar_size : 0);
10629 float content_area_h = body_h - (need_hscroll ? scrollbar_size : 0);
10632 if (need_vscroll) {
10633 float sb_x = win->
x + win->
w - scrollbar_size;
10634 float sb_y = body_y;
10635 float sb_h = content_area_h;
10640 auto_scrollbar_hit = 1;
10645 if (need_hscroll && !auto_scrollbar_hit) {
10646 float sb_x = win->
x;
10647 float sb_y = win->
y + win->
h - scrollbar_size;
10648 float sb_w = content_area_w;
10653 auto_scrollbar_hit = 1;
10662 float rx = win->
x + win->
w - grip;
10663 float ry = win->
y + win->
h - grip;
10665 int in_resize_area = 0;
10669 int need_vscroll = 0, need_hscroll = 0;
10671 if (win->
content_h > body_h) need_vscroll = 1;
10672 if (win->
content_w > win->
w) need_hscroll = 1;
10673 if (need_vscroll && win->
content_w > (win->
w - scrollbar_size)) need_hscroll = 1;
10674 if (need_hscroll && win->
content_h > (body_h - scrollbar_size)) need_vscroll = 1;
10675 if (need_vscroll || need_hscroll) {
10677 float corner_x = win->
x + win->
w - scrollbar_size;
10678 float corner_y = win->
y + win->
h - scrollbar_size;
10679 in_resize_area = just_pressed &&
_point_in_rect(mx, my, corner_x, corner_y, scrollbar_size, scrollbar_size);
10681 in_resize_area = just_pressed &&
_point_in_rect(mx, my, rx, ry, grip, grip);
10684 in_resize_area = just_pressed &&
_point_in_rect(mx, my, rx, ry, grip, grip);
10686 if (in_resize_area) {
10698 float tbx, tby, tbw, tbhh;
10735 float content_x = win->
x - win->
scroll_x;
10746 float ax = content_x + wgt->
x;
10747 float ay = content_y + wgt->
y;
10761 int row_in_view = (int)((my - ay) / ih);
10763 if (row >= 0 && (
size_t)row < ld->
nb_items) {
10770 if (just_pressed) {
10820 float ta_view_h = wgt->
h - text_pad * 2;
10822 int ta_need_sb = (ta_content_h > ta_view_h) ? 1 : 0;
10824 if (ta_need_sb && mx > ax + wgt->
w - ta_sb_w) {
10826 float ta_text_w = wgt->
w - ta_sb_w;
10829 my, ay + text_pad, ta_view_h,
10830 ta_view_h, ta_content_h,
10833 goto textarea_click_done;
10837 ax, ay, wgt->
w, wgt->
h,
10843 textarea_click_done:;
10864 float effective_w = wgt->
w;
10871 float mfw = lww - wgt->
x;
10872 if (mfw > effective_w) effective_w = mfw;
10874 float max_text_w = effective_w - lpad * 2;
10876 float view_h = wgt->
h - lpad;
10878 float tw2 = max_text_w - sb_sz;
10880 ax + lpad, ay + lpad / 2.0f, click_lb->
scroll_y, mx, my);
10888 float click_x = mx - text_ox;
10891 if (char_pos >= 0) {
10893 click_lb->
sel_end = char_pos;
10924 if (click_yd && yf && click_yd->
text) {
10943 if (target < 0) target = 0;
10945 if (target > max_off) target = max_off;
10957 float lfh = lf ? (float)al_get_font_line_height(lf) : 16.0f;
10959 int lb_visible = (int)(wgt->
h / lih);
10960 int lb_need_sb = ((int)lbd->
nb_items > lb_visible) ? 1 : 0;
10963 int lb_max_off = (int)lbd->
nb_items - lb_visible;
10964 if (lb_max_off < 0) lb_max_off = 0;
10968 if (lb_need_sb && mx > ax + wgt->
w - lb_sb_w) {
10973 int clicked_idx = lbd->
scroll_offset + (int)((my - ay) / lih);
10974 if (clicked_idx >= 0 && (
size_t)clicked_idx < lbd->
nb_items) {
10989 float band = spd->
divider * 2.0f;
10992 float dcx = ax + spd->
ratio * wgt->
w;
10993 on_div = (mx >= dcx - band && mx <= dcx + band);
10995 float dcy = ay + spd->
ratio * wgt->
h;
10996 on_div = (my >= dcy - band && my <= dcy + band);
11003 float hfh = hf ? (float)al_get_font_line_height(hf) : 16.0f;
11004 float row_h = hfh + 2.0f;
11006 int nb_rows = (int)((hd->
len + (
size_t)bpr - 1) / (size_t)bpr);
11010 if (hv_visible < 1) hv_visible = 1;
11011 hv_need_sb = (nb_rows > hv_visible) ? 1 : 0;
11013 if (hv_need_sb && mx > ax + wgt->
w - hv_sb_w) {
11021 float yfh = yf ? (float)al_get_font_line_height(yf) : 16.0f;
11022 float row_h = yfh + 2.0f;
11027 if (yv_visible < 1) yv_visible = 1;
11028 yv_need_sb = (nb_lines > yv_visible) ? 1 : 0;
11030 if (yv_need_sb && mx > ax + wgt->
w - yv_sb_w) {
11038 float gfh = gf ? (float)al_get_font_line_height(gf) : 16.0f;
11040 float header_h = row_h;
11041 float data_h = wgt->
h - header_h;
11042 int dg_visible = (int)(data_h / row_h);
11045 if (dg_visible < 1) dg_visible = 1;
11046 float dg_content_w = 0.0f, dg_pane_w = 0.0f, dg_hsb_h;
11047 int dg_need_hsb = 0;
11048 dg_need_sb = ((int)gd->
nb_rows > dg_visible) ? 1 : 0;
11052 if (dg_need_hsb && my > ay + wgt->
h - dg_hsb_h && mx < ax + dg_pane_w) {
11057 }
else if (dg_need_sb && mx > ax + wgt->
w - dg_sb_w && my >= ay + header_h) {
11060 }
else if (my < ay + header_h) {
11066 int hit = -1, resize_col = -1;
11067 for (cc = 0; cc < gd->
nb_cols; cc++) {
11072 if (mx >= right - 4.0f && mx <= right + 4.0f) {
11073 resize_col = (int)pc;
11076 if (mx >= bx && mx < right) {
11082 if (resize_col >= 0) {
11087 }
else if (hit >= 0) {
11092 int clicked = gd->
scroll_offset + (int)((my - (ay + header_h)) / row_h);
11093 if (clicked >= 0 && (
size_t)clicked < gd->
nb_rows) {
11097 int ctrl = 0, shift = 0;
11098 if (al_is_keyboard_installed()) {
11099 ALLEGRO_KEYBOARD_STATE kb;
11100 al_get_keyboard_state(&kb);
11101 ctrl = al_key_down(&kb, ALLEGRO_KEY_LCTRL) || al_key_down(&kb, ALLEGRO_KEY_RCTRL);
11102 shift = al_key_down(&kb, ALLEGRO_KEY_LSHIFT) || al_key_down(&kb, ALLEGRO_KEY_RSHIFT);
11111 for (rr = lo; rr <= hi; rr++) gd->
row_sel[rr] = 1;
11130 float rfh = rf ? (float)al_get_font_line_height(rf) : 16.0f;
11132 int rl_visible = (int)(wgt->
h / rih);
11133 int rl_need_sb = ((int)rld->
nb_items > rl_visible) ? 1 : 0;
11136 int rl_max_off = (int)rld->
nb_items - rl_visible;
11137 if (rl_max_off < 0) rl_max_off = 0;
11141 if (rl_need_sb && mx > ax + wgt->
w - rl_sb_w) {
11146 int clicked_idx = rld->
scroll_offset + (int)((my - ay) / rih);
11147 if (clicked_idx >= 0 && (
size_t)clicked_idx < rld->
nb_items) {
11190 float gfh = gf ? (float)al_get_font_line_height(gf) : 16.0f;
11192 float header_h = row_h;
11193 if (my >= ay + header_h) {
11194 int clicked = gdc->
scroll_offset + (int)((my - (ay + header_h)) / row_h);
11195 if (clicked >= 0 && (
size_t)clicked < gdc->
nb_rows) {
11243 int nx = 0, ny = 0;
11244 int have_target = 0;
11246 int cx = 0, cy = 0;
11247 if (al_get_mouse_cursor_position(&cx, &cy)) {
11253 if (!have_target) {
11257 int dx = (int)(mx - win->
drag_ox);
11258 int dy = (int)(my - win->
drag_oy);
11259 if (dx != 0 || dy != 0) {
11260 int wx = 0, wy = 0;
11261 al_get_window_position(win->
native, &wx, &wy);
11270 al_set_window_position(win->
native, nx, ny);
11280 win->
state &= ~N_GUI_WIN_DRAGGING;
11286 int wx = 0, wy = 0;
11287 al_get_window_position(win->
native, &wx, &wy);
11298 float new_w = (mx - win->
x) + win->
drag_ox;
11299 float new_h = (my - win->
y) + win->
drag_oy;
11300 if (new_w < win->min_w) new_w = win->
min_w;
11301 if (new_h < win->min_h) new_h = win->
min_h;
11306 int nw = (int)(new_w + 0.5f);
11307 int nh = (int)(new_h + 0.5f);
11308 if (nw != (
int)(win->
w + 0.5f) || nh != (
int)(win->
h + 0.5f)) {
11309 al_resize_display(win->
native, nw, nh);
11322 win->
state &= ~N_GUI_WIN_RESIZING;
11333 int need_vscroll = 0, need_hscroll = 0;
11335 if (win->
content_h > body_h) need_vscroll = 1;
11336 if (win->
content_w > win->
w) need_hscroll = 1;
11337 if (need_vscroll && win->
content_w > (win->
w - scrollbar_size)) need_hscroll = 1;
11338 if (need_hscroll && win->
content_h > (body_h - scrollbar_size)) need_vscroll = 1;
11339 float content_area_w = win->
w - (need_vscroll ? scrollbar_size : 0);
11340 float content_area_h = body_h - (need_hscroll ? scrollbar_size : 0);
11343 float sb_y = body_y;
11344 float sb_h = content_area_h;
11349 float sb_x = win->
x;
11350 float sb_w = content_area_w;
11360 if (just_pressed) {
11363 if (fw) fw->
state &= ~N_GUI_STATE_FOCUSED;
11370 if (ctx->
mouse_b1 && event.type == ALLEGRO_EVENT_MOUSE_AXES) {
11376 float content_x = win->
x - win->
scroll_x;
11380 if (!wgt)
continue;
11392 if (yf && drag_yd->
text) {
11393 float yax = content_x + wgt->
x;
11394 float yay = content_y + wgt->
y;
11404 float lax = content_x + wgt->
x;
11405 float lay = content_y + wgt->
y;
11409 float effective_w = wgt->
w;
11416 float mfw = lww - wgt->
x;
11417 if (mfw > effective_w) effective_w = mfw;
11419 float max_text_w = effective_w - lpad * 2;
11421 float view_h = wgt->
h - lpad;
11423 float tw2 = max_text_w - sb_sz;
11425 lax + lpad, lay + lpad / 2.0f, drag_lb->
scroll_y, mx, my);
11433 float click_x = mx - text_ox;
11436 if (char_pos >= 0) {
11445 if (tf && drag_td) {
11446 float ta_ax = content_x + wgt->
x;
11447 float ta_ay = content_y + wgt->
y;
11450 ta_ax, ta_ay, wgt->
w, wgt->
h,
11463 if (just_released) {
11471 int pending_click_id = -1;
11478 if (!wgt)
continue;
11482 float content_x = win->
x - win->
scroll_x;
11484 float ax = content_x + wgt->
x;
11485 float ay = content_y + wgt->
y;
11492 if (bd->
on_click && !pending_click) {
11493 pending_click = bd;
11494 pending_click_id = wgt->
id;
11508 wgt->
state &= ~N_GUI_STATE_ACTIVE;
11512 if (pending_click && pending_click->
on_click)
11525 if (!event_consumed && event.type == ALLEGRO_EVENT_KEY_CHAR &&
11527 int kc =
event.keyboard.keycode;
11533 if (kc == ALLEGRO_KEY_UP) {
11535 event_consumed = 1;
11536 }
else if (kc == ALLEGRO_KEY_DOWN) {
11538 event_consumed = 1;
11539 }
else if (kc == ALLEGRO_KEY_HOME) {
11541 event_consumed = 1;
11542 }
else if (kc == ALLEGRO_KEY_END) {
11544 event_consumed = 1;
11545 }
else if (kc == ALLEGRO_KEY_ENTER || kc == ALLEGRO_KEY_PAD_ENTER) {
11552 event_consumed = 1;
11553 }
else if (kc == ALLEGRO_KEY_ESCAPE) {
11556 event_consumed = 1;
11565 if (kc == ALLEGRO_KEY_UP) {
11567 event_consumed = 1;
11568 }
else if (kc == ALLEGRO_KEY_DOWN) {
11570 event_consumed = 1;
11571 }
else if (kc == ALLEGRO_KEY_HOME) {
11573 event_consumed = 1;
11574 }
else if (kc == ALLEGRO_KEY_END) {
11576 event_consumed = 1;
11577 }
else if (kc == ALLEGRO_KEY_ENTER || kc == ALLEGRO_KEY_PAD_ENTER) {
11584 event_consumed = 1;
11585 }
else if (kc == ALLEGRO_KEY_ESCAPE) {
11588 event_consumed = 1;
11594 if (!event_consumed && event.type == ALLEGRO_EVENT_KEY_CHAR && event.keyboard.keycode == ALLEGRO_KEY_TAB) {
11595 int ctrl = (
event.keyboard.modifiers & ALLEGRO_KEYMOD_CTRL) ? 1 : 0;
11596 int shift = (
event.keyboard.modifiers & ALLEGRO_KEYMOD_SHIFT) ? 1 : 0;
11599 int is_ctrl_tab_in_textarea = 0;
11603 is_ctrl_tab_in_textarea = 1;
11606 if (!is_ctrl_tab_in_textarea) {
11627 int focusable_ids[512];
11628 int nfocusable = 0;
11632 focusable_ids[nfocusable++] = w->
id;
11635 if (nfocusable > 0) {
11638 for (
int i = 0; i < nfocusable; i++) {
11646 next_idx = (cur_idx <= 0) ? nfocusable - 1 : cur_idx - 1;
11648 next_idx = (cur_idx < 0 || cur_idx >= nfocusable - 1) ? 0 : cur_idx + 1;
11653 event_consumed = 1;
11658 if (!event_consumed && event.type == ALLEGRO_EVENT_KEY_CHAR && ctx->
focused_widget_id != -1) {
11665 event_consumed = 1;
11667 if (event.keyboard.modifiers & ALLEGRO_KEYMOD_SHIFT)
11674 if (!event_consumed && event.type == ALLEGRO_EVENT_KEY_CHAR && ctx->
focused_widget_id >= 0) {
11677 int kc =
event.keyboard.keycode;
11683 if (step <= 0) step = 1.0;
11684 double new_val = sd->
value;
11688 if (kc == ALLEGRO_KEY_RIGHT) {
11691 }
else if (kc == ALLEGRO_KEY_LEFT) {
11696 if (kc == ALLEGRO_KEY_UP) {
11699 }
else if (kc == ALLEGRO_KEY_DOWN) {
11704 if (kc == ALLEGRO_KEY_HOME) {
11707 }
else if (kc == ALLEGRO_KEY_END) {
11713 if (sd->
step > 0.0)
11717 if (new_val != sd->
value) {
11718 sd->
value = new_val;
11721 event_consumed = 1;
11733 for (
size_t i = 0; i < ld->
nb_items; i++) {
11740 int new_sel = cur_sel;
11741 if (kc == ALLEGRO_KEY_UP && cur_sel > 0) {
11742 new_sel = cur_sel - 1;
11744 }
else if (kc == ALLEGRO_KEY_DOWN && cur_sel < (
int)ld->
nb_items - 1) {
11745 new_sel = cur_sel + 1;
11747 }
else if (kc == ALLEGRO_KEY_DOWN && cur_sel < 0) {
11750 }
else if (kc == ALLEGRO_KEY_HOME) {
11753 }
else if (kc == ALLEGRO_KEY_END) {
11764 float lfh = lf ? (float)al_get_font_line_height(lf) : 16.0f;
11766 int visible = (int)(fw->
h / lih);
11767 if (new_sel < ld->scroll_offset) ld->
scroll_offset = new_sel;
11769 event_consumed = 1;
11779 int new_sel = cur_sel;
11781 if (kc == ALLEGRO_KEY_UP && cur_sel > 0) {
11782 new_sel = cur_sel - 1;
11784 }
else if (kc == ALLEGRO_KEY_DOWN && cur_sel < (
int)rd->
nb_items - 1) {
11785 new_sel = cur_sel + 1;
11787 }
else if (kc == ALLEGRO_KEY_DOWN && cur_sel < 0) {
11790 }
else if (kc == ALLEGRO_KEY_HOME) {
11793 }
else if (kc == ALLEGRO_KEY_END) {
11798 if (handled && new_sel != cur_sel) {
11803 float rfh = rf ? (float)al_get_font_line_height(rf) : 16.0f;
11805 int visible = (int)(fw->
h / rih);
11806 if (new_sel < rd->scroll_offset) rd->
scroll_offset = new_sel;
11808 event_consumed = 1;
11818 int new_sel = cur_sel;
11820 if (kc == ALLEGRO_KEY_UP && cur_sel > 0) {
11821 new_sel = cur_sel - 1;
11823 }
else if (kc == ALLEGRO_KEY_DOWN && cur_sel < (
int)cd->
nb_items - 1) {
11824 new_sel = cur_sel + 1;
11826 }
else if (kc == ALLEGRO_KEY_DOWN && cur_sel < 0) {
11829 }
else if (kc == ALLEGRO_KEY_HOME) {
11832 }
else if (kc == ALLEGRO_KEY_END) {
11837 if (handled && new_sel != cur_sel) {
11840 event_consumed = 1;
11849 if (max_scroll > 0) {
11850 double step = max_scroll / 20.0;
11851 if (step <= 0) step = 1.0;
11855 if (kc == ALLEGRO_KEY_UP) {
11858 }
else if (kc == ALLEGRO_KEY_DOWN) {
11863 if (kc == ALLEGRO_KEY_LEFT) {
11866 }
else if (kc == ALLEGRO_KEY_RIGHT) {
11871 if (kc == ALLEGRO_KEY_HOME) {
11874 }
else if (kc == ALLEGRO_KEY_END) {
11875 new_pos = max_scroll;
11880 if (new_pos < 0) new_pos = 0;
11881 if (new_pos > max_scroll) new_pos = max_scroll;
11886 event_consumed = 1;
11893 if (kc == ALLEGRO_KEY_SPACE || kc == ALLEGRO_KEY_ENTER) {
11897 event_consumed = 1;
11904 if (!event_consumed && event.type == ALLEGRO_EVENT_KEY_DOWN &&
11905 (event.keyboard.modifiers & ALLEGRO_KEYMOD_CTRL) &&
11914 size_t tlen = strlen(lb->
text);
11915 if ((
size_t)slo > tlen) slo = (int)tlen;
11916 if ((
size_t)shi > tlen) shi = (
int)tlen;
11917 int len = shi - slo;
11920 memcpy(clip, &lb->
text[slo], (
size_t)len);
11923 event_consumed = 1;
11930 if (!event_consumed && event.type == ALLEGRO_EVENT_KEY_DOWN &&
11931 (event.keyboard.modifiers & ALLEGRO_KEYMOD_CTRL) &&
11933 (event.keyboard.keycode == ALLEGRO_KEY_C || event.keyboard.keycode == ALLEGRO_KEY_A)) {
11934 if (event.keyboard.keycode == ALLEGRO_KEY_A) {
11937 event_consumed = 1;
11943 event_consumed = 1;
11956 if (event.type == ALLEGRO_EVENT_KEY_DOWN && !event_consumed) {
11957 int kc =
event.keyboard.keycode;
11961 for (
LIST_NODE* wnode = ctx->
windows->
end; wnode && !event_consumed; wnode = wnode->prev) {
11982 if (!focus_match) {
11990 if (!focus_match) {
12003 event_consumed = 1;
12006 if (event_consumed) {
12017 if (!event_consumed) {
12018 int widget_focused = 0;
12025 if (ftd && (ftd->
multiline || kc != ALLEGRO_KEY_ENTER)) {
12026 widget_focused = 1;
12029 widget_focused = 1;
12033 if (!widget_focused) {
12036 for (
LIST_NODE* wnode = ctx->
windows->
end; wnode && !event_consumed; wnode = wnode->prev) {
12064 event_consumed = 1;
12068 if (event_consumed) {
12081 if (event.type == ALLEGRO_EVENT_MOUSE_AXES && event.mouse.dz != 0) {
12082 int scroll_consumed = 0;
12088 if (cb_wgt && cb_wgt->
data) {
12094 scroll_consumed = 1;
12101 if (dm_wgt && dm_wgt->
data) {
12106 -event.mouse.dz, -1);
12107 scroll_consumed = 1;
12111 if (scroll_consumed)
return 1;
12119 float win_h = win->
h;
12122 float content_x = win->
x;
12123 float content_y = win->
y +
_win_tbh(win);
12129 float ax = content_x + wgt->
x - win->
scroll_x;
12130 float ay = content_y + wgt->
y - win->
scroll_y;
12138 float lfh = lf ? (float)al_get_font_line_height(lf) : 16.0f;
12140 int visible_count = (int)(wgt->
h / lih);
12141 int max_off = (int)ld->
nb_items - visible_count;
12142 if (max_off < 0) max_off = 0;
12144 scroll_consumed = 1;
12149 float hfh = hf ? (float)al_get_font_line_height(hf) : 16.0f;
12150 float row_h = hfh + 2.0f;
12152 int nb_rows = (int)((hd->
len + (
size_t)bpr - 1) / (size_t)bpr);
12155 if (visible_count < 1) visible_count = 1;
12156 max_off = nb_rows - visible_count;
12157 if (max_off < 0) max_off = 0;
12161 scroll_consumed = 1;
12166 float yfh = yf ? (float)al_get_font_line_height(yf) : 16.0f;
12167 float row_h = yfh + 2.0f;
12171 if (visible_count < 1) visible_count = 1;
12172 max_off = nb_lines - visible_count;
12173 if (max_off < 0) max_off = 0;
12177 scroll_consumed = 1;
12182 float gfh = gf ? (float)al_get_font_line_height(gf) : 16.0f;
12184 float data_h = wgt->
h - row_h;
12185 int visible_count = (int)(data_h / row_h);
12187 if (visible_count < 1) visible_count = 1;
12188 max_off = (int)gd->
nb_rows - visible_count;
12189 if (max_off < 0) max_off = 0;
12192 if (al_is_keyboard_installed()) {
12193 ALLEGRO_KEYBOARD_STATE kb;
12194 al_get_keyboard_state(&kb);
12195 dg_shift = al_key_down(&kb, ALLEGRO_KEY_LSHIFT) || al_key_down(&kb, ALLEGRO_KEY_RSHIFT);
12198 gd->
h_scroll -= (float)event.mouse.dz * (row_h * 2.0f);
12206 scroll_consumed = 1;
12213 float rfh = rf ? (float)al_get_font_line_height(rf) : 16.0f;
12215 int visible_count = (int)(wgt->
h / rih);
12216 int max_off = (int)rd->
nb_items - visible_count;
12217 if (max_off < 0) max_off = 0;
12219 scroll_consumed = 1;
12225 std->
scroll_y -= (int)((
float)
event.mouse.dz * scroll_step);
12228 scroll_consumed = 1;
12234 if (step <= 0) step = 1.0;
12235 double new_val = sd->
value + (double)event.mouse.dz * step;
12236 if (sd->
step > 0.0)
12240 if (new_val != sd->
value) {
12241 sd->
value = new_val;
12246 scroll_consumed = 1;
12251 if (max_scroll > 0) {
12252 double step = max_scroll / 20.0;
12253 if (step <= 0) step = 1.0;
12254 sbd->
scroll_pos -= (double)event.mouse.dz * step;
12260 scroll_consumed = 1;
12269 int max_off = (int)cbd->
nb_items - max_vis;
12270 if (max_off < 0) max_off = 0;
12272 scroll_consumed = 1;
12281 int max_off = (int)dmd->
nb_entries - max_vis;
12282 if (max_off < 0) max_off = 0;
12284 scroll_consumed = 1;
12291 sld->
scroll_y -= (float)event.mouse.dz * scroll_step;
12293 scroll_consumed = 1;
12301 if (scroll_consumed)
break;
12307 win->
scroll_y -= (float)event.mouse.dz * scroll_step;
12309 scroll_consumed = 1;
12311 if (scroll_consumed) event_consumed = 1;
12317 if (!scroll_consumed && eff_w > 0 && eff_h > 0) {
12323 event_consumed = 1;
12328 return event_consumed;
12339 float mx = (float)ctx->
mouse_x;
12340 float my = (float)ctx->
mouse_y;
12352 if (win->
native)
continue;
12374 int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
12377 FILE* f = fdopen(fd,
mode);
12383#define _gui_fopen_write(path, mode) fopen((path), (mode))
12388 unsigned char r, g, b, a;
12389 al_unmap_rgba(c, &r, &g, &b, &a);
12390 cJSON* arr = cJSON_CreateArray();
12391 cJSON_AddItemToArray(arr, cJSON_CreateNumber(r));
12392 cJSON_AddItemToArray(arr, cJSON_CreateNumber(g));
12393 cJSON_AddItemToArray(arr, cJSON_CreateNumber(b));
12394 cJSON_AddItemToArray(arr, cJSON_CreateNumber(a));
12395 cJSON_AddItemToObject(parent, name, arr);
12399static ALLEGRO_COLOR
_json_get_color(cJSON* parent,
const char* name, ALLEGRO_COLOR fallback) {
12400 cJSON* arr = cJSON_GetObjectItemCaseSensitive(parent, name);
12401 if (!arr || !cJSON_IsArray(arr) || cJSON_GetArraySize(arr) < 4)
return fallback;
12402 int r = (int)cJSON_GetArrayItem(arr, 0)->valuedouble;
12403 int g = (int)cJSON_GetArrayItem(arr, 1)->valuedouble;
12404 int b = (int)cJSON_GetArrayItem(arr, 2)->valuedouble;
12405 int a = (int)cJSON_GetArrayItem(arr, 3)->valuedouble;
12406 return al_map_rgba((
unsigned char)r, (
unsigned char)g, (
unsigned char)b, (
unsigned char)a);
12411 cJSON* item = cJSON_GetObjectItemCaseSensitive(parent, name);
12412 if (!item || !cJSON_IsNumber(item))
return fallback;
12413 return (
float)item->valuedouble;
12418 cJSON* item = cJSON_GetObjectItemCaseSensitive(parent, name);
12419 if (!item || !cJSON_IsNumber(item))
return fallback;
12420 return (
int)item->valuedouble;
12433 cJSON* root = cJSON_CreateObject();
12434 if (!root)
return -1;
12437 cJSON* theme = cJSON_CreateObject();
12450 cJSON_AddNumberToObject(theme,
"corner_rx", t->
corner_rx);
12451 cJSON_AddNumberToObject(theme,
"corner_ry", t->
corner_ry);
12452 cJSON_AddItemToObject(root,
"theme", theme);
12455 cJSON* sty = cJSON_CreateObject();
12457 cJSON_AddNumberToObject(sty,
"titlebar_h", s->
titlebar_h);
12458 cJSON_AddNumberToObject(sty,
"min_win_w", s->
min_win_w);
12459 cJSON_AddNumberToObject(sty,
"min_win_h", s->
min_win_h);
12460 cJSON_AddNumberToObject(sty,
"title_padding", s->
title_padding);
12463 cJSON_AddNumberToObject(sty,
"tb_btn_size", s->
tb_btn_size);
12464 cJSON_AddNumberToObject(sty,
"tb_btn_spacing", s->
tb_btn_spacing);
12468 cJSON_AddNumberToObject(sty,
"scrollbar_size", s->
scrollbar_size);
12484 cJSON_AddNumberToObject(sty,
"grip_size", s->
grip_size);
12515 cJSON_AddNumberToObject(sty,
"shape_mode", s->
shape_mode);
12526 cJSON_AddNumberToObject(sty,
"label_padding", s->
label_padding);
12531 cJSON_AddNumberToObject(sty,
"scroll_step", s->
scroll_step);
12534 cJSON_AddItemToObject(root,
"style", sty);
12537 char* json_str = cJSON_Print(root);
12538 cJSON_Delete(root);
12539 if (!json_str)
return -1;
12543 cJSON_free(json_str);
12546 fprintf(fp,
"%s\n", json_str);
12548 cJSON_free(json_str);
12562 FILE* fp = fopen(filepath,
"r");
12563 if (!fp)
return -1;
12565 fseek(fp, 0, SEEK_END);
12566 long fsize = ftell(fp);
12567 fseek(fp, 0, SEEK_SET);
12568 if (fsize <= 0 || fsize > 1024 * 1024) {
12574 Malloc(buf,
char, (
size_t)fsize + 1);
12579 size_t nread = fread(buf, 1, (
size_t)fsize, fp);
12583 cJSON* root = cJSON_Parse(buf);
12585 if (!root)
return -1;
12588 cJSON* theme = cJSON_GetObjectItemCaseSensitive(root,
"theme");
12611 if (wgt) wgt->
theme = *t;
12617 cJSON* sty = cJSON_GetObjectItemCaseSensitive(root,
"style");
12699 cJSON_Delete(root);
12704#define _N_GUI_WIN_STATE_PERSIST_MASK (N_GUI_WIN_OPEN | N_GUI_WIN_MINIMISED | N_GUI_WIN_MAXIMISED)
12716 cJSON* root = cJSON_CreateObject();
12717 if (!root)
return -1;
12719 cJSON_AddNumberToObject(root,
"version", 1);
12725 cJSON_AddNumberToObject(root,
"display_w", ctx->
display_w);
12726 cJSON_AddNumberToObject(root,
"display_h", ctx->
display_h);
12727 cJSON* wins = cJSON_CreateArray();
12729 cJSON_Delete(root);
12735 if (!win)
continue;
12750 cJSON* wj = cJSON_CreateObject();
12756 int detached = (win->
native != NULL);
12757 float px = detached ? win->
saved_x : win->
x;
12758 float py = detached ? win->
saved_y : win->
y;
12759 float pw = detached ? win->
saved_w : win->
w;
12760 float ph = detached ? win->
saved_h : win->
h;
12767 al_get_window_position(win->
native, &npx, &npy);
12768 nw = (float)al_get_display_width(win->
native);
12769 nh = (float)al_get_display_height(win->
native);
12771 cJSON_AddStringToObject(wj,
"title", win->
title);
12772 cJSON_AddNumberToObject(wj,
"x", px);
12773 cJSON_AddNumberToObject(wj,
"y", py);
12774 cJSON_AddNumberToObject(wj,
"w", pw);
12775 cJSON_AddNumberToObject(wj,
"h", ph);
12777 cJSON_AddNumberToObject(wj,
"flags", pflags);
12779 cJSON_AddNumberToObject(wj,
"native", 1);
12780 cJSON_AddNumberToObject(wj,
"detach_flags", win->
detach_flags);
12781 if (nw > 0.0f && nh > 0.0f) {
12782 cJSON_AddNumberToObject(wj,
"native_w", nw);
12783 cJSON_AddNumberToObject(wj,
"native_h", nh);
12785 if (npx != INT_MIN && npy != INT_MIN) {
12786 cJSON_AddNumberToObject(wj,
"native_pos_x", npx);
12787 cJSON_AddNumberToObject(wj,
"native_pos_y", npy);
12790 cJSON_AddNumberToObject(wj,
"z_order", win->
z_order);
12791 cJSON_AddNumberToObject(wj,
"z_value", win->
z_value);
12792 cJSON_AddNumberToObject(wj,
"norm_x", win->
norm_x);
12793 cJSON_AddNumberToObject(wj,
"norm_y", win->
norm_y);
12794 cJSON_AddNumberToObject(wj,
"norm_w", win->
norm_w);
12795 cJSON_AddNumberToObject(wj,
"norm_h", win->
norm_h);
12796 cJSON_AddNumberToObject(wj,
"autofit_flags", win->
autofit_flags);
12797 cJSON_AddNumberToObject(wj,
"autofit_border", win->
autofit_border);
12798 cJSON_AddNumberToObject(wj,
"resize_policy", win->
resize_policy);
12803 cJSON* warr = NULL;
12811 if (!warr && !(warr = cJSON_CreateArray()))
12813 w2 = cJSON_CreateObject();
12816 cJSON_AddStringToObject(w2,
"key", wgt->
persist_key);
12818 cJSON_AddStringToObject(w2,
"kind",
"splitpane");
12828 cJSON_AddStringToObject(w2,
"kind",
"datagrid");
12829 cJSON_AddNumberToObject(w2,
"ncols", nc);
12830 jo = cJSON_AddArrayToObject(w2,
"order");
12831 jv = cJSON_AddArrayToObject(w2,
"visible");
12832 jw = cJSON_AddArrayToObject(w2,
"width");
12833 for (c = 0; c < nc; c++) {
12835 if (jo) cJSON_AddItemToArray(jo, cJSON_CreateNumber(phys >= 0 ? phys : c));
12840 cJSON_AddItemToArray(warr, w2);
12843 cJSON_AddItemToObject(wj,
"widgets", warr);
12845 cJSON_AddItemToArray(wins, wj);
12847 cJSON_AddItemToObject(root,
"windows", wins);
12849 char* json_str = cJSON_Print(root);
12850 cJSON_Delete(root);
12851 if (!json_str)
return -1;
12855 cJSON_free(json_str);
12858 fprintf(fp,
"%s\n", json_str);
12860 cJSON_free(json_str);
12874 FILE* fp = fopen(filepath,
"r");
12876 n_log(
LOG_DEBUG,
"n_gui_load_layout_json: %s not found (first run?)", filepath);
12880 fseek(fp, 0, SEEK_END);
12881 long fsize = ftell(fp);
12882 fseek(fp, 0, SEEK_SET);
12883 if (fsize <= 0 || fsize > 4 * 1024 * 1024) {
12889 Malloc(buf,
char, (
size_t)fsize + 1);
12894 size_t nread = fread(buf, 1, (
size_t)fsize, fp);
12898 cJSON* root = cJSON_Parse(buf);
12900 if (!root)
return -1;
12902 cJSON* wins = cJSON_GetObjectItemCaseSensitive(root,
"windows");
12903 if (!wins || !cJSON_IsArray(wins)) {
12904 cJSON_Delete(root);
12915 float sx = 1.0f, sy = 1.0f;
12921 int n_entries = cJSON_GetArraySize(wins);
12922 int* consumed = NULL;
12923 if (n_entries > 0) {
12924 Malloc(consumed,
int, (
size_t)n_entries);
12926 cJSON_Delete(root);
12929 memset(consumed, 0,
sizeof(
int) * (
size_t)n_entries);
12944 for (
int i = 0; i < n_entries; i++) {
12945 if (consumed[i])
continue;
12946 cJSON* wi = cJSON_GetArrayItem(wins, i);
12948 cJSON* state_i = cJSON_GetObjectItemCaseSensitive(wi,
"state");
12949 int is_open_i = state_i && cJSON_IsNumber(state_i) &&
12951 if (is_open_i)
continue;
12952 cJSON* ti = cJSON_GetObjectItemCaseSensitive(wi,
"title");
12953 if (!ti || !cJSON_IsString(ti) || !ti->valuestring)
continue;
12954 for (
int j = i + 1; j < n_entries; j++) {
12955 cJSON* wj = cJSON_GetArrayItem(wins, j);
12957 cJSON* state_j = cJSON_GetObjectItemCaseSensitive(wj,
"state");
12958 int is_open_j = state_j && cJSON_IsNumber(state_j) &&
12960 if (!is_open_j)
continue;
12961 cJSON* tj = cJSON_GetObjectItemCaseSensitive(wj,
"title");
12962 if (tj && cJSON_IsString(tj) && tj->valuestring &&
12963 strcmp(ti->valuestring, tj->valuestring) == 0) {
12972 if (!win)
continue;
12973 cJSON* match = NULL;
12974 int match_idx = -1;
12977 cJSON_ArrayForEach(wj, wins) {
12978 if (!consumed || consumed[idx] == 0) {
12979 cJSON* t = cJSON_GetObjectItemCaseSensitive(wj,
"title");
12980 if (t && cJSON_IsString(t) && t->valuestring &&
12989 if (!match)
continue;
12990 if (consumed) consumed[match_idx] = 1;
13014 if (win->
x < 0.0f || win->
x > ctx->
display_w) win->
x = 0.0f;
13015 if (win->
w < 20.0f) win->
w = 20.0f;
13019 if (win->
y < 0.0f || win->
y > ctx->
display_h) win->
y = 0.0f;
13020 if (win->
h < 20.0f) win->
h = 20.0f;
13026 win->
state = (win->
state & ~_N_GUI_WIN_STATE_PERSIST_MASK) |
13072 if (n_entries > 0) {
13074 for (
int i = 0; i < n_entries; i++)
13075 if (consumed && !consumed[i]) npend++;
13080 for (
int i = 0; i < n_entries && k < npend; i++) {
13081 if (consumed && consumed[i])
continue;
13082 cJSON* wi = cJSON_GetArrayItem(wins, i);
13083 cJSON* t = wi ? cJSON_GetObjectItemCaseSensitive(wi,
"title") : NULL;
13084 if (!t || !cJSON_IsString(t) || !t->valuestring || !t->valuestring[0])
13095 if (live)
continue;
13121 cJSON_ArrayForEach(wi, wins) {
13122 cJSON* warr = cJSON_GetObjectItemCaseSensitive(wi,
"widgets");
13123 if (warr && cJSON_IsArray(warr))
13124 nw += cJSON_GetArraySize(warr);
13131 cJSON_ArrayForEach(wi2, wins) {
13132 cJSON* t = cJSON_GetObjectItemCaseSensitive(wi2,
"title");
13133 cJSON* warr = cJSON_GetObjectItemCaseSensitive(wi2,
"widgets");
13135 const char* title = (t && cJSON_IsString(t) && t->valuestring) ? t->valuestring :
"";
13136 if (!warr || !cJSON_IsArray(warr) || !title[0])
13138 cJSON_ArrayForEach(we, warr) {
13139 cJSON* jk = cJSON_GetObjectItemCaseSensitive(we,
"key");
13140 cJSON* jkind = cJSON_GetObjectItemCaseSensitive(we,
"kind");
13145 if (!jk || !cJSON_IsString(jk) || !jk->valuestring || !jk->valuestring[0])
13147 if (!jkind || !cJSON_IsString(jkind) || !jkind->valuestring)
13149 kind = jkind->valuestring;
13151 memset(p, 0,
sizeof(*p));
13154 if (strcmp(kind,
"splitpane") == 0) {
13157 }
else if (strcmp(kind,
"datagrid") == 0) {
13158 cJSON* jo = cJSON_GetObjectItemCaseSensitive(we,
"order");
13159 cJSON* jv = cJSON_GetObjectItemCaseSensitive(we,
"visible");
13160 cJSON* jw = cJSON_GetObjectItemCaseSensitive(we,
"width");
13164 if (nc < 0) nc = 0;
13167 for (c = 0; c < nc; c++) {
13168 const cJSON* eo = (jo && cJSON_IsArray(jo)) ? cJSON_GetArrayItem(jo, c) : NULL;
13169 const cJSON* ev = (jv && cJSON_IsArray(jv)) ? cJSON_GetArrayItem(jv, c) : NULL;
13170 const cJSON* ew = (jw && cJSON_IsArray(jw)) ? cJSON_GetArrayItem(jw, c) : NULL;
13171 p->
order[c] = eo ? (int)eo->valuedouble : c;
13172 p->
visible[c] = (ev && ((int)ev->valuedouble)) ? 1 : (ev ? 0 : 1);
13173 p->
width[c] = ew ? (float)ew->valuedouble : 0.0f;
13187 cJSON_Delete(root);
13202 n_log(
LOG_ERR,
"n_gui_save_theme_json: cJSON not available (compile with -DHAVE_CJSON)");
13215 n_log(
LOG_ERR,
"n_gui_load_theme_json: cJSON not available (compile with -DHAVE_CJSON)");
13228 n_log(
LOG_ERR,
"n_gui_save_layout_json: cJSON not available (compile with -DHAVE_CJSON)");
13241 n_log(
LOG_ERR,
"n_gui_load_layout_json: cJSON not available (compile with -DHAVE_CJSON)");
13249 if (!panel)
return;
13251 for (
int i = 0; i < panel->
nb_tabs; i++) {
13257 if (clicked < 0)
return;
13263 if (!ctx)
return NULL;
13266 if (!panel)
return NULL;
13287 float bx = panel->
x + (float)idx * panel->
button_w;
13292 if (btn_id < 0)
return -1;
13300 if (!panel || tab_index < 0 || tab_index >= panel->
nb_tabs)
return;
13305 if (!panel || index < 0 || index >= panel->
nb_tabs)
return;
13306 for (
int i = 0; i < panel->
nb_tabs; i++) {
13323 if (!panel || !*panel)
return;
13333 if (!tree || !selected)
return;
13334 if (index < 0 || index >= tree->
nb_visible)
return;
13336 if (node_idx < 0 || node_idx >= tree->
nb_nodes)
return;
13342 if (!ctx)
return NULL;
13345 if (!tree)
return NULL;
13382 if (parent_index >= tree->
nb_nodes)
return -1;
13385 snprintf(node->
label,
sizeof(node->
label),
"%s", label);
13390 if (parent_index < 0) {
13410 if (node_index < 0 || node_index >= tree->
nb_nodes)
return;
13416 memset(removed, 0, (
size_t)tree->
nb_nodes);
13417 removed[node_index] = 1;
13421 for (
int i = 0; i < tree->
nb_nodes; i++) {
13422 if (removed[i])
continue;
13424 if (p >= 0 && removed[p]) {
13434 for (
int i = 0; i < tree->
nb_nodes; i++) {
13435 remap[i] = removed[i] ? -1 : new_count++;
13439 for (
int i = 0; i < tree->
nb_nodes; i++) {
13440 if (removed[i])
continue;
13441 int dst = remap[i];
13442 if (dst != i) tree->
nodes[dst] = tree->
nodes[i];
13451 for (
int i = 0; i < tree->
nb_nodes; i++) {
13454 for (
int i = 0; i < tree->
nb_nodes; i++) {
13463 if (!tree || !new_label)
return;
13464 if (node_index < 0 || node_index >= tree->
nb_nodes)
return;
13466 sizeof(tree->
nodes[node_index].
label),
"%s", new_label);
13471 if (!tree)
return -1;
13473 if (row < 0 || row >= tree->
nb_visible)
return -1;
13479 if (node_index < 0 || node_index >= tree->
nb_nodes)
return;
13490 for (
int row = 0; row < tree->
nb_visible; row++) {
13500 if (!tree || !ptr)
return -1;
13501 for (
int i = 0; i < tree->
nb_nodes; i++) {
13508 if (!tree || node_index < 0 || node_index >= tree->
nb_nodes)
return;
13526 for (
int i = 0; i < tree->
nb_nodes; i++) {
13531 int pad = node->
depth * 2;
13532 if (pad >= (
int)
sizeof(indent) - 1) pad = (int)
sizeof(indent) - 2;
13533 memset(indent,
' ', (
size_t)pad);
13534 indent[pad] =
'\0';
13547 if (saved_node >= 0) {
13548 for (
int row = 0; row < tree->
nb_visible; row++) {
13557 if (saved_scroll > 0) {
13563 if (!tree || !*tree)
return;
13571#define _N_GUI_TREE_DRAG_THRESHOLD_PX 4.0f
13597 float* out_item_area_w,
13600 int* out_scroll_off) {
13601 if (!tree)
return 0;
13605 if (!win)
return 0;
13609 *out_x = win->
x + w->
x;
13620 int visible_count = (int)(w->
h / *out_item_h);
13621 int need_scrollbar = ((int)ld->
nb_items > visible_count) ? 1 : 0;
13623 *out_item_area_w = w->
w - sb_w;
13633 float lx, ly, lw, lh, iw, inset, ih;
13636 &iw, &inset, &ih, &scroll))
13640 if (mx < lx || mx > lx + iw || my < ly || my > ly + lh)
return 0;
13642 int row_in_view = (int)((my - ly) / ih);
13643 int actual_row = row_in_view + scroll;
13644 if (actual_row < 0 || actual_row >= tree->
nb_visible)
return 0;
13647 if (node_idx < 0 || node_idx >= tree->
nb_nodes)
return 0;
13654 float y_in_row = (my - ly) - (
float)row_in_view * ih;
13656 if (y_in_row < ih * 0.4f)
13658 else if (y_in_row > ih * 0.6f)
13663 *out_node_idx = node_idx;
13664 *out_drop_pos = pos;
13669 if (!tree || !tree->
ctx)
return;
13677 float mx = (float)ctx->
mouse_x;
13678 float my = (float)ctx->
mouse_y;
13685 if (b1 && !b1_prev) {
13716 if (!b1 && b1_prev) {
13731 if (!tree || !tree->
ctx)
return;
13734 float lx, ly, lw, lh, iw, inset, ih;
13737 &iw, &inset, &ih, &scroll))
13743 int row_in_view = -1;
13744 for (
int row = 0; row < tree->
nb_visible; row++) {
13746 row_in_view = row - scroll;
13750 if (row_in_view < 0)
return;
13752 float row_y = ly + (float)row_in_view * ih;
13753 if (row_y < ly || row_y + ih > ly + lh) {
13761 float left = lx + inset;
13762 float right = lx + iw - inset;
13767 const float thickness = 2.0f;
13768 const float half = thickness * 0.5f;
13776 al_draw_rectangle(left + half, row_y + half,
13777 right - half, row_y + ih - half,
13778 colour, thickness);
13787 al_draw_line(left, line_y,
13789 colour, thickness);
13798 if (!table)
return;
13804 if (!table)
return;
13805 for (
int i = 0; i < table->
nb_rows; i++) {
13821 if (!table)
return;
13841 float pad_x = table->
padding * sx;
13842 float pad_y = table->
padding * sy;
13845 float gap = 6.0f * sx;
13847 float total_w = win->
w - pad_x * 2.0f;
13848 if (total_w < 0.0f) total_w = 0.0f;
13850 float rh_inner = row_h - 4.0f * sy;
13851 if (rh_inner < 1.0f) rh_inner = 1.0f;
13852 float rw_inner = table->
row_height * sx - 4.0f * sx;
13853 if (rw_inner < 1.0f) rw_inner = 1.0f;
13854 float lbl_h = 18.0f * sy;
13855 if (lbl_h < 1.0f) lbl_h = 1.0f;
13856 float chk_w = rw_inner;
13857 float rem_w = rw_inner;
13865 float trailing = (table->
show_enabled ? (chk_w + gap) : 0.0f) + gap + rem_w;
13867 if (text_cols == 3) {
13868 col_w = total_w * 0.27f;
13870 float avail = total_w - trailing;
13871 if (avail < 0.0f) avail = 0.0f;
13872 col_w = avail / (float)text_cols;
13874 if (col_w < 0.0f) col_w = 0.0f;
13930 float cy = top + hdr_h_outer;
13931 for (
int i = 0; i < table->
nb_rows; i++) {
13995 float btn_w = 30.0f * sx;
14005 if (!ctx)
return NULL;
14008 if (!table)
return NULL;
14009 memset(table, 0,
sizeof(*table));
14033 float rh_inner = row_height - 4.0f;
14034 if (rh_inner < 1.0f) rh_inner = 1.0f;
14035 float hdr_h_label = 18.0f;
14046 "+", padding, padding, 30.0f, rh_inner,
14056 const char* description,
14058 if (!table)
return -1;
14063 if (rh < 1.0f) rh = 1.0f;
14068 for (
int i = 0; i < table->
nb_rows; i++) {
14076 row = &table->
rows[idx];
14089 row = &table->
rows[idx];
14113 if (!table || row_index < 0 || row_index >= table->
nb_rows)
return;
14127 if (!table)
return;
14128 for (
int i = 0; i < table->
nb_rows; i++) {
14145 if (!table)
return;
14153 if (!table)
return;
14158 for (
int i = 0; i < table->
nb_rows; i++) {
14167 if (!table)
return;
14181 if (!table || !*table)
return;
14183 FreeNoLog((*table)->value_placeholder);
14200 snprintf(label,
sizeof(label),
"%s %s", s->
folded ?
"+" :
"-", s->
title);
14219N_GUI_SECTIONLIST*
n_gui_sectionlist_create(
N_GUI_CTX* ctx,
int window_id,
float x,
float y0,
float width,
float header_h,
float gap,
void (*on_toggle)(
int,
int,
void*),
void* user_data) {
14220 if (!ctx)
return NULL;
14223 if (!sl)
return NULL;
14224 memset(sl, 0,
sizeof(*sl));
14242 memset(s, 0,
sizeof(*s));
14243 strncpy(s->
title, title,
sizeof(s->
title) - 1);
14245 s->
folded = folded ? 1 : 0;
14249 snprintf(label,
sizeof(label),
"%s %s", s->
folded ?
"+" :
"-", s->
title);
14256 if (!sl || section_index < 0 || section_index >= sl->
nb_sections)
return;
14261 if (!w || !hdr)
return;
14265 float dy = w->
y - content_top0;
14269 float bottom = dy + w->
h;
14281 float cur = sl->
y0;
14289 hdr->
x = sl->
x + inset;
14291 hdr->
w = sl->
width - inset;
14312 if (!sl || section_index < 0 || section_index >= sl->
nb_sections)
return;
14318 if (!sl || section_index < 0 || section_index >= sl->
nb_sections)
return 0;
14323 if (!sl)
return 0.0f;
14324 float cur = sl->
y0;
14337 if (!sl || !*sl)
return;
ALLEGRO_DISPLAY * display
void on_link_click(int widget_id, const char *link, void *user_data)
void on_scroll(int widget_id, double pos, void *user_data)
#define FreeNoLog(__ptr)
Free Handler without log.
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
#define __n_assert(__ptr, __ret)
macro to assert things
#define Free(__ptr)
Free Handler to get errors.
char title[128]
column header title
char title[128]
window title
ALLEGRO_BITMAP * thumb_bitmap
optional bitmap for the thumb/handle, normal state (NULL = color theme)
float scroll_y
vertical scroll offset for overflowing text (pixels)
float scroll_y
vertical scroll offset for auto-scrollbar (pixels)
int visible
visibility flag
ALLEGRO_BITMAP * panel_bitmap
optional bitmap for the dropdown panel background (NULL = color theme)
int saved_flags
embedded feature flags saved by n_gui_window_detach (a detached window is forced frameless because th...
char * text
owned copy of the text, or NULL
size_t * col_order
display order: display_pos -> physical column index (sized cols_cap), or NULL when the display order ...
ALLEGRO_BITMAP * handle_hover_bitmap
optional bitmap for the handle on hover (NULL = fallback to handle_bitmap)
int window_id
owning window for coord math
float button_h
height of each tab button
int is_open
is dropdown currently open
int content_window_ids[16]
content window IDs (-1 = none)
int w
bounding box width in pixels
int native_drag_wx
native window x at the drag grab, the move is native_drag_wx plus the desktop cursor travel since the...
float gap
vertical gap between rows
int open_combobox_id
id of the combobox whose dropdown is currently open, or -1
ALLEGRO_COLOR scrollbar_track_color
scrollbar track colour
int folded
1 = collapsed (members hidden), 0 = expanded
int max_visible
max visible items in dropdown
int selected_index
currently selected index (-1 = none)
void(* on_remove)(int, void *)
callback on row removal
ALLEGRO_BITMAP * minimize_active_bitmap
optional bitmap for minimize button active state
int sort_col
column index used for sorting, or -1
int scroll_offset
first visible row
size_t items_capacity
allocated capacity
ALLEGRO_COLOR grip_color
grip line colour
float dropdown_border_thickness
dropdown panel border thickness
char * text
text content (dynamically allocated, text_alloc bytes)
int nb_rows
total rows (including removed)
float slider_handle_edge_offset
handle circle offset from edge
int bytes_per_row
bytes shown per row
int selected_row
selected data row (the primary / last-clicked row), or -1
float widget_dy[48]
each member's y offset from the section content top, captured at add time
int parent_index
parent node index, or -1 for root
int shape
shape type: N_GUI_SHAPE_RECT or N_GUI_SHAPE_ROUNDED
float x
saved x (already display-scaled)
float content_h
total content height computed from widgets (internal)
float global_scrollbar_thumb_padding
global thumb inset from track edge
char label[128]
menu label (shown on the button)
size_t items_capacity
allocated capacity
N_GUI_TREE_NODE nodes[2048]
node storage
float x
position x on screen
float scrollbar_size
scrollbar track width/height
float norm_y
normalized position y (0.0-1.0 fraction of reference display height)
void(* on_select)(int widget_id, int index, void *user_data)
callback on selection change (widget_id, selected_index, user_data)
float scrollbar_thumb_corner_r
thumb corner radius
void(* on_change)(int widget_id, float ratio, void *user_data)
callback fired while the divider is dragged (widget_id, ratio, user_data)
int nb_widgets
number of member widgets
int is_dynamic
is this entry dynamic (rebuilt via callback each time menu opens)
float title_padding
padding left of title text
float min_win_h
minimum window height (for resize)
float dropdown_arrow_half_w
horizontal half-extent of the arrow chevron
int toggled
toggle state: 0 = off/unclicked, 1 = on/clicked (only used when toggle_mode=1)
char ** cells
row-major cell strings (nb_rows * nb_cols owned char*)
int lbl_enabled
label widget ID for "On" header
ALLEGRO_BITMAP * item_bg_bitmap
optional bitmap for per-item background, normal state (NULL = color theme)
int scroll_offset
scroll offset in items
float ref_display_h
reference display height at the time normalized values were last captured
float slider_track_corner_r
track corner radius
int y
bounding box y offset from draw origin
float titlebar_h
title bar height
ALLEGRO_BITMAP * handle_active_bitmap
optional bitmap for the handle while dragging (NULL = fallback to handle_bitmap)
void(* on_tab_change)(int, void *)
callback on tab switch (may be NULL)
int selected_syntaxview_id
id of the syntax-view widget with the most recent text selection, or -1
float top_offset
unscaled y offset of the header row from the window top (default 0), to reserve space above the table...
float norm_y
normalized position y (fraction of parent window h, used for SCALE resize)
int dropmenu_max_visible
default max visible items for dropmenu panel
float norm_x
normalized position x (0.0-1.0 fraction of reference display width)
int sel_start
selection start byte offset into text, or -1 when nothing is selected
ALLEGRO_BITMAP * bg_bitmap
optional bitmap for the label background (NULL = no background)
float item_height
item height
N_GUI_THEME theme
color theme for this widget
float title_max_w_reserve
pixels reserved right of title for truncation
int multiselect
1 = multi-row selection enabled (Ctrl/Shift-click), 0 = single-select
double anim_until
deadline (al_get_time seconds) until which a transient animation is in progress (button key-press fla...
size_t rows_cap
allocated row capacity (in rows)
int want_native
1 when the window should live in a native OS window: set by n_gui_window_detach and by a loaded layou...
char text[128]
item display text
int nb_tabs
number of tabs
int key_sources[8]
widget IDs that can trigger this focused key binding.
float checkbox_label_gap
gap between box and label text
int open_dropmenu_id
id of the dropdown menu whose panel is currently open, or -1
float global_scrollbar_thumb_corner_r
global thumb corner radius
N_GUI_THEME default_theme
default theme (applied to new widgets/windows)
int flags
bitmask of N_GUI_DROPMENU_* flags
float saved_y
embedded y saved by n_gui_window_detach, restored by n_gui_window_attach
float dpi_scale
DPI scale factor (1.0 = normal, 1.25 = 125%, 2.0 = HiDPI, etc.)
void * user_data
user data for callback
int scroll_from_wheel
set to 1 when scroll was changed by mouse wheel, cleared on key input
ALLEGRO_COLOR tooltip_fg
tooltip text color
int btn_add
button widget ID for "+" add row
ALLEGRO_BITMAP * bg_bitmap
optional bitmap for the window body background (NULL = color fill)
float scrollbar_thumb_padding
thumb inset from track edge
ALLEGRO_COLOR text_normal
text normal
int remove_id
button widget ID for the remove action
int pressed
which button is currently pressed (N_GUI_TB_BTN_*)
void * on_maximize_user_data
user data for on_maximize callback
int drop_position
N_GUI_DROP_BEFORE / INTO / AFTER.
int combobox_max_visible
default max visible items for combobox dropdown
ALLEGRO_BITMAP * item_bg_bitmap
optional bitmap for per-item background, normal state (NULL = color theme)
float norm_h
normalized height (fraction of parent window h)
void * user_data
user data for callback
int sel_dragging
1 while a mouse drag is extending the selection, 0 otherwise
void(* on_open)(int widget_id, void *user_data)
callback to rebuild dynamic entries each time the menu is opened.
size_t cols_cap
allocated column capacity
int mouse_b1_prev
previous mouse button 1 state
int listbox_id
listbox widget ID
float corner_rx
corner radius for rounded shapes
ALLEGRO_COLOR selection_color
text selection highlight colour (semi-transparent recommended)
int drag_hover_node
current hover node, or -1
ALLEGRO_BITMAP * bitmap
optional bitmap for the button (NULL = color theme)
int flags
bitmask of N_GUI_COMBOBOX_* flags
float gui_offset_x
horizontal letterbox offset for virtual canvas
int h_scroll_dragging
1 while the user is dragging the horizontal scrollbar thumb (so the shared scrollbar-drag handler rou...
int pending_layout_count
number of valid entries in pending_layout
int state
saved minimised/maximised bits, applied on create
float tooltip_delay
inner padding
int key_focus_only
if 1, keycode fires only when the button itself or a source widget has focus.
int value_visible
draw the built-in value label next to/below the handle.
int ncols
column count (kind == DATAGRID)
N_GUI_KV_ROW rows[128]
row storage
char * tooltip
owned tooltip text shown after the pointer rests on the widget (NULL = none); heap-allocated with no ...
int type
widget type (N_GUI_TYPE_*)
int state
current state flags (N_GUI_STATE_*)
float scroll_step
pixels per mouse wheel notch for window auto-scroll
int multiline
0 = single line, 1 = multiline
int lines_valid
0 when cached_nb_lines / cached_headers_end are stale (rebuild on next use).
int key_id
textarea widget ID for the key
ALLEGRO_BITMAP * bitmap_hover
optional bitmap for hover state
int kind
N_GUI_TYPE_SPLITPANE or N_GUI_TYPE_DATAGRID.
int button_ids[16]
toggle button widget IDs
int max_visible
max visible items
float gui_bounds_w
total bounding box width of all windows (computed internally)
double key_press_until
absolute al_get_time() deadline until which the button is rendered in its pressed (N_GUI_STATE_ACTIVE...
float x
position x relative to parent window
float drag_press_x
mouse x at press time
float global_scrollbar_size
global scrollbar track width/height
int highlight_index
open-panel navigation cursor for the wheel and Up/Down keys (-1 = none).
void(* on_toggle)(int, int, void *)
callback(section_index, folded, user_data) on a header click (may be NULL)
float textarea_cursor_width
cursor width in pixels
char text[4096]
text to display
void * user_data
user data for callback
char title[128]
owning window title to match on
float tb_btn_size
titlebar button size (0 = auto: titlebar_h - 4)
float norm_h
normalized height (fraction of reference display height, used in SCALE mode)
char value_format[32]
printf-style format string applied to the numeric value when the built-in readout draws.
float min_win_w
minimum window width (for resize)
ALLEGRO_BITMAP * bg_bitmap
optional bitmap for the combobox background (NULL = color theme)
ALLEGRO_BITMAP * maximize_bitmap
optional bitmap for maximize button normal state (NULL = color theme)
void(* on_change)(int widget_id, double value, void *user_data)
callback on value change
float item_height
item height in pixels
int native_drag_wy
native window y at the drag grab (see native_drag_wx)
float drag_ox
drag offset x (internal)
void(* on_click)(int widget_id, void *user_data)
callback on click (widget_id passed)
float row_height
unscaled row height in pixels
int expanded
1 if expanded
N_GUI_LISTITEM * items
dynamic array of items
char label[128]
display text
int mode
highlighting mode: N_GUI_SYNTAX_*
int drag_armed_node
pressed-but-not-yet-dragging
ALLEGRO_BITMAP * close_hover_bitmap
optional bitmap for close button hover state
int show_enabled
1 to show the enabled-checkbox column (default 1)
N_GUI_THEME theme
color theme for this window chrome
int sel_end
selection end byte offset (tracks the cursor while a drag is in progress)
int native_close_pending
1 when the native window must be released at the next safe point (an ALLEGRO_EVENT_DISPLAY_CLOSE arri...
int sort_dir
sort direction: 1 ascending, -1 descending
float saved_w
embedded width saved by n_gui_window_detach, restored by n_gui_window_attach
char title[64]
section title (header label minus the fold glyph)
int desc_id
textarea widget ID for the description
int widget_ids[48]
member widget ids
float width
column width in pixels
int next_window_id
next window id to assign
float item_selection_inset
item highlight inset from left/right edges
int header_id
clickable header button widget id
float saved_h
embedded height saved by n_gui_window_detach, restored by n_gui_window_attach
ALLEGRO_COLOR border_normal
border normal
void(* on_click)(int widget_id, int entry_index, int tag, void *user_data)
callback when this entry is clicked (widget_id, entry_index, tag, user_data)
N_GUI_SECTION sections[16]
section storage
void(* on_content_draw)(int window_id, void *user_data)
optional callback invoked during n_gui_draw immediately after this window's own content is drawn,...
float init_win_w
parent window width at create time
int has_children
1 if node has children
N_GUI_THEME close_theme
theme for close button (defaults to red hover/active)
void * user_data
user data for callback
float value
progress fraction, clamped to 0.0 .
int scroll_offset
scroll offset
ALLEGRO_COLOR tooltip_bg
tooltip bubble background color
ALLEGRO_COLOR text_hover
text hover
float restore_x
saved x position before maximise (for restore)
float dropdown_arrow_half_h
vertical half-extent of the arrow chevron
int z_value
z-value for N_GUI_ZORDER_FIXED mode (lower = behind, higher = on top)
ALLEGRO_BITMAP * item_bg_bitmap
optional bitmap for per-item background, normal state (NULL = color theme)
int highlight_index
open-panel navigation cursor for the wheel and Up/Down keys (-1 = none).
double cursor_time
timestamp of last cursor activity (for blink reset)
size_t entries_capacity
allocated capacity
int mouse_y
mouse state tracking
float grip_line_thickness
grip line thickness
int window_id
window holding the headers and members
int lbl_key
label widget ID for "Key" header
char key[128]
widget persist key to match on
size_t sel_end
selection end position (tracks cursor during selection)
int resize_policy
per-window resize policy: N_GUI_WIN_RESIZE_NONE, _MOVE, or _SCALE
N_GUI_THEME default_tb_close_theme
default theme for titlebar close button
size_t nb_items
number of items
char persist_key[128]
optional stable key for persisting this widget's user-adjustable state (splitpane divider ratio,...
int native_drag_cx
desktop x of the mouse cursor when a native (N_GUI_DETACH_OWN_CHROME) title bar drag started.
void(* on_close)(int window_id, void *user_data)
callback on close button click (NULL = default: clear N_GUI_WIN_OPEN)
char title[128]
window title to match on
void * user_data
user data for callback
float first_inset
content-local left inset applied to the FIRST header only, so a button can sit before it on the same ...
int cached_nb_lines
cached line count (matches _text_line_count), valid when lines_valid
float padding
unscaled padding in pixels
unsigned char * data
owned copy of the bytes, or NULL
int detach_flags
options the window was detached with (N_GUI_DETACH_*), remembered so a close/open cycle and a restore...
n_gui_tree_on_drop_t on_drop
drag-reorder state (managed by n_gui_tree_tick)
void(* on_select)(int, void *)
selection callback
int shape
shape type: N_GUI_SHAPE_RECT, N_GUI_SHAPE_ROUNDED, N_GUI_SHAPE_BITMAP
int z_order
z-order mode (N_GUI_ZORDER_NORMAL, _ALWAYS_ON_TOP, _ALWAYS_BEHIND, _FIXED)
float max_ratio
upper clamp applied to ratio
int tag
user-defined tag for the entry (e.g.
int mouse_b1
mouse button 1 state
float button_w
width of each tab button
float display_w
display/viewport width (set via n_gui_set_display_size)
int nb_sections
number of sections
N_GUI_LISTITEM * items
dynamic array of items
ALLEGRO_BITMAP * box_hover_bitmap
optional bitmap for the checkbox square on hover (NULL = fallback to box_bitmap/box_checked_bitmap)
int h
bounding box height in pixels
float grip_size
grip area size
void * user_data
opaque user pointer handed back to the callback (not owned by n_gui)
float radio_label_gap
gap between circle and label text
N_GUI_CTX * ctx
GUI context.
ALLEGRO_DISPLAY * display
display pointer for clipboard operations (set via n_gui_set_display)
void * drop_user_data
user data for on_drop
float saved_x
embedded x saved by n_gui_window_detach, restored by n_gui_window_attach
float norm_w
normalized width (fraction of reference display width, used in SCALE mode)
float content_w
total content width computed from widgets (internal)
N_GUI_PENDING_WIDGET * pending_widgets
saved widget state for keyed widgets that did NOT exist when the layout was loaded; n_gui_widget_set_...
void * user_data
user data for this node
float norm_x
normalized position x (fraction of parent window w, used for SCALE resize)
ALLEGRO_COLOR global_scrollbar_thumb_color
global scrollbar thumb colour
int selected_label_id
id of the label widget with the most recent text selection, or -1
float radio_inner_offset
inner filled circle shrink from outer
float min_ratio
lower clamp applied to ratio
unsigned char * row_sel
per-row selection flags (1 = selected), sized rows_cap; NULL until needed
int selected_index
currently selected index (-1 = none)
ALLEGRO_BITMAP * track_bitmap
optional bitmap for the track/rail background (NULL = color theme)
int mouse_x
mouse state tracking
N_GUI_TB_BUTTONS tb_buttons
titlebar button state (minimize, maximize, close)
int order[64]
display position -> physical column
ALLEGRO_COLOR scrollbar_thumb_color
scrollbar thumb colour
int active_tab
currently active tab index
float native_h
last known native window height (see native_w)
float checkbox_max_size
maximum box size
size_t nb_entries
number of entries
int visible_map[2048]
visible row to node index
int tooltip_anchor_x
pointer x when the tooltip was last armed (movement re-arms)
float checkbox_mark_thickness
checkmark line thickness
unsigned char * row_has_color
per-row tint flags (1 = row_color[row] is painted), sized rows_cap; NULL until a row color is set
ALLEGRO_BITMAP * close_bitmap
optional bitmap for close button normal state (NULL = color theme)
int sel_start
selection start byte offset (-1 = no selection)
ALLEGRO_BITMAP * bitmap
bitmap to display (not owned, not freed)
ALLEGRO_BITMAP * fill_bitmap
optional bitmap for the filled portion of the track (NULL = color theme)
ALLEGRO_COLOR tooltip_border
tooltip bubble border color
void * on_close_user_data
user data for on_close callback
N_GUI_THEME default_tb_btn_theme
default theme for titlebar minimize/maximize buttons
int tooltip_widget_id
widget the pointer is resting on for tooltip purposes (-1 = none)
float header_height
unscaled column-header row height
float global_scroll_step
pixels per mouse wheel notch for global scroll
float item_height
item height in dropdown
int hover_row
index of the row the mouse is currently over, or -1.
void * user_data
user data for callback
double scroll_pos
current scroll position
void(* on_change)(int widget_id, const char *text, void *user_data)
callback on text change
ALLEGRO_BITMAP * item_selected_bitmap
optional bitmap for per-item background, selected/highlighted (NULL = color theme)
void * user_data
user data for callback
float autofit_origin_y
original insertion point y for N_GUI_AUTOFIT_CENTER (set by n_gui_window_set_autofit)
N_GUI_DATAGRID_COL * cols
column definitions (physical/storage order; cells are indexed by these)
int scroll_offset
scroll offset in items
int native_drag_cy
desktop y of the mouse cursor at the drag grab (see native_drag_cx)
size_t len
number of bytes
int selected
selection state (for listbox)
ALLEGRO_BITMAP * minimize_hover_bitmap
optional bitmap for minimize button hover state
ALLEGRO_BITMAP * item_hover_bitmap
optional bitmap for the hovered entry background (NULL = color theme)
float virtual_h
virtual canvas height (0 = disabled / identity transform)
int drag_active
1 once past threshold
float y0
content-local y of the first header
N_GUI_CTX * ctx
GUI context.
int shape_mode
global widget shape override: N_GUI_SHAPE_ROUNDED forces a rounded GUI, N_GUI_SHAPE_RECT forces a squ...
int visible
1 = drawn, 0 = hidden (kept in storage, skipped in the header and rows)
float global_scroll_x
global horizontal scroll offset (when GUI exceeds display)
int cached_headers_end
cached first blank-line index (HTTP headers end), or INT_MAX; valid when lines_valid
int native_pos_x
last known native window position on the desktop, applied when the native window is re-created.
float init_win_h
parent window height at create time
float checkbox_mark_margin
checkmark inset from box edge
ALLEGRO_BITMAP * track_bitmap
optional bitmap for the scrollbar track background (NULL = color theme)
ALLEGRO_DISPLAY * native
native OS window backing this pseudo-window, or NULL (the default) when the window is drawn as a pop-...
float checkbox_label_offset
horizontal offset from box edge to label text
N_GUI_CUSTOM_DRAW draw
paint callback invoked during n_gui_draw (NULL = draw nothing)
void(* on_columns_changed)(int widget_id, void *user_data)
callback fired after the user resizes a column by dragging its header border (widget_id,...
ALLEGRO_BITMAP * maximize_active_bitmap
optional bitmap for maximize button active state
ALLEGRO_BITMAP * titlebar_bitmap
optional bitmap for the titlebar background (NULL = color fill)
int scroll_offset
scroll offset in dropdown
N_GUI_CTX * ctx
GUI context.
int mouse_b1_prev
previous frame's b1 state
void * data
widget-specific data (union via void pointer)
double value
current value (always snapped to step)
N_GUI_DROPMENU_ENTRY * entries
dynamic array of entries
float drag_oy
drag offset y (internal)
float slider_track_border_thickness
track outline thickness
int pending_widgets_count
number of valid entries in pending_widgets
int nb_active
active row count
ALLEGRO_COLOR link_color_normal
link colour (normal)
float slider_handle_min_r
minimum handle circle radius
int scale_mode
scale mode: N_GUI_IMAGE_FIT, N_GUI_IMAGE_STRETCH, N_GUI_IMAGE_CENTER
float restore_h
saved height before maximise (for restore)
ALLEGRO_BITMAP * item_selected_bitmap
optional bitmap for per-item background, selected/highlighted (NULL = color theme)
ALLEGRO_BITMAP * bg_bitmap
optional bitmap for the radiolist background (NULL = color theme)
float x
content-local x of every header and the layout origin
int show_value
1 to show the Value column (default 1)
ALLEGRO_BITMAP * box_bitmap
optional bitmap for the checkbox square, unchecked state (NULL = color theme)
void * on_open_user_data
user data for on_open callback
float drag_press_y
mouse y at press time
int show_desc
1 to show the Description column (default 1)
float y
y origin of tab button row
float divider
divider thickness in pixels
float dropdown_arrow_reserve
horizontal space reserved for the arrow on the right
ALLEGRO_BITMAP * close_active_bitmap
optional bitmap for close button active state
float y
position y relative to parent window
int lbl_desc
label widget ID for "Description" header
int orientation
orientation: N_GUI_SLIDER_H or N_GUI_SLIDER_V
float global_scrollbar_border_thickness
global thumb border thickness
int state
state flags (N_GUI_WIN_*)
int visible[64]
per-physical-column visibility
int flags
feature flags (N_GUI_WIN_AUTO_SCROLLBAR, N_GUI_WIN_RESIZABLE, etc.)
int orientation
N_GUI_SPLIT_VERTICAL or N_GUI_SPLIT_HORIZONTAL.
void * user_data
user data for callback
int active
1 if active, 0 if removed
double max_val
maximum value
HASH_TABLE * widgets_by_id
hash table for fast widget lookup by id
float border_thickness
border thickness
float link_underline_thickness
link underline thickness
ALLEGRO_BITMAP * box_checked_bitmap
optional bitmap for the checkbox square, checked state (NULL = color theme)
int autofit_flags
bitmask of N_GUI_AUTOFIT_* flags (0 = no auto-fitting)
unsigned char consumed
1 once applied to a created window
float ratio
divider position as a fraction of the widget extent (0..1)
int drag_source_node
node being dragged, or -1
N_GUI_STYLE style
configurable style (sizes, colours, paddings)
ALLEGRO_FONT * font
font for the title bar
float col_resize_x0
cursor x at the start of a column-resize drag
char * key_placeholder
owned hint shown in each key textarea, or NULL
void * user_data
user data for callback
N_GUI_THEME btn_theme
theme for minimize and maximize buttons
ALLEGRO_COLOR text_active
text active
float ref_display_w
reference display width at the time normalized values were last captured
float restore_w
saved width before maximise (for restore)
int nb_nodes
number of nodes
size_t items_capacity
allocated capacity
int parent_window_id
parent window for tab buttons
double content_size
total content size
float autofit_origin_x
original insertion point x for N_GUI_AUTOFIT_CENTER (set by n_gui_window_set_autofit)
void * user_data
user data for callback
double step
step increment (0 is treated as 1).
float global_scroll_y
global vertical scroll offset (when GUI exceeds display)
int scrollbar_drag_widget_id
id of the widget whose scrollbar is being dragged, or -1
ALLEGRO_BITMAP * maximize_hover_bitmap
optional bitmap for maximize button hover state
float min_h
minimum height
float listbox_default_item_height
default item height for listbox
void * user_data
user data for callback
size_t nb_cols
number of columns
ALLEGRO_COLOR global_scrollbar_thumb_border_color
global scrollbar thumb border colour
float tb_btn_spacing
gap between titlebar buttons
ALLEGRO_COLOR border_active
border active
float scroll_x
horizontal scroll offset for single-line text (pixels)
float label_padding
horizontal padding each side
float titlebar_h
title bar height
ALLEGRO_EVENT_QUEUE * event_queue
event queue the context registers native window event sources into (set via n_gui_set_event_queue).
float ratio
divider ratio (kind == SPLITPANE)
float gui_offset_y
vertical letterbox offset for virtual canvas
int hovered
which button is currently hovered (N_GUI_TB_BTN_*)
ALLEGRO_BITMAP * item_selected_bitmap
optional bitmap for per-item background, selected/highlighted (NULL = color theme)
N_GUI_PENDING_GEOM * pending_layout
layout entries for windows that did NOT exist when the saved layout was loaded (lazily-created panels...
void(* on_select)(int widget_id, int index, int selected, void *user_data)
callback on selection change (widget_id, item_index, selected, user_data)
float natural_h
stacked height of the members when expanded
int scroll_offset
first visible line
float item_height
item height in pixels
void(* on_select)(int widget_id, int index, void *user_data)
callback on selection change (widget_id, selected_index, user_data)
int focused_widget_id
id of the widget that currently has focus, or -1
float h_scroll
horizontal scroll offset in pixels: how far the columns are scrolled to the left when their total wid...
int global_vscroll_drag
1 if global scrollbar vertical thumb is being dragged
int sel_dragging
1 if mouse is actively dragging to select text
int nb_visible
number of visible rows
ALLEGRO_COLOR global_scrollbar_track_color
global scrollbar track colour
float item_height_pad
min padding added to font height for item height
float display_h
display/viewport height
size_t len
text length in bytes
N_GUI_LISTITEM * items
dynamic array of items
void * user_data
user data for callback
float corner_ry
corner radius Y for rounded shapes
int sel_end
selection end byte offset (-1 = no selection)
float width[64]
per-physical-column width
int bg_scale_mode
scale mode for bg_bitmap: N_GUI_IMAGE_FIT, N_GUI_IMAGE_STRETCH, or N_GUI_IMAGE_CENTER
size_t text_alloc
allocated buffer size (char_limit + 1)
ALLEGRO_DISPLAY * pass_display
display the pass currently being processed or drawn belongs to: NULL for the host's main display (and...
ALLEGRO_COLOR bg_normal
background normal
ALLEGRO_BITMAP * handle_bitmap
optional bitmap for the draggable handle, normal state (NULL = color theme)
ALLEGRO_FONT * font
font used by this widget (NULL = context default)
float norm_w
normalized width (fraction of parent window w)
int resize_mode
context resize mode: N_GUI_RESIZE_VIRTUAL or N_GUI_RESIZE_ADAPTIVE
float virtual_w
virtual canvas width (0 = disabled / identity transform)
float radiolist_default_item_height
default item height for radiolist
void * user_data
user data for the callback
void(* on_minimize)(int window_id, void *user_data)
callback on minimize button click (NULL = default: toggle N_GUI_WIN_MINIMISED)
char label[128]
label displayed next to the checkbox
float slider_value_label_offset
gap between slider end and value label
void(* on_context)(int widget_id, int row, int x, int y, void *user_data)
callback on right-click over a data row, for a context menu (widget_id, row, x, y,...
size_t nb_items
number of items
int depth
depth in tree (0 = root)
float tb_btn_glyph_thickness
line thickness for titlebar button glyphs
ALLEGRO_COLOR bg_active
background active/pressed
char mask_char
mask character for password fields (0 = no masking, e.g.
ALLEGRO_BITMAP * minimize_bitmap
optional bitmap for minimize button normal state (NULL = color theme)
int global_hscroll_drag
1 if global scrollbar horizontal thumb is being dragged
float w
saved width (display-scaled), 0 when absent
LIST * windows
ordered list of N_GUI_WINDOW* (back to front)
char text[128]
display text
int scroll_y
scroll offset for long text
char text[4096]
optional centered overlay text (empty string = none)
void(* on_scroll)(int widget_id, double scroll_pos, void *user_data)
callback on scroll
int x
bounding box x offset from draw origin
float gui_bounds_h
total bounding box height of all windows (computed internally)
double min_val
minimum value
float textarea_cursor_blink_period
cursor blink period in seconds (full cycle on+off)
int lbl_value
label widget ID for "Value" header
void(* on_toggle)(int widget_id, int checked, void *user_data)
callback on toggle
ALLEGRO_COLOR bg_hover
background hover
size_t sel_start
selection anchor position (where shift-click/shift-arrow started).
int window_id
parent window
int cursor_shape
system mouse cursor currently applied to the display (an ALLEGRO_SYSTEM_MOUSE_CURSOR_* value),...
void * on_content_draw_data
user data passed to on_content_draw
float dropdown_arrow_thickness
arrow stroke thickness
float tb_btn_right_margin
right margin from window edge to rightmost button
void * user_data
user data for callback
ALLEGRO_COLOR link_color_hover
link colour (hover)
float radio_circle_min_r
minimum outer circle radius
ALLEGRO_BITMAP * bg_bitmap
optional bitmap for the listbox background (NULL = color theme)
float item_text_padding
text padding inside list/combo/dropmenu items
int next_widget_id
next widget id to assign
int enabled_id
checkbox widget ID for the enabled toggle
char * value_placeholder
owned hint shown in each value textarea, or NULL
float autofit_border
padding/border around content for auto-fit (pixels, applied on each side)
float gui_scale
computed uniform scale factor for virtual canvas
int anchor_row
anchor row for Shift-click range selection, or -1
int native_drag_anchored
1 when the four native_drag_* fields hold a usable grab, that is when al_get_mouse_cursor_position wo...
size_t cursor_pos
cursor position in text
float restore_y
saved y position before maximise (for restore)
int scroll_offset
first visible data row
void * user_data
user data for callback
int mode
mode: N_GUI_SLIDER_VALUE or N_GUI_SLIDER_PERCENT
int dirty
non-zero when the GUI's appearance may have changed since the last n_gui_draw.
size_t char_limit
maximum character limit (0 = N_GUI_TEXT_MAX)
void(* on_select)(int widget_id, int row, void *user_data)
callback on row selection (widget_id, row, user_data)
int toggle_mode
toggle mode: 0 = momentary (default), 1 = toggle (stays clicked/unclicked)
int is_open
is the menu currently open
ALLEGRO_COLOR border_hover
border hover
N_GUI_CTX * ctx
GUI context.
void * on_minimize_user_data
user data for on_minimize callback
float scrollbar_thumb_min
minimum thumb dimension
int native_halted
1 while the native window's drawing is halted.
int native_pos_y
last known native window y position (see native_pos_x)
float x
x origin of first tab button
ALLEGRO_BITMAP * thumb_hover_bitmap
optional bitmap for the thumb on hover (NULL = fallback to thumb_bitmap)
int value_id
textarea widget ID for the value
char label[128]
label displayed on the button
ALLEGRO_BITMAP * bg_bitmap
optional bitmap for the text area background (NULL = color theme)
int align
text alignment: N_GUI_ALIGN_LEFT, N_GUI_ALIGN_CENTER, N_GUI_ALIGN_RIGHT
int prev_over_win
whether the pointer was over a window on the previous motion event, so a motion that leaves the GUI s...
float native_w
last known native window width, 0 until the window is first detached.
size_t nb_rows
number of rows
void(* on_maximize)(int window_id, void *user_data)
callback on maximize button click (NULL = default: toggle N_GUI_WIN_MAXIMISED)
size_t text_len
current text length
char link[4096]
optional hyperlink URL (empty string = no link)
int orientation
orientation: N_GUI_SCROLLBAR_H or N_GUI_SCROLLBAR_V
float global_scrollbar_thumb_min
global minimum thumb dimension
double viewport_size
visible viewport size
int col_resize_col
physical column being resized by a header-border drag, or -1
unsigned char consumed
1 once applied
void(* on_link_click)(int widget_id, const char *link, void *user_data)
callback when link is clicked (widget_id, link_url, user_data)
ALLEGRO_FONT * default_font
default font (must be set before adding widgets)
float combobox_max_dropdown_width
maximum dropdown width for N_GUI_COMBOBOX_AUTO_WIDTH (0 = display width)
int selection_mode
selection mode: N_GUI_SELECT_NONE, N_GUI_SELECT_SINGLE, N_GUI_SELECT_MULTIPLE
float h
saved height (display-scaled), 0 when absent
size_t nb_items
number of items
int key_modifiers
required modifier key flags for the keybind (0 = no modifier requirement, matches any modifier state ...
ALLEGRO_COLOR * row_color
per-row background tint, sized rows_cap; NULL until a row color is set
float header_h
header button height
LIST * widgets
list of N_GUI_WIDGET* contained in this window
void * user_data
user data for callback
float y
position y on screen
ALLEGRO_BITMAP * bitmap_active
optional bitmap for active/pressed state
int tooltip_anchor_y
pointer y when the tooltip was last armed
double tooltip_armed_at
time the tooltip hover was (re)armed, from al_get_time()
char * placeholder
optional placeholder/hint text drawn dimmed while the field is empty (NULL = none); cleared from view...
int enabled
enabled flag (1 = enabled, 0 = disabled: drawn dimmed and ignores input)
float radio_circle_border_thickness
outer circle border thickness
float col_resize_w0
original width of the column at the start of a resize drag
int keycode
bound keyboard keycode (0 = none).
ALLEGRO_BITMAP * thumb_active_bitmap
optional bitmap for the thumb while dragging (NULL = fallback to thumb_bitmap)
float slider_track_size
track width (vertical) or height (horizontal)
ALLEGRO_DISPLAY * active_display
display that last received input, used to pick the display for clipboard and mouse-cursor calls.
float scroll_x
horizontal scroll offset for auto-scrollbar (pixels)
float slider_handle_border_thickness
handle border thickness
const char * n_gui_syntaxview_get_text(N_GUI_CTX *ctx, int widget_id)
get the text currently shown by a syntax view
void n_gui_set_display_size(N_GUI_CTX *ctx, float w, float h)
Set the display (viewport) size for global scrollbar computation.
void n_gui_combobox_set_bitmaps(N_GUI_CTX *ctx, int widget_id, ALLEGRO_BITMAP *bg, ALLEGRO_BITMAP *item_bg, ALLEGRO_BITMAP *item_selected)
Set optional bitmap overlays on a combobox widget.
int n_gui_load_theme_json(N_GUI_CTX *ctx, const char *filepath)
load a theme and style from a JSON file
int n_gui_listbox_get_scroll_offset(N_GUI_CTX *ctx, int widget_id)
get the current scroll offset (in items)
void n_gui_dropmenu_clear(N_GUI_CTX *ctx, int widget_id)
Remove all entries from a dropdown menu.
#define N_GUI_STATE_HOVER
mouse is hovering the widget
void n_gui_sectionlist_set_folded(N_GUI_SECTIONLIST *sl, int section_index, int folded)
set a section's folded state and relayout; does NOT fire on_toggle (for programmatic restore)
void n_gui_update_transform(N_GUI_CTX *ctx)
Recalculate scale and offset from virtual canvas to physical display.
#define N_GUI_DROPMENU_EXPAND_UP
dropdown panel opens upward (above the button) instead of downward.
int n_gui_add_hexview(N_GUI_CTX *ctx, int window_id, float x, float y, float w, float h)
Add a read-only hexadecimal byte viewer.
int n_gui_button_is_toggled(N_GUI_CTX *ctx, int widget_id)
Check if a toggle button is currently in the "on" state.
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)
float n_gui_detect_dpi_scale(N_GUI_CTX *ctx, ALLEGRO_DISPLAY *display)
Detect and apply DPI scale from an Allegro display.
float n_gui_splitpane_get_ratio(N_GUI_CTX *ctx, int widget_id)
get the current divider ratio of a split pane
void n_gui_toggle_window(N_GUI_CTX *ctx, int window_id)
Toggle window visibility (show if hidden, hide if shown)
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...
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)
void n_gui_hexview_set_data(N_GUI_CTX *ctx, int widget_id, const unsigned char *data, size_t len)
set (copy) the bytes shown by a hex viewer
#define N_GUI_TREE_MAX
maximum number of nodes in a tree view
#define N_GUI_ZORDER_NORMAL
default z-order: window participates in normal raise/lower ordering
#define N_GUI_ALIGN_LEFT
left aligned text
void n_gui_raise_window(N_GUI_CTX *ctx, int window_id)
Bring a window to the front (top of draw order).
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)
int n_gui_add_slider(N_GUI_CTX *ctx, int window_id, float x, float y, float w, float h, double min_val, double max_val, double initial, int mode, void(*on_change)(int, double, void *), void *user_data)
Add a slider widget.
void n_gui_combobox_set_flags(N_GUI_CTX *ctx, int widget_id, int flags)
Set combobox feature flags.
void n_gui_window_apply_autofit(N_GUI_CTX *ctx, int window_id)
Trigger auto-fit recalculation for a window.
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,...
int n_gui_needs_redraw(N_GUI_CTX *ctx)
Return non-zero if the GUI must be redrawn this frame, i.e.
int n_gui_datagrid_get_row_count(N_GUI_CTX *ctx, int widget_id)
get the number of rows in a data grid
#define N_GUI_SYNTAX_HTTP
syntax view: HTTP message highlighting (request/status line and headers)
void n_gui_textarea_set_text(N_GUI_CTX *ctx, int widget_id, const char *text)
set the text content of a textarea widget
void n_gui_kvtable_relayout(N_GUI_KVTABLE *table)
re-apply layout to all KV table widgets (positions, sizes, normalized coords).
int n_gui_save_layout_json(N_GUI_CTX *ctx, const char *filepath)
save the geometry + persistent state of every window to a JSON file
int n_gui_window_detach(N_GUI_CTX *ctx, int window_id, int detach_flags)
Promote a pop-up window to a native OS window.
#define N_GUI_DETACH_SCALE_CONTENT
scale the window's widgets when the native window is resized by the user.
#define N_GUI_TB_BTN_NONE
no titlebar button
#define N_GUI_SLIDER_PERCENT
slider uses 0-100 percentage
#define N_GUI_DROP_BEFORE
drop position relative to a tree row (drag-and-drop)
int n_gui_kvtable_get_count(const N_GUI_KVTABLE *table)
get the number of active rows
double n_gui_scrollbar_get_pos(N_GUI_CTX *ctx, int widget_id)
get the current scroll position of a scrollbar widget
void n_gui_tree_set_label(N_GUI_TREE *tree, int node_index, const char *new_label)
change the display label of a node
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
int n_gui_add_vslider(N_GUI_CTX *ctx, int window_id, float x, float y, float w, float h, double min_val, double max_val, double initial, int mode, void(*on_change)(int, double, void *), void *user_data)
Add a vertical slider widget.
void n_gui_set_display(N_GUI_CTX *ctx, ALLEGRO_DISPLAY *display)
Set the display pointer for clipboard operations (copy/paste).
void n_gui_window_set_bitmaps(N_GUI_CTX *ctx, int window_id, ALLEGRO_BITMAP *bg, ALLEGRO_BITMAP *titlebar, int bg_scale_mode)
Set optional bitmap overlays on a window's body and titlebar.
void n_gui_set_widget_theme(N_GUI_CTX *ctx, int widget_id, N_GUI_THEME theme)
Override the theme of a specific widget.
#define N_GUI_SECTIONLIST_MAX
maximum number of foldable sections in a section list
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
int n_gui_wants_mouse(N_GUI_CTX *ctx)
Check if the mouse is currently over any open GUI window.
int n_gui_dropmenu_get_count(N_GUI_CTX *ctx, int widget_id)
Get number of entries in a dropdown menu.
int n_gui_radiolist_add_item(N_GUI_CTX *ctx, int widget_id, const char *text)
add an item to a radiolist widget
#define N_GUI_WIN_VSCROLL_DRAG
window vertical auto-scrollbar is being dragged
void n_gui_set_widget_tooltip(N_GUI_CTX *ctx, int widget_id, const char *text)
Set (or clear) the tooltip text of any widget.
#define N_GUI_TYPE_DATAGRID
widget type: sortable column data grid
void n_gui_lower_window(N_GUI_CTX *ctx, int window_id)
Lower a window to the bottom of the draw order.
void n_gui_label_set_text(N_GUI_CTX *ctx, int widget_id, const char *text)
set the text of a label widget
int n_gui_window_native_is_hidden(N_GUI_CTX *ctx, int window_id)
Check whether a detached window is currently not drawable.
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
int n_gui_add_listbox(N_GUI_CTX *ctx, int window_id, float x, float y, float w, float h, int selection_mode, void(*on_select)(int, int, int, void *), void *user_data)
Add a listbox widget.
#define N_GUI_COMBOBOX_EXPAND_UP
dropdown panel opens upward (above the widget) instead of downward.
#define N_GUI_PERSIST_MAX_COLS
Maximum datagrid columns whose layout is persisted per widget.
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...
#define N_GUI_COMBOBOX_AUTO_WIDTH
dropdown panel expands to fit the longest item text
#define N_GUI_TYPE_LABEL
widget type: static text label (with optional hyperlink)
#define N_GUI_WIN_RESIZE_SCALE
reposition AND resize proportionally, child widgets scale too
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.
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...
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...
int n_gui_datagrid_get_scroll_offset(N_GUI_CTX *ctx, int widget_id)
first visible data row (the vertical scroll position), or 0.
#define N_GUI_TYPE_CHECKBOX
widget type: checkbox
void n_gui_window_set_tb_button_bitmaps(N_GUI_CTX *ctx, int window_id, int btn_type, ALLEGRO_BITMAP *normal, ALLEGRO_BITMAP *hover, ALLEGRO_BITMAP *active)
Set optional bitmap overlays on a titlebar button.
void n_gui_focus_window(N_GUI_CTX *ctx, int window_id)
Give a window keyboard focus and bring it to the front.
#define N_GUI_KV_MAX
maximum number of rows in a KV table
#define N_GUI_TYPE_DROPMENU
widget type: dropdown menu with static and dynamic entries
int n_gui_process_event(N_GUI_CTX *ctx, ALLEGRO_EVENT event)
Process an allegro event through the GUI system.
int n_gui_window_get_flags(N_GUI_CTX *ctx, int window_id)
Get feature flags of a window.
void n_gui_minimize_window(N_GUI_CTX *ctx, int window_id)
Minimise a window (show title bar only)
#define N_GUI_DETACH_NONE
no option
int n_gui_add_label(N_GUI_CTX *ctx, int window_id, const char *text, float x, float y, float w, float h, int align)
Add a static text label.
void n_gui_set_widget_enabled(N_GUI_CTX *ctx, int widget_id, int enabled)
Enable or disable a widget.
int n_gui_add_radiolist(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 radio list widget (single selection with radio bullets)
#define N_GUI_SPLIT_HORIZONTAL
split pane: horizontal divider, regions are top and bottom
#define N_GUI_WIN_FIXED_POSITION
disable window dragging (default:enable)
void n_gui_tab_free(N_GUI_TAB_PANEL **panel)
free a tab panel (does not destroy the N_GUI widgets)
void n_gui_close_window(N_GUI_CTX *ctx, int window_id)
Close (hide) a window.
void n_gui_maximize_window(N_GUI_CTX *ctx, int window_id)
Toggle maximised state (full display or restore to previous size).
void n_gui_listbox_set_bitmaps(N_GUI_CTX *ctx, int widget_id, ALLEGRO_BITMAP *bg, ALLEGRO_BITMAP *item_bg, ALLEGRO_BITMAP *item_selected)
Set optional bitmap overlays on a listbox widget.
void n_gui_label_set_link(N_GUI_CTX *ctx, int widget_id, const char *link)
set the link URL of a label widget
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 ...
#define N_GUI_RESIZE_VIRTUAL
fixed virtual canvas with uniform scaling (default/existing behavior)
ALLEGRO_EVENT_QUEUE * n_gui_get_event_queue(N_GUI_CTX *ctx)
Get the event queue previously given to n_gui_set_event_queue.
void n_gui_kvtable_free(N_GUI_KVTABLE **table)
free a KV table (does not destroy the N_GUI widgets)
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).
void n_gui_button_set_keycode_focused(N_GUI_CTX *ctx, int widget_id, int keycode, int modifiers, const int *sources, int source_count)
Set a focused key binding on a button.
void n_gui_radiolist_clear(N_GUI_CTX *ctx, int widget_id)
remove all items from a radiolist widget
#define N_GUI_TYPE_SPLITPANE
widget type: split pane with a draggable divider between two regions
void n_gui_kvtable_clear(N_GUI_KVTABLE *table)
remove every row at once.
void n_gui_slider_set_value_format(N_GUI_CTX *ctx, int widget_id, const char *fmt)
Override the built-in value readout's printf format string.
void n_gui_listbox_set_selected(N_GUI_CTX *ctx, int widget_id, int index, int selected)
set the selection state of a listbox item
#define N_GUI_SELECT_NONE
no selection allowed (display only)
int(* n_gui_tree_on_drop_t)(int src_node, int dst_node, int position, void *user_data)
drag-reorder drop callback.
#define N_GUI_TYPE_HEXVIEW
widget type: read-only hexadecimal byte viewer
int n_gui_add_window_auto(N_GUI_CTX *ctx, const char *title, float x, float y)
Add a window with automatic sizing (use n_gui_window_autosize after adding widgets)
void n_gui_syntaxview_set_selection(N_GUI_CTX *ctx, int widget_id, int start, int end)
set the selection range of a syntax view (byte offsets into the text)
double n_gui_slider_get_value(N_GUI_CTX *ctx, int widget_id)
get the current value of a slider widget
int n_gui_listbox_add_item(N_GUI_CTX *ctx, int widget_id, const char *text)
add an item to a listbox widget
N_GUI_THEME n_gui_default_tb_btn_theme(void)
Build a default theme for titlebar minimize/maximize buttons.
void n_gui_set_virtual_size(N_GUI_CTX *ctx, float w, float h)
Set the virtual canvas size for resolution-independent scaling.
int n_gui_tooltip_pending(N_GUI_CTX *ctx)
Report the tooltip phase.
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)
float n_gui_get_dpi_scale(const N_GUI_CTX *ctx)
Get current DPI scale factor.
void n_gui_tree_clear(N_GUI_TREE *tree)
remove all nodes and clear the backing listbox; tree object remains valid
N_GUI_THEME n_gui_default_theme(void)
Build a sensible default colour theme.
#define N_GUI_WIN_RESIZE_NONE
no adaptation: absolute position and size unchanged
void n_gui_window_set_zorder(N_GUI_CTX *ctx, int window_id, int z_mode, int z_value)
Set window z-order mode and value.
int n_gui_radiolist_get_selected(N_GUI_CTX *ctx, int widget_id)
get the selected item index in a radiolist widget
void n_gui_tab_set_content_window(N_GUI_TAB_PANEL *panel, int tab_index, int window_id)
associate a content window with a tab
#define N_GUI_TYPE_SLIDER
widget type: slider
#define N_GUI_WIN_OPEN
window is visible
void n_gui_button_set_label(N_GUI_CTX *ctx, int widget_id, const char *label)
Replace the label text drawn on a button.
void n_gui_button_set_state_bitmaps(N_GUI_CTX *ctx, int widget_id, ALLEGRO_BITMAP *normal, ALLEGRO_BITMAP *hover, ALLEGRO_BITMAP *active)
Skin a button (or toggle button) with per-state bitmaps.
int n_gui_save_theme_json(N_GUI_CTX *ctx, const char *filepath)
save the current theme and style to a JSON file
#define N_GUI_SELECT_SINGLE
single item selection
#define N_GUI_TB_BTN_CLOSE
close titlebar button
int n_gui_combobox_add_item(N_GUI_CTX *ctx, int widget_id, const char *text)
add an item to a combo box
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.
float n_gui_sectionlist_content_height(const N_GUI_SECTIONLIST *sl)
total content height in pixels under the current fold state, for sizing/scrolling the host window
void n_gui_window_autosize(N_GUI_CTX *ctx, int window_id)
Recompute and apply minimum-fit size for a window based on its current widgets.
int n_gui_syntaxview_get_line_count(N_GUI_CTX *ctx, int widget_id)
get the number of text lines in a syntax view
#define N_GUI_SECTION_WIDGETS_MAX
maximum number of member widgets per section
void n_gui_window_set_minimize_callback(N_GUI_CTX *ctx, int window_id, void(*on_minimize)(int, void *), void *user_data)
Set the minimize button callback for a window.
int n_gui_add_splitpane(N_GUI_CTX *ctx, int window_id, float x, float y, float w, float h, int orientation, float ratio, void(*on_change)(int, float, void *), void *user_data)
Add a split pane widget: a draggable divider between two regions.
const char * n_gui_widget_get_persist_key(N_GUI_CTX *ctx, int widget_id)
Get a widget's persist key ("" when unset), or NULL when the widget is invalid.
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
void n_gui_set_focus(N_GUI_CTX *ctx, int widget_id)
Set keyboard focus to a specific widget.
void n_gui_tree_rebuild(N_GUI_TREE *tree)
rebuild the listbox to reflect current tree state
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...
void n_gui_datagrid_set_multiselect(N_GUI_CTX *ctx, int widget_id, int enabled)
enable (1) or disable (0) multi-row selection.
void n_gui_textarea_set_selection(N_GUI_CTX *ctx, int widget_id, size_t start, size_t end)
set the text selection range (byte offsets into text content)
#define N_GUI_SELECT_MULTIPLE
multiple item selection
void n_gui_scrollbar_set_bitmaps(N_GUI_CTX *ctx, int widget_id, ALLEGRO_BITMAP *track, ALLEGRO_BITMAP *thumb, ALLEGRO_BITMAP *thumb_hover, ALLEGRO_BITMAP *thumb_active)
Set optional bitmap overlays on a scrollbar widget.
#define N_GUI_WIN_FRAMELESS
frameless window: no title bar drawn, drag via window body unless N_GUI_WIN_FIXED_POSITION is also se...
void n_gui_set_shape_mode(N_GUI_CTX *ctx, int shape_mode)
Set the global widget shape (round or square GUI).
int n_gui_add_combobox(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 combo box widget (dropdown selector)
void n_gui_syntaxview_set_mode(N_GUI_CTX *ctx, int widget_id, int mode)
set the highlighting mode of a syntax view
void n_gui_button_set_toggled(N_GUI_CTX *ctx, int widget_id, int toggled)
Set the toggle state of a button.
void n_gui_progressbar_set_text(N_GUI_CTX *ctx, int widget_id, const char *text)
set the centered overlay text (NULL or "" clears it)
void n_gui_tab_set_active(N_GUI_TAB_PANEL *panel, int index)
set the active tab (toggles buttons, opens/closes content windows)
#define N_GUI_DETACH_RESIZABLE
the native window can be resized by the user through the OS window manager
int n_gui_window_is_detached(N_GUI_CTX *ctx, int window_id)
Check whether a window currently lives in a native OS window.
void n_gui_slider_set_step(N_GUI_CTX *ctx, int widget_id, double step)
set slider step increment.
int n_gui_add_toggle_button(N_GUI_CTX *ctx, int window_id, const char *label, float x, float y, float w, float h, int shape, int initial_state, void(*on_click)(int, void *), void *user_data)
Add a toggle button widget (stays clicked/unclicked on single click)
int n_gui_get_topmost_open_window(const N_GUI_CTX *ctx)
Get the id of the frontmost open, non-minimized window.
void n_gui_kvtable_remove_row(N_GUI_KVTABLE *table, int row_index)
remove a row by index (hides widgets, marks inactive)
int n_gui_add_label_link(N_GUI_CTX *ctx, int window_id, const char *text, const char *link, float x, float y, float w, float h, int align, void(*on_link_click)(int, const char *, void *), void *user_data)
Add a static text label with hyperlink.
void n_gui_textarea_set_mask_char(N_GUI_CTX *ctx, int widget_id, char mask)
Set a mask character for password-style input.
void n_gui_window_set_tb_close_theme(N_GUI_CTX *ctx, int window_id, N_GUI_THEME theme)
Set the theme for the titlebar close button on a specific window.
void n_gui_window_set_tb_btn_theme(N_GUI_CTX *ctx, int window_id, N_GUI_THEME theme)
Set the theme for titlebar minimize/maximize buttons on a specific window.
int n_gui_add_progressbar(N_GUI_CTX *ctx, int window_id, float x, float y, float w, float h)
add a horizontal progress bar (display only); returns the widget id or -1
int n_gui_tab_get_active(const N_GUI_TAB_PANEL *panel)
get the active tab index
size_t n_gui_hexview_get_length(N_GUI_CTX *ctx, int widget_id)
get the number of bytes currently held by a hex viewer
int n_gui_listbox_get_selected(N_GUI_CTX *ctx, int widget_id)
get the index of the first selected item in a listbox
#define N_GUI_AUTOFIT_EXPAND_LEFT
expand leftward instead of rightward when adjusting width
int n_gui_add_image(N_GUI_CTX *ctx, int window_id, float x, float y, float w, float h, ALLEGRO_BITMAP *bitmap, int scale_mode)
Add an image display widget.
void n_gui_widget_set_persist_key(N_GUI_CTX *ctx, int widget_id, const char *key)
Give a widget a stable key so its user-adjustable state (a splitpane's divider ratio,...
void n_gui_label_set_bitmap(N_GUI_CTX *ctx, int widget_id, ALLEGRO_BITMAP *bg)
Set optional background bitmap on a label widget.
void n_gui_draw(N_GUI_CTX *ctx)
Draw all visible windows and their widgets.
void n_gui_progressbar_set_value(N_GUI_CTX *ctx, int widget_id, float value)
set the progress fraction (clamped to 0.0 .
#define N_GUI_TYPE_SYNTAXVIEW
widget type: read-only syntax-highlighted text view
#define N_GUI_WIN_MINIMISED
window is minimised (title bar only)
#define N_GUI_SLIDER_H
horizontal slider (default)
int n_gui_tree_find_by_user_data(const N_GUI_TREE *tree, const void *ptr)
find the first node whose user_data pointer equals ptr, or -1.
void n_gui_tree_set_selection(N_GUI_TREE *tree, int node_index)
programmatically select a node; ancestors are expanded so the node is visible, and the listbox scroll...
#define N_GUI_AUTOFIT_CENTER
center the window on its insertion point after auto-fit (overrides EXPAND_LEFT/EXPAND_UP for centerin...
int n_gui_tab_add(N_GUI_TAB_PANEL *panel, const char *label)
add a tab to the panel, returns tab index
void n_gui_tree_set_on_drop(N_GUI_TREE *tree, n_gui_tree_on_drop_t on_drop, void *user_data)
install (or clear, with NULL) a drag-reorder drop callback.
void n_gui_slider_set_bitmaps(N_GUI_CTX *ctx, int widget_id, ALLEGRO_BITMAP *track, ALLEGRO_BITMAP *fill, ALLEGRO_BITMAP *handle, ALLEGRO_BITMAP *handle_hover, ALLEGRO_BITMAP *handle_active)
Set optional bitmap overlays on a slider widget.
#define N_GUI_SYNTAX_XML
syntax view: XML/HTML highlighting (tags, attributes, quoted values, comments)
int n_gui_window_get_zorder(N_GUI_CTX *ctx, int window_id)
Get window z-order mode.
void n_gui_tree_free(N_GUI_TREE **tree)
free a tree view (does not destroy the N_GUI listbox)
N_GUI_SECTIONLIST * n_gui_sectionlist_create(N_GUI_CTX *ctx, int window_id, float x, float y0, float width, float header_h, float gap, void(*on_toggle)(int, int, void *), void *user_data)
create an empty section list anchored at (x,y0) in window_id; sections stack downward from y0
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...
#define N_GUI_TYPE_IMAGE
widget type: image display
int n_gui_window_get_resize_policy(N_GUI_CTX *ctx, int window_id)
Get per-window resize policy.
void n_gui_checkbox_set_checked(N_GUI_CTX *ctx, int widget_id, int checked)
set the checked state of a checkbox widget
int n_gui_dropmenu_add_dynamic_entry(N_GUI_CTX *ctx, int widget_id, const char *text, int tag, void(*on_click)(int, int, int, void *), void *user_data)
Add a dynamic entry (rebuilt each time menu opens)
void n_gui_apply_adaptive_resize(N_GUI_CTX *ctx, float new_w, float new_h)
Apply adaptive resize: reposition/resize all windows according to their policies for the new display ...
int n_gui_tree_get_selection(N_GUI_TREE *tree)
get the index of the currently selected node, or -1 when nothing is selected or the selection points ...
int n_gui_is_widget_enabled(N_GUI_CTX *ctx, int widget_id)
Check if a widget is enabled.
void n_gui_button_set_keycode(N_GUI_CTX *ctx, int widget_id, int keycode, int modifiers)
Bind a keyboard key with optional modifier requirements to a button.
#define N_GUI_SYNTAX_JSON
syntax view: JSON highlighting (keys, strings, numbers, punctuation)
N_GUI_THEME n_gui_default_tb_close_theme(void)
Build a default theme for the titlebar close button.
char * n_gui_syntaxview_get_selected_text(N_GUI_CTX *ctx, int widget_id)
get a copy of the currently selected text in a syntax view
int n_gui_window_is_open(N_GUI_CTX *ctx, int window_id)
Check if a window is currently visible.
void n_gui_set_dpi_scale(N_GUI_CTX *ctx, float scale)
Set DPI scale factor manually (default 1.0)
#define N_GUI_TYPE_RADIOLIST
widget type: radio list (single select radio buttons)
#define N_GUI_SLIDER_V
vertical slider
int n_gui_get_resize_mode(N_GUI_CTX *ctx)
Get current resize mode.
N_GUI_WIDGET * n_gui_get_widget(N_GUI_CTX *ctx, int widget_id)
Get a widget pointer by id.
int n_gui_dropmenu_add_entry(N_GUI_CTX *ctx, int widget_id, const char *text, int tag, void(*on_click)(int, int, int, void *), void *user_data)
Add a static entry to a dropdown menu.
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...
#define N_GUI_ZORDER_ALWAYS_BEHIND
always drawn behind normal windows, cannot be raised above them
#define N_GUI_IMAGE_STRETCH
stretch to fill bounds
N_GUI_WINDOW * n_gui_get_window(N_GUI_CTX *ctx, int window_id)
Get a window pointer by id.
#define N_GUI_ZORDER_ALWAYS_ON_TOP
always drawn on top of normal windows, cannot be lowered behind them
int n_gui_add_syntaxview(N_GUI_CTX *ctx, int window_id, float x, float y, float w, float h, int mode)
Add a read-only syntax-highlighted text view.
void n_gui_datagrid_clear_selection(N_GUI_CTX *ctx, int widget_id)
clear the entire selection (no row selected)
void n_gui_dropmenu_set_bitmaps(N_GUI_CTX *ctx, int widget_id, ALLEGRO_BITMAP *panel, ALLEGRO_BITMAP *item_hover)
Set optional bitmap overlays on a dropmenu widget.
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.
void n_gui_slider_set_value_visible(N_GUI_CTX *ctx, int widget_id, int visible)
Toggle the built-in value label.
int n_gui_window_attach(N_GUI_CTX *ctx, int window_id)
Return a detached window to being an in-display pop-up.
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....
void n_gui_draw_detached(N_GUI_CTX *ctx)
Render and flip every detached window, and release the ones whose native window was closed.
N_GUI_CTX * n_gui_new_ctx(ALLEGRO_FONT *default_font)
Create a new GUI context.
void n_gui_datagrid_clear_rows(N_GUI_CTX *ctx, int widget_id)
remove all rows from a data grid (columns are kept)
void n_gui_slider_set_range(N_GUI_CTX *ctx, int widget_id, double min_val, double max_val)
set slider min/max range, clamping the current value if needed
const char * n_gui_listbox_get_item_text(N_GUI_CTX *ctx, int widget_id, int index)
get the text of a listbox item
void n_gui_radiolist_set_bitmaps(N_GUI_CTX *ctx, int widget_id, ALLEGRO_BITMAP *bg, ALLEGRO_BITMAP *item_bg, ALLEGRO_BITMAP *item_selected)
Set optional bitmap overlays on a radiolist widget.
N_GUI_TREE * n_gui_tree_create(N_GUI_CTX *ctx, int window_id, float x, float y, float w, float h, void(*on_select)(int, void *), void *user_data)
create a tree view in an existing window
#define N_GUI_WIN_MAXIMISED
window is maximised (full display size)
int n_gui_add_button_bitmap(N_GUI_CTX *ctx, int window_id, const char *label, float x, float y, float w, float h, ALLEGRO_BITMAP *normal, ALLEGRO_BITMAP *hover, ALLEGRO_BITMAP *active, void(*on_click)(int, void *), void *user_data)
Add a bitmap-based button.
#define N_GUI_IMAGE_CENTER
draw at original size, centered
void n_gui_window_set_close_callback(N_GUI_CTX *ctx, int window_id, void(*on_close)(int, void *), void *user_data)
Set the close button callback for a window.
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.
void n_gui_button_set_toggle_mode(N_GUI_CTX *ctx, int widget_id, int toggle_mode)
Enable or disable toggle mode on a button.
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
#define N_GUI_ALIGN_CENTER
center aligned text
#define N_GUI_DETACH_OWN_CHROME
keep N_GUI's own window chrome instead of the window manager's: the native window is created frameles...
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
void n_gui_tree_toggle_expand(N_GUI_TREE *tree, int node_index)
toggle expand/collapse of a node
#define N_GUI_TYPE_SCROLLBAR
widget type: scrollbar
void n_gui_textarea_scroll_to_offset(N_GUI_CTX *ctx, int widget_id, size_t byte_offset)
scroll a multiline textarea so that the given byte offset is vertically centered
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.
#define N_GUI_TYPE_PROGRESSBAR
widget type: horizontal progress bar (display only)
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
#define N_GUI_TB_BTN_MAXIMIZE
maximize/restore titlebar button
void(* N_GUI_CUSTOM_DRAW)(N_GUI_WIDGET *widget, float x, float y, ALLEGRO_FONT *font, void *user_data)
Owner-draw callback for a custom widget (N_GUI_TYPE_CUSTOM).
#define N_GUI_TB_BTN_MINIMIZE
minimize titlebar button
#define N_GUI_SPLIT_VERTICAL
split pane: vertical divider, regions are left and right
void n_gui_textarea_set_bitmap(N_GUI_CTX *ctx, int widget_id, ALLEGRO_BITMAP *bg)
Set optional background bitmap on a textarea widget.
void n_gui_listbox_clear(N_GUI_CTX *ctx, int widget_id)
remove all items from a listbox widget
#define N_GUI_TYPE_BUTTON
widget type: button
#define N_GUI_TYPE_COMBOBOX
widget type: combo box (dropdown)
float n_gui_dropmenu_panel_width(N_GUI_CTX *ctx, int widget_id)
Width the open drop-down panel needs to show its entries.
#define N_GUI_TYPE_CUSTOM
widget type: owner-draw custom widget (rendering delegated to a callback)
int n_gui_add_scrollbar(N_GUI_CTX *ctx, int window_id, float x, float y, float w, float h, int orientation, int shape, double content_size, double viewport_size, void(*on_scroll)(int, double, void *), void *user_data)
Add a scrollbar widget.
N_GUI_TEXT_DIMS n_gui_get_text_dims(ALLEGRO_FONT *font, const char *text)
get the bounding box dimensions of text rendered with the given font.
#define N_GUI_WIN_BTN_MINIMIZE
enable minimize button on the title bar
void n_gui_destroy_ctx(N_GUI_CTX **ctx)
Destroy a GUI context and all its windows/widgets.
int n_gui_window_is_minimised(N_GUI_CTX *ctx, int window_id)
Check if a window is currently minimised.
void n_gui_restore_window(N_GUI_CTX *ctx, int window_id)
Restore a minimised window to its full size.
#define N_GUI_ZORDER_FIXED
fixed z-value: window is sorted within a dedicated group between ALWAYS_BEHIND and NORMAL windows.
const char * n_gui_textarea_get_text(N_GUI_CTX *ctx, int widget_id)
get the text content of a textarea widget
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
int n_gui_get_shape_mode(N_GUI_CTX *ctx)
Get the global widget shape.
#define N_GUI_WIN_HSCROLL_DRAG
window horizontal auto-scrollbar is being dragged
void n_gui_checkbox_set_bitmaps(N_GUI_CTX *ctx, int widget_id, ALLEGRO_BITMAP *box, ALLEGRO_BITMAP *box_checked, ALLEGRO_BITMAP *box_hover)
Set optional bitmap overlays on a checkbox widget.
void n_gui_listbox_set_scroll_offset(N_GUI_CTX *ctx, int widget_id, int offset)
set the scroll offset (in items), clamps to valid range
float n_gui_progressbar_get_value(N_GUI_CTX *ctx, int widget_id)
get the current progress fraction (0.0 on an invalid widget)
int n_gui_sectionlist_get_count(const N_GUI_SECTIONLIST *sl)
number of sections in the list
#define N_GUI_TEXT_MAX
maximum length for textarea content
#define N_GUI_STATE_IDLE
widget is idle / normal state
void n_gui_textarea_scroll_to_bottom(N_GUI_CTX *ctx, int widget_id)
scroll a multiline textarea to the bottom
size_t n_gui_textarea_get_text_length(N_GUI_CTX *ctx, int widget_id)
return the current text length in bytes
void n_gui_open_window(N_GUI_CTX *ctx, int window_id)
Open (show) a window.
int n_gui_window_get_zvalue(N_GUI_CTX *ctx, int window_id)
Get window z-value (for N_GUI_ZORDER_FIXED mode).
ALLEGRO_DISPLAY * n_gui_window_get_display(N_GUI_CTX *ctx, int window_id)
Get the native display backing a window, or NULL when it is a pop-up.
#define N_GUI_WIN_BTN_MAXIMIZE
enable maximize/restore button on the title bar
int n_gui_sectionlist_add_section(N_GUI_SECTIONLIST *sl, const char *title, float header_y, int folded)
add a section with a header button at header_y (members added next are captured relative to it); retu...
void n_gui_dropmenu_set_entry_text(N_GUI_CTX *ctx, int widget_id, int index, const char *text)
Update text of an existing entry.
void n_gui_window_set_content_draw_callback(N_GUI_CTX *ctx, int window_id, void(*on_content_draw)(int, void *), void *user_data)
Set the content-draw callback for a window.
int n_gui_tree_add_node(N_GUI_TREE *tree, const char *label, int parent_index, void *user_data)
add a node to the tree
#define N_GUI_WIN_BTN_CLOSE
enable close button on the title bar
int n_gui_listbox_get_count(N_GUI_CTX *ctx, int widget_id)
get the number of items in a listbox widget
int n_gui_window_set_native_icons(N_GUI_CTX *ctx, int window_id, ALLEGRO_BITMAP **icons, int num_icons)
Give a detached window's OS window a taskbar / title bar icon.
void n_gui_dropmenu_set_label(N_GUI_CTX *ctx, int widget_id, const char *label)
Replace the button label shown on a dropmenu.
void n_gui_tree_draw_overlay(N_GUI_TREE *tree)
per-frame overlay drawing: draws the active drop-indicator on top of the listbox.
const char * n_gui_combobox_get_item_text(N_GUI_CTX *ctx, int widget_id, int index)
get the text of the combobox item at index ("" if out of range / not a combobox)
int n_gui_count_detached(N_GUI_CTX *ctx)
Count the windows currently detached into native OS windows.
#define N_GUI_WIN_NO_HSCROLL
with N_GUI_WIN_AUTO_SCROLLBAR, never show the horizontal scrollbar (vertical-only scrolling): content...
#define N_GUI_ZORDER_POPUP
popup/modal dialogs: drawn above EVERYTHING including ALWAYS_ON_TOP windows.
void n_gui_dropmenu_set_flags(N_GUI_CTX *ctx, int widget_id, int flags)
Set dropmenu feature flags (bitmask of N_GUI_DROPMENU_* values)
void n_gui_splitpane_set_ratio(N_GUI_CTX *ctx, int widget_id, float ratio)
set the divider ratio of a split pane (clamped to its min/max)
int n_gui_checkbox_is_checked(N_GUI_CTX *ctx, int widget_id)
check if a checkbox widget is checked
#define N_GUI_WIN_RESIZE_MOVE
reposition proportionally, keep pixel size
void n_gui_splitpane_set_limits(N_GUI_CTX *ctx, int widget_id, float min_ratio, float max_ratio)
set the minimum and maximum allowed divider ratio of a split pane
#define N_GUI_STATE_ACTIVE
widget is being pressed / dragged
void n_gui_set_default_theme(N_GUI_CTX *ctx, N_GUI_THEME theme)
Set the default theme on a context and sync scrollbar style colors.
int n_gui_combobox_get_selected(N_GUI_CTX *ctx, int widget_id)
get the selected item index in a combobox widget
void n_gui_tree_remove_node(N_GUI_TREE *tree, int node_index)
remove a node and its entire subtree; remaining node indices are compacted (callers holding indices a...
void n_gui_image_set_bitmap(N_GUI_CTX *ctx, int widget_id, ALLEGRO_BITMAP *bitmap)
set the bitmap of an image widget
int n_gui_load_layout_json(N_GUI_CTX *ctx, const char *filepath)
load a JSON window layout file and apply it to matching windows
int n_gui_window_is_maximised(N_GUI_CTX *ctx, int window_id)
Check if a window is currently maximised.
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
void n_gui_syntaxview_set_text(N_GUI_CTX *ctx, int widget_id, const char *text)
set (copy) the text shown by a syntax view
void n_gui_slider_set_value(N_GUI_CTX *ctx, int widget_id, double value)
set the value of a slider widget
#define N_GUI_AUTOFIT_EXPAND_UP
expand upward instead of downward when adjusting height
#define N_GUI_SHAPE_BITMAP
bitmap-based rendering
#define N_GUI_SHAPE_ROUNDED
rounded rectangle shape
#define N_GUI_ALIGN_RIGHT
right aligned text
int n_gui_sectionlist_is_folded(const N_GUI_SECTIONLIST *sl, int section_index)
query a section's folded state (1 = folded, 0 = expanded)
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)
void n_gui_syntaxview_scroll_to_offset(N_GUI_CTX *ctx, int widget_id, int byte_offset)
scroll a syntax view so the line holding a byte offset is vertically centered
#define N_GUI_AUTOFIT_H
auto-adjust window height to content
void n_gui_sectionlist_add_widget(N_GUI_SECTIONLIST *sl, int section_index, int widget_id)
register an existing widget as a member of a section (captures its current y as the fold offset)
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...
void n_gui_sectionlist_set_first_inset(N_GUI_SECTIONLIST *sl, float inset)
set a left inset applied to the FIRST section's header only, so a caller can place a button before it...
void n_gui_radiolist_set_selected(N_GUI_CTX *ctx, int widget_id, int index)
set the selected item in a radiolist widget
void n_gui_window_set_flags(N_GUI_CTX *ctx, int window_id, int flags)
Set feature flags on a window.
#define N_GUI_KEY_MOD_MASK
mask of supported modifier flags for button keybind matching
#define N_GUI_ALIGN_JUSTIFIED
justified text (spread words to fill width)
void n_gui_set_widget_visible(N_GUI_CTX *ctx, int widget_id, int visible)
Show or hide a widget.
void n_gui_syntaxview_select_all(N_GUI_CTX *ctx, int widget_id)
select the entire text of a syntax view
N_GUI_TAB_PANEL * n_gui_tab_create(N_GUI_CTX *ctx, int window_id, float x, float y, float button_w, float button_h, void(*on_tab_change)(int, void *), void *user_data)
create a tab panel in an existing window
void n_gui_mark_dirty(N_GUI_CTX *ctx)
Mark the GUI as needing a redraw.
#define N_GUI_ID_MAX
maximum length for widget id/name strings
N_GUI_STYLE n_gui_default_style(void)
Build sensible default style (all configurable sizes, colours, paddings)
#define N_GUI_TAB_MAX
maximum number of tabs in a single tab panel
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)
#define N_GUI_AUTOFIT_W
auto-adjust window width to content
void n_gui_window_set_maximize_callback(N_GUI_CTX *ctx, int window_id, void(*on_maximize)(int, void *), void *user_data)
Set the maximize button callback for a window.
void n_gui_scrollbar_set_sizes(N_GUI_CTX *ctx, int widget_id, double content_size, double viewport_size)
set the content and viewport sizes of a scrollbar widget
#define N_GUI_WIN_AUTO_SCROLLBAR
enable automatic scrollbars when content exceeds window size
#define N_GUI_WIN_RESIZING
window is being resized
int n_gui_window_from_display(N_GUI_CTX *ctx, ALLEGRO_DISPLAY *display)
Find the window detached into a given display.
#define N_GUI_RESIZE_ADAPTIVE
virtual size tracks display; windows adapt per their resize_policy
void n_gui_textarea_set_placeholder(N_GUI_CTX *ctx, int widget_id, const char *text)
Set placeholder/hint text shown dimmed while a textarea is empty.
int n_gui_add_textarea(N_GUI_CTX *ctx, int window_id, float x, float y, float w, float h, int multiline, size_t char_limit, void(*on_change)(int, const char *, void *), void *user_data)
Add a text area widget.
void n_gui_sectionlist_free(N_GUI_SECTIONLIST **sl)
free the section list (does not destroy the N_GUI widgets or window)
#define N_GUI_TYPE_LISTBOX
widget type: listbox (selectable list)
int n_gui_datagrid_get_selected(N_GUI_CTX *ctx, int widget_id)
get the selected row index, or -1 if none
int n_gui_listbox_is_selected(N_GUI_CTX *ctx, int widget_id, int index)
check if a listbox item is selected
void n_gui_window_update_normalized(N_GUI_CTX *ctx, int window_id)
Recapture normalized coordinates for a window from its current absolute position/size.
#define N_GUI_SYNTAX_YAML
syntax view: YAML highlighting (keys, quoted values, list markers, comments)
int n_gui_add_checkbox(N_GUI_CTX *ctx, int window_id, const char *label, float x, float y, float w, float h, int initial_checked, void(*on_toggle)(int, int, void *), void *user_data)
Add a checkbox widget.
void n_gui_combobox_clear(N_GUI_CTX *ctx, int widget_id)
remove all items from a combobox widget
void n_gui_sectionlist_relayout(N_GUI_SECTIONLIST *sl)
re-stack all sections from y0 by current fold state: hide folded members, show and reposition expande...
#define N_GUI_SYNTAX_JS
syntax view: JavaScript highlighting (keywords, strings, numbers, comments)
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
#define N_GUI_SHAPE_RECT
rectangle shape (default)
void n_gui_combobox_set_selected(N_GUI_CTX *ctx, int widget_id, int index)
set the selected item in a combobox widget
int n_gui_listbox_remove_item(N_GUI_CTX *ctx, int widget_id, int index)
remove an item from a listbox widget
#define N_GUI_SCROLLBAR_V
vertical scrollbar
N_GUI_THEME n_gui_make_theme(ALLEGRO_COLOR bg, ALLEGRO_COLOR bg_hover, ALLEGRO_COLOR bg_active, ALLEGRO_COLOR border, ALLEGRO_COLOR border_hover, ALLEGRO_COLOR border_active, ALLEGRO_COLOR text, ALLEGRO_COLOR text_hover, ALLEGRO_COLOR text_active, float border_thickness, float corner_rx, float corner_ry)
Create a custom theme with explicit colours.
int n_gui_add_dropmenu(N_GUI_CTX *ctx, int window_id, const char *label, float x, float y, float w, float h, void(*on_open)(int, void *), void *on_open_user_data)
Add a dropdown menu widget.
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.
void n_gui_screen_to_virtual(const N_GUI_CTX *ctx, float sx, float sy, float *vx, float *vy)
Convert physical screen coordinates to virtual canvas coordinates.
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.
void n_gui_set_event_queue(N_GUI_CTX *ctx, ALLEGRO_EVENT_QUEUE *queue)
Set the event queue used to register native window event sources.
int n_gui_add_custom(N_GUI_CTX *ctx, int window_id, float x, float y, float w, float h, N_GUI_CUSTOM_DRAW draw, void *user_data)
add an owner-draw custom widget; returns the widget id or -1
#define N_GUI_KEY_SOURCES_MAX
maximum number of source widgets for a focused key binding
#define N_GUI_WIN_RESIZABLE
enable user-resizable window with a drag handle at bottom-right
#define N_GUI_STATE_FOCUSED
widget has keyboard focus
void n_gui_tree_tick(N_GUI_TREE *tree)
per-frame poll: reads ctx->mouse_* to track drag state and fires the on_drop callback on release.
#define N_GUI_WIN_DRAGGING
window is being dragged
void n_gui_reset_all_widget_themes(N_GUI_CTX *ctx)
Reset all widget and window themes to ctx->default_theme.
#define N_GUI_TYPE_TEXTAREA
widget type: text area
void n_gui_window_set_autofit(N_GUI_CTX *ctx, int window_id, int autofit_flags, float border)
Configure auto-fit behavior for a dialog window.
void n_gui_scrollbar_set_pos(N_GUI_CTX *ctx, int widget_id, double pos)
set the scroll position of a scrollbar widget
void n_gui_dropmenu_clear_dynamic(N_GUI_CTX *ctx, int widget_id)
Remove all dynamic entries (keep static ones)
The top-level GUI context that holds all windows.
Owner-draw custom widget data: a paint callback plus its user pointer.
one data grid column definition
data grid specific data: a sortable column table
dropdown menu specific data
A single entry in a dropdown menu (static or dynamic)
hex viewer specific data: a read-only byte dump
image widget specific data
a single row in the KV table
key-value table built from textareas, checkboxes, and buttons
static text label specific data
a single item in a list/radio/combo widget
A saved window position retained for a window not yet created at load time (see N_GUI_CTX::pending_la...
Saved user-adjustable state for a keyed widget that did not exist when the layout was loaded (a lazil...
Progress-bar widget data (display only).
a single foldable section: a clickable header plus the member widgets it shows/hides
a vertical accordion of foldable sections inside one window; folding hides a section's widgets and re...
split pane specific data: a draggable divider between two regions
Global style holding every configurable layout constant.
syntax view specific data: read-only highlighted text
tab panel built from toggle buttons with content window management
Titlebar button state for a window (minimize, maximize, close)
bounding box dimensions returned by n_gui_get_text_dims()
Color theme for a widget.
tree view built from an N_GUI listbox
a single node in the tree view
A pseudo window that contains widgets.
int ht_get_ptr(HASH_TABLE *table, const char *key, void **val)
get pointer at 'key' from 'table'
int destroy_ht(HASH_TABLE **table)
empty a table and destroy it
HASH_TABLE * new_ht(size_t size)
Create a hash table with the given size.
int ht_put_ptr(HASH_TABLE *table, const char *key, void *ptr, void(*destructor)(void *ptr), void *(*duplicator)(void *ptr))
put an arbitrary pointer value with given key in the targeted hash table
LIST_NODE * end
pointer to the end of the list
void * ptr
void pointer to store
LIST_NODE * start
pointer to the start of the list
size_t nb_items
number of item currently in the list
void(* destroy_func)(void *ptr)
pointer to destructor function if any, else NULL
#define UNLIMITED_LIST_ITEMS
flag to pass to new_generic_list for an unlimited number of item in the list.
int list_push(LIST *list, void *ptr, void(*destructor)(void *ptr))
Add a pointer to the end of the list.
#define list_foreach(__ITEM_, __LIST_)
ForEach macro helper, safe for node removal during iteration.
int list_unshift(LIST *list, void *ptr, void(*destructor)(void *ptr))
Add a pointer at the start of the list.
int list_destroy(LIST **list)
Empty and Free a list container.
void * remove_list_node_f(LIST *list, LIST_NODE *node)
Internal function called each time we need to get a node out of a list.
LIST * new_generic_list(size_t max_items)
Initialiaze a generic list container to max_items pointers.
Structure of a generic list node.
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
#define LOG_DEBUG
debug-level messages
#define LOG_ERR
error conditions
#define LOG_WARNING
warning conditions
int n_clipboard_set(int which, const char *text)
Own which selection and serve text to any app that requests it.
int n_clipboard_available(void)
Whether a real clipboard backend (X11 or Win32) is active on this platform.
char * n_clipboard_get(int which)
Fetch the current text of which selection from its owner.
void n_clipboard_destroy(void)
Stop the backend thread and release the display connection.
System clipboard: full X11 selection support on Linux, Win32 clipboard on Windows/MinGW.
#define N_CLIPBOARD_PRIMARY
the X11 PRIMARY selection (mouse select-to-copy / middle-click paste); a no-op on Windows,...
#define N_CLIPBOARD_CLIPBOARD
the Ctrl+C / Ctrl+V clipboard selection
static void _draw_justified_selection(ALLEGRO_FONT *font, float x, float y, float max_w, float max_h, const char *text, int sel_start, int sel_end, ALLEGRO_COLOR sel_color)
helper: draw selection highlight rectangles over justified/wrapped text.
static int _n_gui_tree_hit_row(N_GUI_TREE *tree, float mx, float my, int *out_node_idx, int *out_drop_pos)
Hit-test the mouse against the listbox's visible rows and fill the out params.
static size_t _textarea_pos_from_mouse(const N_GUI_TEXTAREA_DATA *td, ALLEGRO_FONT *font, float mx, float my, float ax, float ay, float widget_w, float widget_h, float pad, float scrollbar_size)
helper: find the byte position in a textarea closest to the given mouse coordinates (mx,...
static float _text_w(ALLEGRO_FONT *font, const char *text)
helper: get the advance width of text.
static void _draw_rows_scrollbar(float ax, float ay, float w, float h, int nb_rows, int visible, int scroll_offset, const N_GUI_STYLE *style, N_GUI_THEME *theme)
draw a row-indexed vertical scrollbar (shared by hexview, syntaxview and datagrid) at the right edge ...
static void _n_gui_sectionlist_header_clicked(int widget_id, void *user_data)
static void _register_widget(N_GUI_CTX *ctx, N_GUI_WIDGET *w)
helper: register a widget in the hash table
static float _json_get_float(cJSON *parent, const char *name, float fallback)
helper: read a float from JSON, return fallback if missing
static N_GUI_WINDOW * _find_focused_window(N_GUI_CTX *ctx)
helper: find the window containing a focused widget
static ALLEGRO_COLOR _bg_for_state(const N_GUI_THEME *t, int state)
helper: pick colour based on widget state
static void _n_gui_tree_listbox_selected(int widget_id, int index, int selected, void *user_data)
#define _N_GUI_TREE_DRAG_THRESHOLD_PX
pixels of mouse movement before a press becomes a drag
static void _draw_text_truncated(ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x, float y, float max_w, const char *text)
helper: draw text truncated to a maximum pixel width.
static int _native_monitor_info(ALLEGRO_DISPLAY *display, ALLEGRO_MONITOR_INFO *info)
helper: the monitor rectangle a native window sits on.
static void _syntax_run(ALLEGRO_FONT *font, ALLEGRO_COLOR col, float *cx, float y, const char *s, int len)
draw a run of text and advance the pen x by its width
#define N_GUI_MEAS_KEY_MAX
static float _tb_buttons_area_width(const N_GUI_WINDOW *win, const N_GUI_STYLE *style)
compute the total width consumed by enabled titlebar buttons (0 if none/frameless)
static void _draw_textarea(N_GUI_WIDGET *wgt, float ox, float oy, ALLEGRO_FONT *default_font, N_GUI_STYLE *style)
draw a textarea widget
static ALLEGRO_DISPLAY * _event_display(const ALLEGRO_EVENT *event)
helper: the display an event originates from, or NULL when the event carries no display (timer,...
static void _normalize_crlf(char *s)
helper: strip CR from a string in-place, normalizing CRLF to LF.
static void _draw_progressbar(N_GUI_WIDGET *wgt, float ox, float oy, ALLEGRO_FONT *default_font, N_GUI_STYLE *style)
draw a sortable data grid: fixed header row plus scrollable data rows
static int _is_focusable_type(int type)
helper: check if a widget type is focusable via Tab navigation
static void _draw_slider(N_GUI_WIDGET *wgt, float ox, float oy, ALLEGRO_FONT *default_font, N_GUI_STYLE *style)
draw a slider widget (horizontal or vertical)
static void _draw_image(N_GUI_WIDGET *wgt, float ox, float oy)
draw an image widget
static int _zorder_group(const N_GUI_WINDOW *w)
static void _draw_themed_rect(N_GUI_THEME *t, int state, float x, float y, float w, float h, int rounded)
draw a themed rectangle or rounded rectangle.
static void _draw_dropmenu(N_GUI_WIDGET *wgt, float ox, float oy, ALLEGRO_FONT *default_font, const N_GUI_STYLE *style)
draw a dropdown menu button (closed state)
static float _label_content_height(const char *text, ALLEGRO_FONT *font, float max_w)
helper: compute the total content height of justified/wrapped label text, in pixels.
static int _syntax_js_regex_possible(char c)
whether a '/' may start a regex literal after last significant char c (start of line,...
static N_GUI_WINDOW * _find_widget_window(N_GUI_CTX *ctx, int wgt_id, float *ox, float *oy)
helper: find the parent window of a widget by id, returning the window's content origin (accounting f...
static void _tb_button_action(N_GUI_CTX *ctx, N_GUI_WINDOW *win, int btn_type)
Dispatch a titlebar button action, invoke the user callback if set, otherwise fall back to the built-...
static ALLEGRO_BITMAP * _select_state_bitmap(int state, ALLEGRO_BITMAP *normal_bmp, ALLEGRO_BITMAP *hover_bmp, ALLEGRO_BITMAP *active_bmp)
helper: select per-state bitmap with fallback chain.
static int _datagrid_resize_hover(N_GUI_CTX *ctx, float px, float py)
Whether the pointer at (px,py) rests on a datagrid column-resize border: the header row of a visible ...
static void _native_drag_begin(N_GUI_WINDOW *win)
helper: anchor an own-chrome window's title bar drag on the desktop cursor.
static float _label_text_origin_x(const N_GUI_LABEL_DATA *lb, ALLEGRO_FONT *font, float ax, float wgt_w, float win_w, float wgt_x, float label_padding)
helper: compute the screen-space x origin where label text starts, accounting for alignment.
static int _syntaxview_offset_from_mouse(const N_GUI_SYNTAXVIEW_DATA *yd, ALLEGRO_FONT *font, float mx, float my, float ax, float ay, float pad)
Map a mouse position over a syntax view to a byte offset into its text.
static void _set_clipping_rect_transformed(int wx, int wy, int ww, int wh)
helper: set clipping rectangle in world space, transforming to screen space.
static int _n_gui_tree_node_visible(N_GUI_TREE *tree, int node_index)
static void _n_gui_kv_apply_layout(N_GUI_KVTABLE *table)
static void _datagrid_ensure_sel(N_GUI_DATAGRID_DATA *gd)
helper: ensure the per-row selection array exists, sized to rows_cap
static void _draw_dropmenu_panel(N_GUI_CTX *ctx)
draw the dropdown menu panel overlay (called after all windows)
static int _win_on_pass(const N_GUI_CTX *ctx, const N_GUI_WINDOW *win)
helper: whether a window takes part in the pass currently being processed or drawn.
static void _draw_widget(N_GUI_WIDGET *wgt, float ox, float oy, ALLEGRO_FONT *default_font, float win_w, N_GUI_STYLE *style)
static int _native_own_chrome(const N_GUI_WINDOW *win)
helper: whether a window is detached AND keeps drawing its own chrome (N_GUI_DETACH_OWN_CHROME).
static ALLEGRO_DISPLAY * _ctx_io_display(const N_GUI_CTX *ctx)
helper: the display to use for clipboard and mouse-cursor calls.
static void _window_update_content_size(N_GUI_WINDOW *win, ALLEGRO_FONT *default_font)
helper: recompute content extents for a window (for scrollbar support)
static void _n_gui_window_capture_normalized(const N_GUI_CTX *ctx, N_GUI_WINDOW *win)
capture normalized coords for a window and its widgets from current absolutes
static void _draw_textarea_placeholder(const N_GUI_TEXTAREA_DATA *td, const N_GUI_WIDGET *wgt, ALLEGRO_FONT *font, float tx, float ty)
draw a textarea's placeholder/hint at (tx,ty), dimmed, while the field is empty; a no-op once any tex...
static int _shape_rounded(const N_GUI_STYLE *style, int widget_shape)
resolve whether a shape-aware widget draws rounded: the global shape_mode override (style->shape_mode...
static float _min_thickness(float requested)
helper: compute minimum line thickness so it stays >= 1 physical pixel.
static float _scrollbar_calc_scroll(float mouse, float track_start, float track_length, float viewport, float content, float thumb_min)
helper: compute scroll position from mouse coordinate using thumb-aware math.
static float _tb_btn_resolved_size(const N_GUI_WINDOW *win, const N_GUI_STYLE *style)
return the effective titlebar button size (0 = auto from titlebar_h)
static int _syntax_js_regex_kw(const char *s, int n)
whether the n bytes at s are a keyword after which an expression (and therefore a regex literal) can ...
static void _textarea_clear_selection(N_GUI_TEXTAREA_DATA *td)
clear the selection (set both anchors to cursor_pos)
static void _release_native_window(N_GUI_CTX *ctx, N_GUI_WINDOW *win)
forward declaration: unregister and destroy a window's native display, leaving the window's geometry ...
static int _text_line_count(const char *s)
helper: destroy a single widget (called by list destructor)
static void _draw_scrollbar(N_GUI_WIDGET *wgt, float ox, float oy, const N_GUI_STYLE *style)
draw a scrollbar widget
static void _textarea_sel_range(const N_GUI_TEXTAREA_DATA *td, size_t *lo, size_t *hi)
get the ordered selection range (lo, hi)
static FILE * _gui_fopen_write(const char *path, const char *mode)
static void _draw_widget_vscrollbar(float area_x, float area_y, float area_w, float view_h, float content_h, float scroll_y, N_GUI_STYLE *style)
helper: draw a mini vertical scrollbar inside a widget.
static char * _ngui_clip_get(ALLEGRO_DISPLAY *display, int which)
static void _sort_windows_by_zorder(N_GUI_CTX *ctx)
Sort windows list by z-order: ALWAYS_BEHIND first, then FIXED (by z_value), then NORMAL,...
static void _draw_custom(N_GUI_WIDGET *wgt, float ox, float oy, ALLEGRO_FONT *default_font)
draw a single widget.
static ALLEGRO_COLOR _color_with_alpha(ALLEGRO_COLOR c, float a)
Helper: return a copy of c with the given alpha (0..1).
static int _justified_char_at_pos(const char *text, ALLEGRO_FONT *font, float max_w, float text_x, float text_y, float scroll_y, float click_mx, float click_my)
helper: find the byte offset in justified text closest to a click position.
static float _textarea_content_height(const N_GUI_TEXTAREA_DATA *td, ALLEGRO_FONT *font, float widget_w, float pad)
helper: compute the total content height of multiline textarea text (with line-wrap),...
static N_GUI_MEAS_ENTRY * _ngui_meas_slot(ALLEGRO_FONT *font, const char *text, size_t len)
find (or claim) the cache slot for (font, text[len]).
static int _tooltip_widget_at(N_GUI_CTX *ctx, float px, float py)
helper: top-most visible tooltip-bearing widget under a gui-space point (-1 = none)
static int _textarea_handle_key(N_GUI_WIDGET *wgt, ALLEGRO_EVENT *ev, ALLEGRO_FONT *font, float pad, float sb_size, N_GUI_CTX *ctx)
handle textarea key input.
static int _cell_is_num(const char *s)
true when every character of a non-empty string is a decimal digit
static void _ngui_publish_primary_selection(N_GUI_CTX *ctx)
publish the active text selection (syntax view, label, or focused textarea) to the X11 PRIMARY select...
static void _draw_combobox(N_GUI_WIDGET *wgt, float ox, float oy, ALLEGRO_FONT *default_font, const N_GUI_STYLE *style)
draw a combobox widget (closed state)
static int _items_grow(N_GUI_LISTITEM **items, const size_t *nb, size_t *cap)
helper: ensure items array has room for one more, returns 1 on success
static void _draw_syntaxview(N_GUI_WIDGET *wgt, float ox, float oy, ALLEGRO_FONT *default_font, N_GUI_STYLE *style)
static int _scrollbar_calc_scroll_int(float mouse, float track_start, float track_length, int visible_items, int total_items, float thumb_min)
helper: integer variant of _scrollbar_calc_scroll for item-based widgets.
static void _draw_hexview(N_GUI_WIDGET *wgt, float ox, float oy, ALLEGRO_FONT *default_font, N_GUI_STYLE *style)
draw a read-only hex viewer: offset, hex bytes, and an ASCII gutter
static void _draw_tooltip(N_GUI_CTX *ctx)
helper: draw the hover-tooltip bubble for the currently armed tooltip widget, but ONLY in the render ...
static void _datagrid_apply_columns(N_GUI_CTX *ctx, int widget_id, int ncols, const int *order, const int *visible, const float *width)
static void _destroy_widget(void *ptr)
static size_t _datagrid_phys(const N_GUI_DATAGRID_DATA *gd, size_t dp)
physical column index shown at display position dp (identity when no order).
static void _draw_datagrid(N_GUI_WIDGET *wgt, float ox, float oy, ALLEGRO_FONT *default_font, N_GUI_STYLE *style)
static int _point_in_rect(float px, float py, float rx, float ry, float rw, float rh)
helper: test if point is inside a rectangle
static ALLEGRO_COLOR _text_for_state(const N_GUI_THEME *t, int state)
static int _cell_cmp(const char *a, const char *b)
compare two cell strings: numerically when both are integers, else case-insensitive
#define N_GUI_ANIM_TAIL_SEC
static double _clamp(double v, double lo, double hi)
helper: clamp a double between lo and hi
static int _n_gui_tree_listbox_bounds(N_GUI_TREE *tree, float *out_x, float *out_y, float *out_w, float *out_h, float *out_item_area_w, float *out_inset, float *out_item_h, int *out_scroll_off)
Return the listbox's absolute (screen-space) bounds and geometry via out params.
static void _textarea_delete_selection(N_GUI_WIDGET *wgt)
delete the currently selected text, move cursor to selection start
static int _json_get_int(cJSON *parent, const char *name, int fallback)
helper: read an int from JSON, return fallback if missing
static N_GUI_WIDGET * _new_widget(N_GUI_CTX *ctx, int type, float x, float y, float w, float h)
helper: allocate and initialise a base widget
static int _tb_button_rect(const N_GUI_WINDOW *win, const N_GUI_STYLE *style, int btn_type, float *out_x, float *out_y, float *out_w, float *out_h)
compute the absolute rect for a titlebar button.
static void _draw_tb_buttons(N_GUI_WINDOW *win, const N_GUI_STYLE *style)
draw the titlebar buttons for a window
static double _slider_snap_value(double val, double min_val, double max_val, double step)
helper: snap a slider value to the nearest valid step from min_val.
static void _draw_radiolist(N_GUI_WIDGET *wgt, float ox, float oy, ALLEGRO_FONT *default_font, const N_GUI_STYLE *style)
draw a radiolist widget
static void _list_panel_highlight_step(int *highlight, int *scroll, int nb, int max_visible, int delta, int fallback)
helper: move an open list panel's highlight cursor (combobox / dropmenu) by delta items and scroll th...
static void _draw_bitmap_scaled(ALLEGRO_BITMAP *bmp, float dx, float dy, float dw, float dh, int mode)
helper: draw a bitmap into a rectangle, respecting the given scale mode.
static void _draw_checkbox(N_GUI_WIDGET *wgt, float ox, float oy, ALLEGRO_FONT *default_font, N_GUI_STYLE *style)
draw a checkbox widget
static void _draw_combobox_dropdown(N_GUI_CTX *ctx)
static void _n_gui_kv_add_clicked(int widget_id, void *user_data)
static void _n_gui_tab_button_clicked(int widget_id, void *user_data)
static N_GUI_DATAGRID_DATA * _datagrid_data(N_GUI_CTX *ctx, int widget_id)
fetch a data grid's column table for an API call, or NULL on a bad id.
static int _textarea_has_selection(const N_GUI_TEXTAREA_DATA *td)
return 1 if the textarea has an active selection
static bool _tooltip_line_cb(int line_num, const char *line, int size, void *extra)
helper: al_do_multiline_text callback that just counts the wrapped lines.
static ALLEGRO_COLOR _border_for_state(const N_GUI_THEME *t, int state)
static N_GUI_MEAS_ENTRY _ngui_meas_cache[1024u]
static float _syntax_prefix_w(ALLEGRO_FONT *font, const char *s, int n)
pixel width of the first n bytes of s in font (bounded copy).
#define _N_GUI_WIN_STATE_PERSIST_MASK
static void _ngui_clip_set(ALLEGRO_DISPLAY *display, int which, const char *text)
static LIST_NODE * _find_window_node(N_GUI_CTX *ctx, int window_id)
helper: find a window node in the context list by id
static void _draw_text_justified(ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x, float y, float max_w, float max_h, const char *text)
helper: draw justified text within a given width, with multi-line word wrapping.
static int _dropmenu_entries_grow(N_GUI_DROPMENU_ENTRY **entries, const size_t *nb, size_t *cap)
helper: ensure dropmenu entries array has room for one more
static void _draw_listbox(N_GUI_WIDGET *wgt, float ox, float oy, ALLEGRO_FONT *default_font, N_GUI_STYLE *style)
draw a listbox widget
static float _dropdown_panel_y(const N_GUI_CTX *ctx, float widget_top, float widget_bottom, float panel_h, int expand_up)
draw the combobox dropdown overlay (called after all windows)
static void _draw_splitpane(N_GUI_WIDGET *wgt, float ox, float oy)
draw a split pane: only the divider bar is painted (the app fills the two regions with its own widget...
static void _textarea_paste_clip(N_GUI_WIDGET *wgt, N_GUI_TEXTAREA_DATA *td, const char *clip)
insert clipboard text at the cursor, replacing any selection.
static int _textarea_copy_to_clipboard(const N_GUI_TEXTAREA_DATA *td, ALLEGRO_DISPLAY *display)
copy selected text to clipboard.
static void _slider_update_from_mouse(N_GUI_WIDGET *wgt, float mx, float my, float win_x, float win_content_y)
handle slider drag (horizontal or vertical)
static void _draw_button(N_GUI_WIDGET *wgt, float ox, float oy, ALLEGRO_FONT *default_font, const N_GUI_STYLE *style)
draw a button widget
static int _pointer_over_window(const N_GUI_CTX *ctx, float px, float py)
helper: is the pointer over any open window that takes part in the current pass? O(windows) and used ...
static int _datagrid_ensure_colors(N_GUI_DATAGRID_DATA *gd)
helper: ensure the per-row tint arrays exist, sized to rows_cap (rows start untinted); returns 1 when...
static void _scrollbar_update_from_mouse(N_GUI_WIDGET *wgt, float mx, float my, float win_x, float win_content_y, const N_GUI_STYLE *style)
handle scrollbar drag
static void _draw_window(N_GUI_WINDOW *win, ALLEGRO_FONT *default_font, N_GUI_STYLE *style)
draw a window chrome + its widgets
static float _win_tbh(const N_GUI_WINDOW *win)
helper: effective title bar height (0 for frameless windows)
#define N_GUI_KEY_PRESS_FLASH_SEC
static void _compute_gui_bounds(N_GUI_CTX *ctx)
helper: compute the bounding box of all open windows
static void _draw_label(N_GUI_WIDGET *wgt, float ox, float oy, ALLEGRO_FONT *default_font, float win_w, N_GUI_STYLE *style)
static void _n_gui_widget_capture_normalized(const N_GUI_WINDOW *win, N_GUI_WIDGET *wgt)
capture normalized coords for a single widget relative to its parent window
static void _destroy_window(void *ptr)
helper: destroy a single window (called by list destructor)
static ALLEGRO_COLOR _json_get_color(cJSON *parent, const char *name, ALLEGRO_COLOR fallback)
helper: read an RGBA colour from a JSON array [r,g,b,a]
const ALLEGRO_FONT * font
static int _utf8_char_len(unsigned char c)
return the byte length of a UTF-8 character from its lead byte
static void _syntax_draw_line(ALLEGRO_FONT *font, N_GUI_THEME *th, float x, float y, const char *s, int n, int mode, int line_idx, int in_headers)
draw one text line with mode-specific highlighting starting at (x,y)
static void _json_add_color(cJSON *parent, const char *name, ALLEGRO_COLOR c)
helper: add an RGBA colour as a JSON array [r,g,b,a] (0-255)
static void _native_apply_minimised(N_GUI_WINDOW *win)
helper: mirror an own-chrome window's minimised state onto its OS window by shrinking the display to ...
static void _syntaxview_ensure_lines(N_GUI_SYNTAXVIEW_DATA *yd)
forward declaration: (re)build a syntaxview's cached line count and headers-end index when stale.
static int _label_char_at_x(const N_GUI_LABEL_DATA *lb, ALLEGRO_FONT *font, float click_x)
draw a label widget.
static void _apply_pending_widget(N_GUI_CTX *ctx, const char *title, const N_GUI_WIDGET *wgt)
static void _draw_cols_scrollbar(float ax, float bar_y, float track_w, float content_w, float h_scroll, const N_GUI_STYLE *style, N_GUI_THEME *theme)
draw a horizontal scrollbar along the bottom edge of a widget: track_w is the width of the scrollable...
static void _text_dims(ALLEGRO_FONT *font, const char *text, int *x, int *y, int *w, int *h)
helper: memoized al_get_text_dimensions (bounding box x/y/w/h).
static void _n_gui_kv_remove_clicked(int widget_id, void *user_data)
static int _syntax_js_keyword(const char *s, int n)
whether the n bytes at s form a JavaScript keyword or literal name
#define N_GUI_MEAS_CACHE_SIZE
static void _n_gui_sectionlist_set_header_label(N_GUI_SECTIONLIST *sl, int idx)
static void _datagrid_hmetrics(const N_GUI_WIDGET *wgt, const N_GUI_DATAGRID_DATA *gd, ALLEGRO_FONT *font, const N_GUI_STYLE *style, float *content_w, float *pane_w, int *need_hsb)
Compute the datagrid horizontal-scroll metrics used identically by the draw path and the mouse handle...
static void _clear_syntaxview_selection(N_GUI_CTX *ctx)
drop any active syntax-view text selection (used when focus moves to another selectable widget,...
static int _utf8_encode(int cp, char *out)
encode a Unicode code point into UTF-8, return the number of bytes written (0 on error)
GUI system: buttons, sliders, text areas, checkboxes, scrollbars, dropdown menus, windows.