Skip to content

Commit 950cb01

Browse files
committed
migrate collection popover menu
1 parent 26d7163 commit 950cb01

File tree

4 files changed

+135
-59
lines changed

4 files changed

+135
-59
lines changed

data/themes/darktable.css

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,22 @@ menuitem label,
875875
margin: 0;
876876
}
877877

878+
/*------------------------------------------------
879+
- Popup menu -
880+
----------------------------------------------*/
881+
popover.menu {
882+
padding: 0;
883+
}
884+
885+
popover.menu modelbutton {
886+
padding: 0.1em 0.5em;
887+
}
888+
889+
popover.menu modelbutton:hover {
890+
background-color: @selected_bg_color;
891+
}
892+
893+
878894
tooltip,
879895
#range-current
880896
{

src/gui/gtk.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4600,6 +4600,21 @@ void dt_gui_dialog_restore_size(GtkDialog *dialog, const char *conf)
46004600
g_signal_connect(dialog, "configure-event", G_CALLBACK(_resize_dialog), (gpointer)conf);
46014601
}
46024602

4603+
GtkWidget *dt_gui_popover_menu_from_model(GtkWidget *parent, GMenu *menu)
4604+
{
4605+
GtkWidget *popover_menu;
4606+
4607+
#if GTK_CHECK_VERSION(4, 0, 0)
4608+
popover_menu = gtk_popover_menu_new_from_model(G_MENU_MODEL(menu));
4609+
gtk_widget_set_parent(popover_menu, parent);
4610+
#else
4611+
popover_menu = gtk_popover_new_from_model(parent, G_MENU_MODEL(menu));
4612+
#endif
4613+
4614+
return popover_menu;
4615+
}
4616+
4617+
46034618
// clang-format off
46044619
// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
46054620
// vim: shiftwidth=2 expandtab tabstop=2 cindent

src/gui/gtk.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
This file is part of darktable,
3-
Copyright (C) 2009-2024 darktable developers.
3+
Copyright (C) 2009-2025 darktable developers.
44
55
darktable is free software: you can redistribute it and/or modify
66
it under the terms of the GNU General Public License as published by
@@ -627,6 +627,10 @@ void dt_gui_commit_on_focus_loss(GtkCellRenderer *renderer, GtkCellEditable **ac
627627
// restore dialog size from config file
628628
void dt_gui_dialog_restore_size(GtkDialog *dialog, const char *conf);
629629

630+
// Popover menu
631+
GtkWidget *dt_gui_popover_menu_from_model(GtkWidget *parent, GMenu *menu);
632+
633+
630634
G_END_DECLS
631635

632636
// clang-format off

src/libs/collect.c

Lines changed: 99 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ typedef struct dt_lib_collect_t
9696
gboolean inited;
9797

9898
GtkWidget *history_box;
99+
100+
GSimpleActionGroup *action_group;
99101
} dt_lib_collect_t;
100102

101103
typedef struct dt_lib_collect_params_rule_t
@@ -2924,9 +2926,28 @@ static gboolean entry_focus_in_callback(GtkWidget *w,
29242926
return FALSE;
29252927
}
29262928

2927-
static void menuitem_mode(GtkMenuItem *menuitem,
2928-
dt_lib_collect_rule_t *d)
2929+
static void menuitem_mode(GSimpleAction *simple,
2930+
GVariant *parameter,
2931+
gpointer userdata)
29292932
{
2933+
dt_lib_collect_t *m = (dt_lib_collect_t *) userdata;
2934+
2935+
gsize nb = g_variant_n_children(parameter);
2936+
2937+
if(nb != 2)
2938+
return;
2939+
2940+
GVariant *v;
2941+
v = g_variant_get_child_value(parameter, 0);
2942+
const dt_lib_collect_mode_t mode = g_variant_get_int32(v);
2943+
g_variant_unref(v);
2944+
2945+
v = g_variant_get_child_value(parameter, 1);
2946+
const int rule_index = g_variant_get_int32(v);
2947+
g_variant_unref(v);
2948+
2949+
dt_lib_collect_rule_t *d = &m->rule[rule_index];
2950+
29302951
// add next row with and operator
29312952
const int _a = dt_conf_get_int("plugins/lighttable/collect/num_rules");
29322953
const int active = CLAMP(_a, 1, MAX_RULES);
@@ -2935,8 +2956,6 @@ static void menuitem_mode(GtkMenuItem *menuitem,
29352956
{
29362957
char confname[200] = { 0 };
29372958
snprintf(confname, sizeof(confname), "plugins/lighttable/collect/mode%1d", active);
2938-
const dt_lib_collect_mode_t mode =
2939-
GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menuitem), "menuitem_mode"));
29402959

