--- a/ui/gtk/menu.c Mon Jun 17 21:20:58 2024 +0200 +++ b/ui/gtk/menu.c Sun Sep 29 13:32:51 2024 +0200 @@ -42,8 +42,7 @@ #include <cx/linked_list.h> #include <cx/array_list.h> -#if UI_GTK2 || UI_GTK3 - +#if GTK_MAJOR_VERSION <= 3 static ui_menu_add_f createMenuItem[] = { /* UI_MENU */ add_menu_widget, @@ -501,4 +500,194 @@ } } -#endif /* UI_GTK2 || UI_GTK3 */ +#endif /* GTK_MAJOR_VERSION <= 3 */ + + + +#if GTK_MAJOR_VERSION >= 4 + + + +static ui_gmenu_add_f createMenuItem[] = { + /* UI_MENU */ ui_gmenu_add_menu, + /* UI_MENU_ITEM */ ui_gmenu_add_menuitem, + /* UI_MENU_CHECK_ITEM */ ui_gmenu_add_checkitem, + /* UI_MENU_RADIO_ITEM */ ui_gmenu_add_radioitem, + /* UI_MENU_ITEM_LIST */ ui_gmenu_add_menuitem_list, + /* UI_MENU_CHECKITEM_LIST */ ui_gmenu_add_menuitem_list, + /* UI_MENU_RADIOITEM_LIST */ ui_gmenu_add_menuitem_list, + /* UI_MENU_SEPARATOR */ ui_gmenu_add_menuseparator +}; + +void ui_gmenu_add_menu_items(GMenu *parent, int i, UiMenu *menu, UiObject *obj) { + UiMenuItemI *it = menu->items_begin; + int index = 0; + while(it) { + createMenuItem[it->type](parent, index, it, obj); + it = it->next; + index++; + } +} + +void ui_gmenu_add_menu(GMenu *parent, int index, UiMenuItemI *item, UiObject *obj) { + UiMenu *mi = (UiMenu*)item; + GMenu *menu = g_menu_new(); + ui_gmenu_add_menu_items(menu, 0, mi, obj); + g_menu_append_submenu(parent, mi->label, G_MENU_MODEL(menu)); +} + +void ui_gmenu_add_menuitem(GMenu *parent, int index, UiMenuItemI *item, UiObject *obj) { + UiMenuItem *i = (UiMenuItem*)item; + + GSimpleAction *action = g_simple_action_new(item->id, NULL); + g_action_map_add_action(obj->ctx->action_map, G_ACTION(action)); + + if(i->callback != NULL) { + UiEventData *event = malloc(sizeof(UiEventData)); + event->obj = obj; + event->userdata = i->userdata; + event->callback = i->callback; + event->value = 0; + event->customdata = NULL; + + g_signal_connect( + action, + "activate", + G_CALLBACK(ui_activate_event_wrapper), + event); + g_signal_connect( + obj->widget, + "destroy", + G_CALLBACK(ui_destroy_userdata), + event); + } + + char action_name[32]; + snprintf(action_name, 32, "win.%s", item->id); + g_menu_append(parent, i->label, action_name); +} + +void ui_gmenu_add_menuseparator(GMenu *p, int index, UiMenuItemI *item, UiObject *obj) { + +} + +void ui_gmenu_add_checkitem(GMenu *p, int index, UiMenuItemI *item, UiObject *obj) { + UiMenuCheckItem *checkitem = (UiMenuCheckItem*)item; + + // TODO +} + +void ui_gmenu_add_radioitem(GMenu *p, int index, UiMenuItemI *item, UiObject *obj) { + +} + +void ui_gmenu_add_menuitem_list(GMenu *p, int index, UiMenuItemI *item, UiObject *obj) { + UiMenuItemList *il = (UiMenuItemList*)item; + + const CxAllocator *a = obj->ctx->allocator; + + UiActiveGMenuItemList *ls = cxMalloc( + a, + sizeof(UiActiveGMenuItemList)); + + ls->object = obj; + ls->menu = p; + ls->index = index; + ls->oldcount = 0; + ls->getvalue = il->getvalue; + + UiVar* var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST); + ls->var = var; + UiList *list = var->value; + + ls->callback = il->callback; + ls->userdata = il->userdata; + + list->observers = ui_add_observer( + list->observers, + (ui_callback)ui_update_gmenu_item_list, + ls); + + GSimpleAction *action = g_simple_action_new(item->id, g_variant_type_new("i")); + g_action_map_add_action(obj->ctx->action_map, G_ACTION(action)); + snprintf(ls->action, 32, "win.%s", item->id); + + + UiEventData *event = malloc(sizeof(UiEventData)); + event->obj = obj; + event->userdata = il->userdata; + event->callback = il->callback; + event->customdata = var; + event->value = 0; + + g_signal_connect( + action, + "activate", + G_CALLBACK(ui_menu_list_item_activate_event_wrapper), + event); + g_signal_connect( + obj->widget, + "destroy", + G_CALLBACK(ui_destroy_userdata), + event); + + ui_update_gmenu_item_list(NULL, ls); +} + +void ui_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEventData *event) { + int intval = event->value; + if(parameter && g_variant_is_of_type(parameter, G_VARIANT_TYPE_INT32)) { + intval = g_variant_get_int32(parameter); + } + + UiEvent evt; + evt.obj = event->obj; + evt.window = event->obj->window; + evt.document = event->obj->ctx->document; + evt.eventdata = event->customdata; + evt.intval = intval; + event->callback(&evt, event->userdata); +} + +void ui_menu_list_item_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEventData *event) { + int index = g_variant_get_int32(parameter); + UiVar *var = event->customdata; + UiList *list = var->value; + + UiEvent evt; + evt.obj = event->obj; + evt.window = event->obj->window; + evt.document = event->obj->ctx->document; + evt.eventdata = ui_list_get(list, index); + evt.intval = index; + event->callback(&evt, event->userdata); + +} + +void ui_update_gmenu_item_list(UiEvent *event, UiActiveGMenuItemList *list) { + // remove old items + for(int i=0;i<list->oldcount;i++) { + g_menu_remove(list->menu, list->index); + } + UiList *ls = list->var->value; + + // add list items + ui_getvaluefunc getvalue = list->getvalue; + int i = 0; + void* elm = ui_list_first(ls); + while(elm) { + char *label = (char*) (getvalue ? getvalue(elm, 0) : elm); + + GMenuItem *item = g_menu_item_new(label, NULL); + GVariant *v = g_variant_new("i", i); + g_menu_item_set_action_and_target_value(item, list->action, v); + g_menu_insert_item(list->menu, list->index+i, item); + + elm = ui_list_next(ls); + i++; + } + + list->oldcount = i; +} + +#endif