Wed, 31 Dec 2025 11:06:54 +0100
implement menu radio items (Win32)
| application/main.c | file | annotate | diff | comparison | revisions | |
| ui/win32/menu.c | file | annotate | diff | comparison | revisions | |
| ui/win32/menu.h | file | annotate | diff | comparison | revisions |
--- a/application/main.c Wed Dec 31 10:34:29 2025 +0100 +++ b/application/main.c Wed Dec 31 11:06:54 2025 +0100 @@ -1288,6 +1288,12 @@ ui_menu("File") { ui_menuitem("Open"); ui_menu_toggleitem("Test"); + ui_menuseparator(); + ui_menu_radioitem(.label = "Option 1", .varname = "radio"); + ui_menu_radioitem(.label = "Option 2", .varname = "radio"); + ui_menu_radioitem(.label = "Option 3", .varname = "radio"); + ui_menu_radioitem(.label = "Option 4", .varname = "radio"); + ui_menuseparator(); ui_menuitem("Close"); }
--- a/ui/win32/menu.c Wed Dec 31 10:34:29 2025 +0100 +++ b/ui/win32/menu.c Wed Dec 31 11:06:54 2025 +0100 @@ -28,6 +28,8 @@ #include "menu.h" +#include <cx/array_list.h> + static ui_menu_add_f createMenuItem[] = { /* UI_MENU */ ui_add_menu, /* UI_MENU_ITEM */ ui_add_menu_item, @@ -164,8 +166,94 @@ menu_stateitem_update(i->obj); } +static void menu_radioitem_clicked(UiObject *obj, uint64_t id, UiStateMenuItem *item) { + UiInteger *i = item->var->value; // UiVar is always not NULL for radio items + ui_set(i, item->index+1); + + UiEvent event; + event.obj = obj; + event.window = obj->window; + event.document = obj->ctx->document; + event.eventdata = i; + event.eventdatatype = UI_EVENT_DATA_INTEGER_VALUE; + event.intval = item->state; + event.set = ui_get_setop(); + + if (item->onchange) { + item->onchange(&event, item->userdata); + } + + event.intval = (int)ui_get(i); + ui_notify_evt(i->observers, &event); +} + void ui_add_menu_radioitem(HMENU parent, int pos, UiMenuItemI *item, UiObject *obj) { + uint64_t id = ++obj->ctx->command_id_counter; + UiMenuRadioItem *i = (UiMenuRadioItem*)item; + AppendMenu(parent, MF_STRING, id, i->label); + + UiVar *var = uic_widget_var(obj->ctx, obj->ctx, NULL, i->varname, UI_VAR_INTEGER); + if (!var) { + return; // radio item without var is useless + } + + UiInteger *v = var->value; + CxList *group = v->obj; + if (!group) { + // first radio button in this group + group = cxArrayListCreate(obj->ctx->allocator, sizeof(UiStateMenuItem), 4); + v->obj = group; + v->get = ui_radioitem_get; + v->set = ui_radioitem_set; + } + + UiStateMenuItem sitem = { 0 }; + sitem.obj = obj; + sitem.menu = parent; + sitem.id = id; + sitem.onchange = i->callback; + sitem.userdata = i->userdata; + sitem.var = var; + sitem.index = (int)cxListSize(group); + cxListAdd(group, &sitem); + + if (v->value == sitem.index+1) { + sitem.state = 1; + menu_stateitem_update(&sitem); + } + + + UiStateMenuItem *sitem_ptr = cxListAt(group, sitem.index); + // register command id + UiCommand cmd; + cmd.callback = (ui_command_func)menu_radioitem_clicked; + cmd.userdata = sitem_ptr; + cxMapPut(obj->ctx->command_map, id, &cmd); +} + +int64_t ui_radioitem_get(UiInteger *i) { + return i->value; +} + +void ui_radioitem_set(UiInteger *i, int64_t value) { + CxList *group = i->obj; + // de-select all items + CxIterator it = cxListIterator(group); + cx_foreach(UiStateMenuItem *, item, it) { + if (item->state) { + item->state = FALSE; + menu_stateitem_update(item); + } + } + + if (value > 0) { + UiStateMenuItem *item = cxListAt(group, value-1); + if (item) { + item->state = TRUE; + menu_stateitem_update(item); + } + } } void ui_add_menu_list(HMENU parent, int pos, UiMenuItemI *item, UiObject *obj) {
--- a/ui/win32/menu.h Wed Dec 31 10:34:29 2025 +0100 +++ b/ui/win32/menu.h Wed Dec 31 11:06:54 2025 +0100 @@ -44,6 +44,7 @@ UiVar *var; ui_callback onchange; void *userdata; + int index; UiBool state; } UiStateMenuItem; @@ -63,6 +64,9 @@ int64_t ui_checkitem_get(UiInteger *i); void ui_checkitem_set(UiInteger *i, int64_t value); +int64_t ui_radioitem_get(UiInteger *i); +void ui_radioitem_set(UiInteger *i, int64_t value); + #ifdef __cplusplus } #endif