29412960
dt_conf_set_int(confname, mode);
29422961
snprintf(confname, sizeof(confname), "plugins/lighttable/collect/string%1d", active);
@@ -2951,17 +2970,34 @@ static void menuitem_mode(GtkMenuItem *menuitem,
29512970
DT_COLLECTION_PROP_UNDEF, NULL);
29522971
}
29532972

2954-
static void menuitem_mode_change(GtkMenuItem *menuitem,
2955-
dt_lib_collect_rule_t *d)
2973+
static void menuitem_mode_change(GSimpleAction *simple,
2974+
GVariant *parameter,
2975+
gpointer userdata)
29562976
{
2977+
dt_lib_collect_t *m = (dt_lib_collect_t *) userdata;
2978+
2979+
gsize nb = g_variant_n_children(parameter);
2980+
2981+
if(nb != 2)
2982+
return;
2983+
2984+
GVariant *v;
2985+
v = g_variant_get_child_value(parameter, 0);
2986+
const dt_lib_collect_mode_t mode = g_variant_get_int32(v);
2987+
g_variant_unref(v);
2988+
2989+
v = g_variant_get_child_value(parameter, 1);
2990+
const int rule_index = g_variant_get_int32(v);
2991+
g_variant_unref(v);
2992+
2993+
dt_lib_collect_rule_t *d = &m->rule[rule_index];
2994+
29572995
// add next row with and operator
29582996
const int num = d->num + 1;
29592997
if(num < MAX_RULES && num > 0)
29602998
{
29612999
char confname[200] = { 0 };
29623000
snprintf(confname, sizeof(confname), "plugins/lighttable/collect/mode%1d", num);
2963-
const dt_lib_collect_mode_t mode =
2964-
GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menuitem), "menuitem_mode"));
29653001
dt_conf_set_int(confname, mode);
29663002
}
29673003
dt_lib_collect_t *c = get_collect(d);
@@ -3184,9 +3220,15 @@ static void _metadata_changed(gpointer instance,
31843220
}
31853221
}
31863222

3187-
static void menuitem_clear(GtkMenuItem *menuitem,
3188-
dt_lib_collect_rule_t *d)
3223+
static void menuitem_clear(GSimpleAction *simple,
3224+
GVariant *parameter,
3225+
gpointer userdata)
31893226
{
3227+
dt_lib_collect_t *m = (dt_lib_collect_t*) userdata;
3228+
3229+
const int index = g_variant_get_int32(parameter);
3230+
dt_lib_collect_rule_t *d = &m->rule[index];
3231+
31903232
// remove this row, or if 1st, clear text entry box
31913233
const int _a = dt_conf_get_int("plugins/lighttable/collect/num_rules");
31923234
const int active = CLAMP(_a, 1, MAX_RULES);
@@ -3231,72 +3273,58 @@ static void menuitem_clear(GtkMenuItem *menuitem,
32313273
DT_COLLECTION_PROP_UNDEF, NULL);
32323274
}
32333275

