# HG changeset patch # User Olaf Wintermann # Date 1732211147 -3600 # Node ID b130f80ec7f99aed0c5b00a83efe454a0b687306 # Parent d15eca5fd8b3614618567840e8a30def322657b0 implement list/table contextmenu (GTK) diff -r d15eca5fd8b3 -r b130f80ec7f9 application/main.c --- a/application/main.c Thu Nov 21 13:17:56 2024 +0100 +++ b/application/main.c Thu Nov 21 18:45:47 2024 +0100 @@ -40,6 +40,7 @@ UiText *text; UiDouble *progress; UiList *list; + UiList *list2; UiList *menulist; UiInteger *radio; UiInteger *tabview; @@ -152,6 +153,10 @@ ui_list_append(doc->list, "test1"); ui_list_append(doc->list, "test2"); ui_list_append(doc->list, "test3"); + doc->list2 = ui_list_new(docctx, "list2"); + ui_list_append(doc->list2, "test1"); + ui_list_append(doc->list2, "test2"); + ui_list_append(doc->list2, "test3"); doc->radio = ui_int_new(docctx, "radio"); doc->tabview = ui_int_new(docctx, "tabview"); doc->image = ui_generic_new(docctx, "image"); @@ -241,6 +246,10 @@ UiMenuBuilder *menubuilder; +void* table_getvalue(void *row, int col) { + return row; +} + void application_startup(UiEvent *event, void *data) { // global list UiContext *global = ui_global_context(); @@ -303,6 +312,11 @@ ui_radiobutton(obj, .label = "Radio 2", .varname = "radio"); ui_radiobutton(obj, .label = "Radio 3", .varname = "radio"); } + ui_newline(obj); + + UiModel *model = ui_model(obj->ctx, UI_STRING, "col1", -1); + model->getvalue = table_getvalue; + ui_table(obj, .model = model, .list = doc->list2, .colspan = 2, .hexpand = TRUE, .contextmenu = menubuilder); } } ui_tab(obj, "Tab 2") { diff -r d15eca5fd8b3 -r b130f80ec7f9 ui/gtk/image.c --- a/ui/gtk/image.c Thu Nov 21 13:17:56 2024 +0100 +++ b/ui/gtk/image.c Thu Nov 21 18:45:47 2024 +0100 @@ -73,7 +73,7 @@ } if(args.contextmenu) { - UIMENU menu = ui_create_menu(args.contextmenu, obj); + UIMENU menu = ui_contextmenu_create(args.contextmenu, obj, eventbox); ui_widget_set_contextmenu(eventbox, menu); } diff -r d15eca5fd8b3 -r b130f80ec7f9 ui/gtk/list.c --- a/ui/gtk/list.c Thu Nov 21 13:17:56 2024 +0100 +++ b/ui/gtk/list.c Thu Nov 21 18:45:47 2024 +0100 @@ -37,6 +37,7 @@ #include "list.h" #include "icon.h" +#include "menu.h" void* ui_strmodel_getvalue(void *elm, int column) { @@ -235,6 +236,10 @@ G_CALLBACK(ui_listview_selection_event), event); } + if(args.contextmenu) { + UIMENU menu = ui_contextmenu_create(args.contextmenu, obj, view); + ui_widget_set_contextmenu(view, menu); + } // add widget to the current container @@ -396,7 +401,11 @@ event); } // TODO: destroy callback - + + if(args.contextmenu) { + UIMENU menu = ui_contextmenu_create(args.contextmenu, obj, view); + ui_widget_set_contextmenu(view, menu); + } GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(view)); if(args.multiselection) { diff -r d15eca5fd8b3 -r b130f80ec7f9 ui/gtk/menu.c --- a/ui/gtk/menu.c Thu Nov 21 13:17:56 2024 +0100 +++ b/ui/gtk/menu.c Thu Nov 21 18:45:47 2024 +0100 @@ -75,12 +75,6 @@ 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; @@ -361,12 +355,18 @@ * widget menu functions */ +UIMENU ui_contextmenu_create(UiMenuBuilder *builder, UiObject *obj, UIWIDGET widget) { + GtkWidget *menu_widget = gtk_menu_new(); + ui_add_menu_items(menu_widget, 0, builder->menus_begin, obj); + return GTK_MENU(menu_widget); +} + static gboolean ui_button_press_event(GtkWidget *widget, GdkEvent *event, GtkMenu *menu) { if(event->type == GDK_BUTTON_PRESS) { GdkEventButton *e = (GdkEventButton*)event; if(e->button == 3) { gtk_widget_show_all(GTK_WIDGET(menu)); - ui_contextmenu_popup(menu); + ui_contextmenu_popup(menu, widget, 0, 0); return TRUE; } } @@ -377,7 +377,7 @@ g_signal_connect(widget, "button-press-event", (GCallback) ui_button_press_event, menu); } -void ui_contextmenu_popup(UIMENU menu) { +void ui_contextmenu_popup(UIMENU menu, GtkWidget *widget, int x, int y) { #if GTK_MAJOR_VERSION >= 3 && GTK_MINOR_VERSION >= 16 gtk_menu_popup_at_pointer(menu, NULL); #else @@ -590,35 +590,40 @@ /* --------------------- context menu / menubuilder --------------------- */ -GtkPopoverMenu* ui_create_menu(UiMenuBuilder *builder, UiObject *obj) { +static void remove_popover(GtkWidget *object, GtkPopoverMenu *menu) { + gtk_widget_unparent(GTK_WIDGET(menu)); +} + +UIMENU ui_contextmenu_create(UiMenuBuilder *builder, UiObject *obj, GtkWidget *widget) { 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); + gtk_widget_set_parent(GTK_WIDGET(contextmenu), widget); + g_signal_connect( + widget, + "destroy", + G_CALLBACK(remove_popover), + contextmenu); 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_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); +} + +void ui_contextmenu_popup(UIMENU menu, UIWIDGET widget, int x, int y) { + gtk_popover_set_pointing_to(GTK_POPOVER(menu), &(GdkRectangle){ x, y, 0, 0 }); + gtk_popover_popup(GTK_POPOVER(menu)); } #endif diff -r d15eca5fd8b3 -r b130f80ec7f9 ui/ui/menu.h --- a/ui/ui/menu.h Thu Nov 21 13:17:56 2024 +0100 +++ b/ui/ui/menu.h Thu Nov 21 18:45:47 2024 +0100 @@ -97,7 +97,7 @@ UIEXPORT void ui_contextmenu_builder(UiMenuBuilder **out_builder); UIEXPORT void ui_menubuilder_free(UiMenuBuilder *builder); UIEXPORT UIMENU ui_contextmenu_create(UiMenuBuilder *builder, UiObject *obj, UIWIDGET widget); -UIEXPORT void ui_contextmenu_popup(UIMENU menu); +UIEXPORT void ui_contextmenu_popup(UIMENU menu, UIWIDGET widget, int x, int y); // used for macro UIEXPORT void ui_menu_close(void); diff -r d15eca5fd8b3 -r b130f80ec7f9 ui/ui/tree.h --- a/ui/ui/tree.h Thu Nov 21 13:17:56 2024 +0100 +++ b/ui/ui/tree.h Thu Nov 21 18:45:47 2024 +0100 @@ -130,6 +130,7 @@ ui_callback ondrop; void* ondropsdata; UiBool multiselection; + UiMenuBuilder *contextmenu; const int *groups; };