Skip to content

Commit 21db843

Browse files
authored
Merge pull request #5 from sysprog21/dropdown
Move dropdown state from static to per-context
2 parents 450667a + 5c5c096 commit 21db843

File tree

2 files changed

+27
-31
lines changed

2 files changed

+27
-31
lines changed

src/input.c

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1438,19 +1438,7 @@ bool iui_radio(iui_context *ctx,
14381438
* TextField-style component that reveals a menu of options
14391439
*/
14401440

1441-
/* Static state for dropdown menu (one active at a time) */
1442-
/* Dropdown menu state - single instance per UI context.
1443-
* Thread-safety: This static state assumes single-threaded UI rendering.
1444-
* Each thread/context should have its own UI instance. If multi-context
1445-
* support is needed, move this state into iui_context.
1446-
*/
1447-
static struct {
1448-
bool open; /* menu is visible */
1449-
float x, y, width; /* menu position and width */
1450-
int hovered_index; /* currently hovered option */
1451-
int frames_since_open; /* frame counter for click protection */
1452-
const int *selected; /* pointer to track which dropdown is active */
1453-
} s_dropdown = {0};
1441+
14541442

14551443
bool iui_dropdown(iui_context *ctx, const iui_dropdown_options *options)
14561444
{
@@ -1481,8 +1469,8 @@ bool iui_dropdown(iui_context *ctx, const iui_dropdown_options *options)
14811469
};
14821470

14831471
/* Check if this dropdown's menu is open */
1484-
bool is_open =
1485-
s_dropdown.open && (s_dropdown.selected == options->selected_index);
1472+
bool is_open = ctx->dropdown.open &&
1473+
(ctx->dropdown.selected == options->selected_index);
14861474

14871475
/* Get field interaction state */
14881476
iui_state_t state =
@@ -1560,36 +1548,36 @@ bool iui_dropdown(iui_context *ctx, const iui_dropdown_options *options)
15601548
if (!options->disabled && state == IUI_STATE_PRESSED) {
15611549
if (is_open) {
15621550
/* Close menu */
1563-
s_dropdown.open = false;
1551+
ctx->dropdown.open = false;
15641552
} else {
15651553
/* Open menu */
1566-
s_dropdown.open = true;
1567-
s_dropdown.x = field_rect.x;
1568-
s_dropdown.y = field_rect.y + field_h;
1569-
s_dropdown.width = field_rect.width;
1570-
s_dropdown.hovered_index = selected;
1571-
s_dropdown.frames_since_open = 0;
1572-
s_dropdown.selected = options->selected_index;
1554+
ctx->dropdown.open = true;
1555+
ctx->dropdown.x = field_rect.x;
1556+
ctx->dropdown.y = field_rect.y + field_h;
1557+
ctx->dropdown.width = field_rect.width;
1558+
ctx->dropdown.hovered_index = selected;
1559+
ctx->dropdown.frames_since_open = 0;
1560+
ctx->dropdown.selected = options->selected_index;
15731561
}
15741562
}
15751563

15761564
/* Draw menu if open */
15771565
if (is_open) {
15781566
/* Capture frame count BEFORE incrementing for click protection.
1579-
* This ensures the first frame after opening (frames_active == 0)
1567+
* This ensures that first frame after opening (frames_active == 0)
15801568
* blocks clicks, preventing click-through from the field that opened
1581-
* this menu.
1569+
* menu.
15821570
*/
1583-
int frames_active = s_dropdown.frames_since_open++;
1571+
int frames_active = ctx->dropdown.frames_since_open++;
15841572

15851573
/* Calculate menu height (capped at max) */
15861574
float item_h = IUI_DROPDOWN_ITEM_HEIGHT;
15871575
float menu_h = options->option_count * item_h;
15881576
if (menu_h > IUI_DROPDOWN_MENU_MAX_HEIGHT)
15891577
menu_h = IUI_DROPDOWN_MENU_MAX_HEIGHT;
15901578

1591-
iui_rect_t menu_rect = {s_dropdown.x, s_dropdown.y, s_dropdown.width,
1592-
menu_h};
1579+
iui_rect_t menu_rect = {ctx->dropdown.x, ctx->dropdown.y,
1580+
ctx->dropdown.width, menu_h};
15931581

15941582
/* Begin modal for menu */
15951583
iui_begin_modal(ctx, "dropdown_menu_modal");
@@ -1612,7 +1600,7 @@ bool iui_dropdown(iui_context *ctx, const iui_dropdown_options *options)
16121600
/* Update hovered index */
16131601
if (item_state == IUI_STATE_HOVERED ||
16141602
item_state == IUI_STATE_PRESSED) {
1615-
s_dropdown.hovered_index = i;
1603+
ctx->dropdown.hovered_index = i;
16161604
}
16171605

16181606
/* Draw selection/hover background */
@@ -1640,7 +1628,7 @@ bool iui_dropdown(iui_context *ctx, const iui_dropdown_options *options)
16401628
if (frames_active >= 1 && item_state == IUI_STATE_PRESSED) {
16411629
*options->selected_index = i;
16421630
selection_changed = (i != selected);
1643-
s_dropdown.open = false;
1631+
ctx->dropdown.open = false;
16441632
iui_close_modal(ctx);
16451633
}
16461634
}
@@ -1652,7 +1640,7 @@ bool iui_dropdown(iui_context *ctx, const iui_dropdown_options *options)
16521640
bool mouse_pressed = (ctx->mouse_pressed & IUI_MOUSE_LEFT);
16531641

16541642
if (!mouse_in_menu && !mouse_in_field && mouse_pressed) {
1655-
s_dropdown.open = false;
1643+
ctx->dropdown.open = false;
16561644
iui_close_modal(ctx);
16571645
}
16581646
}

src/internal.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,14 @@ struct iui_context {
440440
int menu_item_index;
441441
float menu_prev_height;
442442

443+
struct {
444+
bool open;
445+
float x, y, width;
446+
int hovered_index;
447+
int frames_since_open;
448+
const int *selected;
449+
} dropdown;
450+
443451
/* COOL PATH - Scroll State */
444452
iui_scroll_state *active_scroll;
445453
iui_scroll_state *scroll_dragging;

0 commit comments

Comments
 (0)