3234-
static gboolean popup_button_callback(GtkWidget *widget,
3276+
static gboolean popup_button_callback(GtkWidget *button,
32353277
GdkEventButton *event,
32363278
dt_lib_collect_rule_t *d)
32373279
{
32383280
if(event->button != 1)
32393281
return FALSE;
32403282

3241-
GtkWidget *menu = gtk_menu_new();
3242-
GtkWidget *mi;
3283+
GMenu *menu = g_menu_new();
32433284
const int _a = dt_conf_get_int("plugins/lighttable/collect/num_rules");
32443285
const int active = CLAMP(_a, 1, MAX_RULES);
32453286

3246-
mi = gtk_menu_item_new_with_label(_("clear this rule"));
3247-
gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
3248-
g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(menuitem_clear), d);
3249-
3287+
gchar *action;
3288+
3289+
action = g_strdup_printf("collect.clear(%d)", d->num);
3290+
g_menu_append(menu, _("clear this rule"), action);
3291+
g_free(action);
3292+
32503293
if(d->num == active - 1)
32513294
{
3252-
mi = gtk_menu_item_new_with_label(_("narrow down search"));
3253-
g_object_set_data(G_OBJECT(mi), "menuitem_mode",
3254-
GINT_TO_POINTER(DT_LIB_COLLECT_MODE_AND));
3255-
gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
3256-
g_signal_connect(G_OBJECT(mi), "activate",
3257-
G_CALLBACK(menuitem_mode), d);
3258-
3259-
mi = gtk_menu_item_new_with_label(_("add more images"));
3260-
g_object_set_data(G_OBJECT(mi), "menuitem_mode",
3261-
GINT_TO_POINTER(DT_LIB_COLLECT_MODE_OR));
3262-
gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
3263-
g_signal_connect(G_OBJECT(mi), "activate",
3264-
G_CALLBACK(menuitem_mode), d);
3265-
3266-
mi = gtk_menu_item_new_with_label(_("exclude images"));
3267-
g_object_set_data(G_OBJECT(mi), "menuitem_mode",
3268-
GINT_TO_POINTER(DT_LIB_COLLECT_MODE_AND_NOT));
3269-
gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
3270-
g_signal_connect(G_OBJECT(mi), "activate",
3271-
G_CALLBACK(menuitem_mode), d);
3295+
const char *fmt = "collect.mode((%d,%d))";
3296+
3297+
action = g_strdup_printf(fmt, DT_LIB_COLLECT_MODE_AND, d->num);
3298+
g_menu_append(menu, _("narrow down search"), action);
3299+
g_free(action);
3300+
3301+
action = g_strdup_printf(fmt, DT_LIB_COLLECT_MODE_OR, d->num);
3302+
g_menu_append(menu, _("add more images"), action);
3303+
g_free(action);
3304+
3305+
action = g_strdup_printf(fmt, DT_LIB_COLLECT_MODE_AND_NOT, d->num);
3306+
g_menu_append(menu, _("exclude images"), action);
3307+
g_free(action);
32723308
}
32733309
else if(d->num < active - 1)
32743310
{
3275-
mi = gtk_menu_item_new_with_label(_("change to: and"));
3276-
g_object_set_data(G_OBJECT(mi), "menuitem_mode",
3277-
GINT_TO_POINTER(DT_LIB_COLLECT_MODE_AND));
3278-
gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
3279-
g_signal_connect(G_OBJECT(mi), "activate",
3280-
G_CALLBACK(menuitem_mode_change), d);
3311+
const char *fmt = "collect.modechange((%d,%d))";
32813312

3282-
mi = gtk_menu_item_new_with_label(_("change to: or"));
3283-
g_object_set_data(G_OBJECT(mi), "menuitem_mode",
3284-
GINT_TO_POINTER(DT_LIB_COLLECT_MODE_OR));
3285-
gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
3286-
g_signal_connect(G_OBJECT(mi), "activate",
3287-
G_CALLBACK(menuitem_mode_change), d);
3313+
action = g_strdup_printf(fmt, DT_LIB_COLLECT_MODE_AND, d->num);
3314+
g_menu_append(menu, _("change to: and"), action);
3315+
g_free(action);
32883316

3289-
mi = gtk_menu_item_new_with_label(_("change to: except"));
3290-
g_object_set_data(G_OBJECT(mi), "menuitem_mode",
3291-
GINT_TO_POINTER(DT_LIB_COLLECT_MODE_AND_NOT));
3292-
gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
3293-
g_signal_connect(G_OBJECT(mi), "activate",
3294-
G_CALLBACK(menuitem_mode_change), d);
3295-
}
3317+
action = g_strdup_printf(fmt, DT_LIB_COLLECT_MODE_OR, d->num);
3318+
g_menu_append(menu, _("change to: or"), action);
3319+
g_free(action);
32963320

3297-
gtk_widget_show_all(GTK_WIDGET(menu));
3321+
action = g_strdup_printf(fmt, DT_LIB_COLLECT_MODE_AND_NOT, d->num);
3322+
g_menu_append(menu, _("change to: except"), action);
3323+
g_free(action);
3324+
}
32983325

3299-
gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event);
3326+
GtkWidget *popover_menu = dt_gui_popover_menu_from_model(button, menu);
3327+
gtk_popover_popup(GTK_POPOVER(popover_menu));
33003328

33013329
return TRUE;
33023330
}
@@ -3654,6 +3682,17 @@ void gui_init(dt_lib_module_t *self)
36543682
self->widget = dt_gui_vbox();
36553683
dt_gui_add_class(self->widget, "dt_spacing_sw");
36563684

3685+
// setup the actions for this module
3686+
const GActionEntry entries[] = {
3687+
{ "clear", menuitem_clear, "i" },
3688+
{ "mode", menuitem_mode, "(ii)" },
3689+
{ "modechange", menuitem_mode_change, "(ii)" }
3690+
};
3691+
3692+
d->action_group = g_simple_action_group_new();
3693+
g_action_map_add_action_entries(G_ACTION_MAP(d->action_group), entries, G_N_ELEMENTS(entries), d);
3694+
gtk_widget_insert_action_group(self->widget, "collect", G_ACTION_GROUP(d->action_group));
3695+
36573696
d->active_rule = 0;
36583697
d->nb_rules = 0;
36593698
d->params = (dt_lib_collect_params_t *)malloc(sizeof(dt_lib_collect_params_t));
@@ -3808,6 +3847,8 @@ void gui_cleanup(dt_lib_module_t *self)
38083847
g_object_unref(d->listfilter);
38093848
g_object_unref(d->vmonitor);
38103849

3850+
g_object_unref(d->action_group);
3851+
38113852
/* TODO: Make sure we are cleaning up all allocations */
38123853

38133854
free(self->data);

0 commit comments

Comments
 (0)