# HG changeset patch # User Olaf Wintermann # Date 1732191476 -3600 # Node ID d15eca5fd8b3614618567840e8a30def322657b0 # Parent 473c03f85197c643f031d3ae34f5021c169ab9e9 implement image viewer context menus (GTK) diff -r 473c03f85197 -r d15eca5fd8b3 application/main.c --- a/application/main.c Thu Nov 21 12:04:53 2024 +0100 +++ b/application/main.c Thu Nov 21 13:17:56 2024 +0100 @@ -239,6 +239,8 @@ ui_show(obj); } +UiMenuBuilder *menubuilder; + void application_startup(UiEvent *event, void *data) { // global list UiContext *global = ui_global_context(); @@ -327,7 +329,7 @@ } ui_tab(obj, "Tab 5") { ui_button(obj, .label = "Test Button", .icon = "application-x-generic", .onclick = action_button); - ui_imageviewer(obj, .varname = "image", .style_class = "imageviewer"); + ui_imageviewer(obj, .varname = "image", .style_class = "imageviewer", .contextmenu = menubuilder); } ui_tab(obj, "Tab 6") { @@ -369,7 +371,6 @@ ui_menuitem(.label = "Test"); } - UiMenuBuilder *menubuilder; ui_contextmenu(&menubuilder) { ui_menuitem(.label = "Context Item 1"); ui_menuitem(.label = "Context Item 2"); diff -r 473c03f85197 -r d15eca5fd8b3 ui/gtk/image.c --- a/ui/gtk/image.c Thu Nov 21 12:04:53 2024 +0100 +++ b/ui/gtk/image.c Thu Nov 21 13:17:56 2024 +0100 @@ -29,6 +29,7 @@ #include "image.h" #include "container.h" +#include "menu.h" #include "../common/context.h" #include "../common/object.h" @@ -51,6 +52,7 @@ gtk_container_add(GTK_CONTAINER(eventbox), image); #else SCROLLEDWINDOW_SET_CHILD(scrolledwindow, image); + GtkWidget *eventbox = image; #endif UI_APPLY_LAYOUT1(current, args); @@ -70,6 +72,11 @@ } } + if(args.contextmenu) { + UIMENU menu = ui_create_menu(args.contextmenu, obj); + ui_widget_set_contextmenu(eventbox, menu); + } + return scrolledwindow; } diff -r 473c03f85197 -r d15eca5fd8b3 ui/gtk/menu.c --- a/ui/gtk/menu.c Thu Nov 21 12:04:53 2024 +0100 +++ b/ui/gtk/menu.c Thu Nov 21 13:17:56 2024 +0100 @@ -75,6 +75,12 @@ return mb; } +GtkMenu* ui_create_menu(UiMenuBuilder *builder, UiObject *obj) { + GtkWidget *menu_widget = gtk_menu_new(); + ui_add_menu_items(menu_widget, 0, builder->menus_begin, obj); + return GTK_MENU(menu_widget); +} + void ui_add_menu_items(GtkWidget *parent, int i, UiMenu *menu, UiObject *obj) { UiMenuItemI *it = menu->items_begin; int index = 0; @@ -355,7 +361,6 @@ * widget menu functions */ -/* static gboolean ui_button_press_event(GtkWidget *widget, GdkEvent *event, GtkMenu *menu) { if(event->type == GDK_BUTTON_PRESS) { GdkEventButton *e = (GdkEventButton*)event; @@ -368,19 +373,8 @@ return FALSE; } -UIMENU ui_contextmenu(UiObject *obj) { - UiContainer *ct = uic_get_current_container(obj); - return ui_contextmenu_w(obj, ct->current); -} - -UIMENU ui_contextmenu_w(UiObject *obj, UIWIDGET widget) { - UiContainer *ct = uic_get_current_container(obj); - - GtkMenu *menu = GTK_MENU(gtk_menu_new()); +void ui_widget_set_contextmenu(GtkWidget *widget, GtkMenu *menu) { g_signal_connect(widget, "button-press-event", (GCallback) ui_button_press_event, menu); - - ct->menu = menu; - return menu; } void ui_contextmenu_popup(UIMENU menu) { @@ -390,117 +384,6 @@ gtk_menu_popup(menu, NULL, NULL, 0, 0, 0, gtk_get_current_event_time()); #endif } -*/ - -void ui_widget_menuitem(UiObject *obj, char *label, ui_callback f, void *userdata) { - ui_widget_menuitem_gr(obj, label, f, userdata, -1); -} - -void ui_widget_menuitem_gr(UiObject *obj, char *label, ui_callback f, void *userdata, ...) { - UiContainer *ct = uic_get_current_container(obj); - if(!ct->menu) { - return; - } - - // add groups - CxList *groups = NULL; - va_list ap; - va_start(ap, userdata); - int group; - while((group = va_arg(ap, int)) != -1) { - if(!groups) { - groups = cxArrayListCreate(cxDefaultAllocator, NULL, sizeof(int), 16); - } - cxListAdd(groups, &group); - } - va_end(ap); - - // create menuitem - GtkWidget *widget = gtk_menu_item_new_with_mnemonic(label); - gtk_widget_show(widget); - - if(f) { - UiEventData *event = malloc(sizeof(UiEventData)); - event->obj = obj; - event->userdata = userdata; - event->callback = f; - event->value = 0; - event->customdata = NULL; - - g_signal_connect( - widget, - "activate", - G_CALLBACK(ui_menu_event_wrapper), - event); - g_signal_connect( - widget, - "destroy", - G_CALLBACK(ui_destroy_userdata), - event); - } - - gtk_menu_shell_append(GTK_MENU_SHELL(ct->menu), widget); - - if(groups) { - uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, groups); - cxListDestroy(groups); - } -} - -void ui_widget_menuitem_st(UiObject *obj, char *stockid, ui_callback f, void *userdata) { - ui_widget_menuitem_stgr(obj, stockid, f, userdata, -1); -} - -void ui_widget_menuitem_stgr(UiObject *obj, char *stockid, ui_callback f, void *userdata, ...) { - UiContainer *ct = uic_get_current_container(obj); - if(!ct->menu) { - return; - } - - // add groups - CxList *groups = NULL; - va_list ap; - va_start(ap, userdata); - int group; - while((group = va_arg(ap, int)) != -1) { - if(!groups) { - groups = cxArrayListCreate(cxDefaultAllocator, NULL, sizeof(int), 16); - } - cxListAdd(groups, &group); - } - va_end(ap); - - // create menuitem - GtkWidget *widget = gtk_image_menu_item_new_from_stock(stockid, obj->ctx->accel_group); - gtk_widget_show(widget); - - if(f) { - UiEventData *event = malloc(sizeof(UiEventData)); - event->obj = obj; - event->userdata = userdata; - event->callback = f; - event->value = 0; - event->customdata = NULL; - - g_signal_connect( - widget, - "activate", - G_CALLBACK(ui_menu_event_wrapper), - event); - g_signal_connect( - widget, - "destroy", - G_CALLBACK(ui_destroy_userdata), - event); - } - - gtk_menu_shell_append(GTK_MENU_SHELL(ct->menu), widget); - - if(groups) { - uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, groups); - cxListDestroy(groups); - } -} #endif /* GTK_MAJOR_VERSION <= 3 */ @@ -704,4 +587,38 @@ list->oldcount = i; } + +/* --------------------- context menu / menubuilder --------------------- */ + +GtkPopoverMenu* ui_create_menu(UiMenuBuilder *builder, UiObject *obj) { + GMenu *menu = g_menu_new(); + ui_gmenu_add_menu_items(menu, 0, builder->menus_begin, obj); + GtkWidget *contextmenu = gtk_popover_menu_new_from_model(G_MENU_MODEL(menu)); + gtk_popover_set_has_arrow(GTK_POPOVER(contextmenu), FALSE); + gtk_widget_set_halign(contextmenu, GTK_ALIGN_START); + return GTK_POPOVER_MENU(contextmenu); +} + +static void gesture_button_press(GtkGestureClick *gesture, gint n_press, gdouble x, gdouble y, gpointer user_data) { + gtk_popover_set_pointing_to (GTK_POPOVER (user_data), &(GdkRectangle){ x, y, 0, 0 }); + gtk_popover_popup(GTK_POPOVER(user_data)); +} + +static void remove_popover(GtkWidget *object, GtkPopoverMenu *menu) { + gtk_widget_unparent(GTK_WIDGET(menu)); +} + +void ui_widget_set_contextmenu(GtkWidget *widget, GtkPopoverMenu *menu) { + GtkGesture *gesture = gtk_gesture_click_new(); + gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), 3); + gtk_widget_add_controller(widget, GTK_EVENT_CONTROLLER(gesture)); + g_signal_connect(gesture, "pressed", G_CALLBACK(gesture_button_press), menu); + gtk_widget_set_parent(GTK_WIDGET(menu), widget); + g_signal_connect( + widget, + "destroy", + G_CALLBACK(remove_popover), + menu); +} + #endif diff -r 473c03f85197 -r d15eca5fd8b3 ui/gtk/menu.h --- a/ui/gtk/menu.h Thu Nov 21 12:04:53 2024 +0100 +++ b/ui/gtk/menu.h Thu Nov 21 13:17:56 2024 +0100 @@ -39,6 +39,9 @@ extern "C" { #endif +UIMENU ui_create_menu(UiMenuBuilder *builder, UiObject *obj); +void ui_widget_set_contextmenu(GtkWidget *widget, UIMENU menu); + #if GTK_MAJOR_VERSION <= 3 typedef struct UiActiveMenuItemList UiActiveMenuItemList; diff -r 473c03f85197 -r d15eca5fd8b3 ui/ui/image.h --- a/ui/ui/image.h Thu Nov 21 12:04:53 2024 +0100 +++ b/ui/ui/image.h Thu Nov 21 13:17:56 2024 +0100 @@ -52,6 +52,7 @@ UiBool autoscale; UiGeneric *value; const char *varname; + UiMenuBuilder *contextmenu; } UiImageViewerArgs; #define ui_imageviewer(obj, ...) ui_imageviewer_create(obj, (UiImageViewerArgs){ __VA_ARGS__ } ) diff -r 473c03f85197 -r d15eca5fd8b3 ui/ui/menu.h --- a/ui/ui/menu.h Thu Nov 21 12:04:53 2024 +0100 +++ b/ui/ui/menu.h Thu Nov 21 13:17:56 2024 +0100 @@ -99,12 +99,6 @@ UIEXPORT UIMENU ui_contextmenu_create(UiMenuBuilder *builder, UiObject *obj, UIWIDGET widget); UIEXPORT void ui_contextmenu_popup(UIMENU menu); -UIEXPORT void ui_widget_menuitem(UiObject *obj, char *label, ui_callback f, void *userdata); -UIEXPORT void ui_widget_menuitem_st(UiObject *obj, char *stockid, ui_callback f, void *userdata); -UIEXPORT void ui_widget_menuitem_gr(UiObject *obj, char *label, ui_callback f, void *userdata, ...); -UIEXPORT void ui_widget_menuitem_stgr(UiObject *obj, char *stockid, ui_callback f, void *userdata, ...); - - // used for macro UIEXPORT void ui_menu_close(void); UIEXPORT int ui_menu_is_open(void);