implement image viewer context menus (GTK) newapi

Thu, 21 Nov 2024 13:17:56 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Thu, 21 Nov 2024 13:17:56 +0100
branch
newapi
changeset 389
d15eca5fd8b3
parent 388
473c03f85197
child 390
b130f80ec7f9

implement image viewer context menus (GTK)

application/main.c file | annotate | diff | comparison | revisions
ui/gtk/image.c file | annotate | diff | comparison | revisions
ui/gtk/menu.c file | annotate | diff | comparison | revisions
ui/gtk/menu.h file | annotate | diff | comparison | revisions
ui/ui/image.h file | annotate | diff | comparison | revisions
ui/ui/menu.h file | annotate | diff | comparison | revisions
--- 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");
--- 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;
 }
 
--- 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
--- 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;
--- 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__ } )
--- 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);

mercurial