diff -r 86d3a45dc928 -r 24677835f298 ui/win32/menu.c --- a/ui/win32/menu.c Wed Dec 31 10:06:15 2025 +0100 +++ b/ui/win32/menu.c Wed Dec 31 10:34:29 2025 +0100 @@ -66,7 +66,7 @@ } } -static void menu_item_clicked(UiObject *obj, UiMenuItem *item) { +static void menu_item_clicked(UiObject *obj, uint64_t id, UiMenuItem *item) { UiEvent event; event.obj = obj; event.window = obj->window; @@ -92,8 +92,76 @@ cxMapPut(obj->ctx->command_map, id, &cmd); } +static void menu_stateitem_update(UiStateMenuItem *item) { + MENUITEMINFO mi = { 0 }; + mi.cbSize = sizeof(mi); + mi.fMask = MIIM_STATE; + mi.fState = item->state ? MFS_CHECKED : MFS_UNCHECKED; + SetMenuItemInfo(item->menu, item->id, FALSE, &mi); +} + +static void menu_checkitem_clicked(UiObject *obj, uint64_t id, UiStateMenuItem *item) { + item->state = !item->state; + menu_stateitem_update(item); + + UiEvent event; + event.obj = obj; + event.window = obj->window; + event.document = obj->ctx->document; + event.eventdata = NULL; + event.eventdatatype = 0; + event.intval = 0; + event.set = 0; + if (item->onchange) { + item->onchange(&event, item->userdata); + } + + if (item->var) { + UiInteger *i = item->var->value; + ui_notify_evt(i->observers, &event); + } +} + void ui_add_menu_checkitem(HMENU parent, int pos, UiMenuItemI *item, UiObject *obj) { + uint64_t id = ++obj->ctx->command_id_counter; + UiMenuCheckItem *i = (UiMenuCheckItem*)item; + AppendMenu(parent, MF_STRING, id, i->label); + + // create an UiStateMenuItem with the same lifetime as the UiObject + UiStateMenuItem *sitem = ui_malloc(obj->ctx, sizeof(UiStateMenuItem)); + memset(sitem, 0, sizeof(UiStateMenuItem)); + sitem->obj = obj; + sitem->menu = parent; + sitem->id = id; + sitem->onchange = i->callback; + sitem->userdata = i->userdata; + sitem->var = uic_widget_var(obj->ctx, obj->ctx, NULL, i->varname, UI_VAR_INTEGER); + // bind to var + if (sitem->var) { + UiInteger *v = sitem->var->value; + sitem->state = v->value != 0; + v->obj = sitem; + v->get = ui_checkitem_get; + v->set = ui_checkitem_set; + } + + // register command id + UiCommand cmd; + cmd.callback = (ui_command_func)menu_checkitem_clicked; + cmd.userdata = sitem; + cxMapPut(obj->ctx->command_map, id, &cmd); + + menu_stateitem_update(sitem); +} + +int64_t ui_checkitem_get(UiInteger *i) { + return i->value; +} + +void ui_checkitem_set(UiInteger *i, int64_t value) { + i->value = value; + menu_stateitem_update(i->obj); } void ui_add_menu_radioitem(HMENU parent, int pos, UiMenuItemI *item, UiObject *obj) {