diff -r b174e721663e -r 6d0da97105d8 ui/gtk/menu.c --- a/ui/gtk/menu.c Sat Dec 27 22:47:56 2025 +0100 +++ b/ui/gtk/menu.c Thu Jan 08 18:06:04 2026 +0100 @@ -153,29 +153,100 @@ GtkWidget *widget = gtk_check_menu_item_new_with_mnemonic(ci->label); gtk_menu_shell_append(GTK_MENU_SHELL(p), widget); - if(ci->callback) { - UiEventData *event = malloc(sizeof(UiEventData)); - event->obj = obj; - event->userdata = ci->userdata; - event->callback = ci->callback; - event->value = 0; - event->customdata = NULL; - - g_signal_connect( - widget, - "toggled", - G_CALLBACK(ui_menu_event_toggled), - event); - g_signal_connect( - widget, - "destroy", - G_CALLBACK(ui_destroy_userdata), - event); + UiVarEventData *event = malloc(sizeof(UiVarEventData)); + memset(event, 0, sizeof(UiVarEventData)); + event->obj = obj; + event->userdata = ci->userdata; + event->callback = ci->callback; + event->var = uic_widget_var(obj->ctx, obj->ctx, NULL, ci->varname, UI_VAR_INTEGER); + if(event->var) { + UiInteger *v = event->var->value; + v->obj = widget; + v->get = ui_checkitem_get; + v->set = ui_checkitem_set; + if(v->value != 0) { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), TRUE); + } + } + + g_signal_connect( + widget, + "toggled", + G_CALLBACK(ui_menu_event_toggled), + event); + g_signal_connect( + widget, + "destroy", + G_CALLBACK(ui_destroy_userdata), + event); +} + +static void ui_menu_event_radio_item_toggled(GtkRadioMenuItem *ri, UiVarEventData *event) { + UiInteger *i = event->var->value; + + UiEvent evt; + evt.obj = event->obj; + evt.window = event->obj->window; + evt.document = event->obj->ctx->document; + evt.eventdata = i; + evt.eventdatatype = i ? UI_EVENT_DATA_INTEGER_VALUE : 0; + evt.intval = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(ri)); + + if(event->callback) { + event->callback(&evt, event->userdata); + } + + if(evt.intval) { + evt.intval = ui_get(i); + ui_notify_evt(i->observers, &evt); } } +static void ui_destroy_menu_radio_item(GtkWidget *unused, UiVarEventData *event) { + if(event->customint1) { + uic_unbind_var(event->var); + } + free(event); +} + void add_radioitem_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) { - // TODO + UiMenuRadioItem *ri = (UiMenuRadioItem*)item; + + UiVar *var = uic_widget_var(obj->ctx, obj->ctx, NULL, ri->varname, UI_VAR_INTEGER); + if(!var) { + fprintf(stderr, "Error: menu radioitem varname is null\n"); + return; + } + int first = 0; + UiInteger *i = var->value; + GSList *group = i->obj; + GtkWidget *widget = gtk_radio_menu_item_new_with_label(group, ri->label); + gtk_menu_shell_append(GTK_MENU_SHELL(p), widget); + if(!group) { + i->get = ui_radioitem_get; + i->set = ui_radioitem_set; + first = 1; + } + i->obj = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(widget)); + + UiVarEventData *event = malloc(sizeof(UiVarEventData)); + memset(event, 0, sizeof(UiVarEventData)); + event->obj = obj; + event->var = var; + event->callback = ri->callback; + event->userdata = ri->userdata; + event->customint1 = first; + + g_signal_connect( + widget, + "toggled", + G_CALLBACK(ui_menu_event_radio_item_toggled), + event); + g_signal_connect( + widget, + "destroy", + G_CALLBACK(ui_destroy_menu_radio_item), + event); } static void menuitem_list_remove_binding(void *obj) { @@ -323,14 +394,23 @@ uic_set_tmp_eventdata(NULL, 0); } -void ui_menu_event_toggled(GtkCheckMenuItem *ci, UiEventData *event) { +void ui_menu_event_toggled(GtkCheckMenuItem *ci, UiVarEventData *event) { + UiInteger *i = event->var ? event->var->value : NULL; + UiEvent evt; evt.obj = event->obj; evt.window = event->obj->window; evt.document = event->obj->ctx->document; - evt.eventdata = NULL; + evt.eventdata = i; + evt.eventdatatype = i ? UI_EVENT_DATA_INTEGER_VALUE : 0; evt.intval = gtk_check_menu_item_get_active(ci); - event->callback(&evt, event->userdata); + if(event->callback) { + event->callback(&evt, event->userdata); + } + + if(i) { + ui_notify_evt(i->observers, &evt); + } } int64_t ui_checkitem_get(UiInteger *i) { @@ -341,7 +421,48 @@ void ui_checkitem_set(UiInteger *i, int64_t value) { i->value = value; - gtk_check_menu_item_set_active(i->obj, value); + gtk_check_menu_item_set_active(i->obj, (gboolean)value); +} + +int64_t ui_radioitem_get(UiInteger *value) { + int selection = 0; + GSList *ls = value->obj; + guint len = g_slist_length(ls); + int i = 0; + while(ls) { + if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(ls->data))) { + selection = len - i; + break; + } + ls = ls->next; + i++; + } + + value->value = selection; + return selection; +} + +void ui_radioitem_set(UiInteger *i, int64_t value) { + GSList *ls = i->obj; + + int len = g_slist_length(ls); + if(value > len) { + value = len; + } + int s = len - value; + int j = 0; + int unset = 1; + while(ls) { + if(j == s) { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ls->data), TRUE); + unset = 0; + break; + } + ls = ls->next; + j++; + } + + i->value = value; }