Ansel
0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
popup.c
Go to the documentation of this file.
1
/*
2
* This file is part of Ansel,
3
* Copyright (C) 2026 Aurélien PIERRE.
4
*
5
* Ansel is free software: you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation, either version 3 of the License, or
8
* (at your option) any later version.
9
*
10
* Ansel is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
14
*
15
* You should have received a copy of the GNU General Public License
16
* along with Ansel. If not, see <http://www.gnu.org/licenses/>.
17
*/
18
19
#include "
widgets/popup.h
"
20
21
#include "
system/macros.h
"
// IS_NULL_PTR
22
#include "
widgets/widget_settings.h
"
// DT_GUI_BOX_SPACING, DT_PIXEL_APPLY_DPI, root window
23
#include "
widgets/widget_style.h
"
// dt_gui_add_class
24
25
GtkWidget
*
dt_gui_get_popup_relative_widget
(
GtkWidget
*widget,
GdkRectangle
*
rect
)
26
{
27
if
(
IS_NULL_PTR
(widget))
return
NULL
;
28
29
GtkWidget
*
relative
= widget;
30
31
// Wayland only accepts the top-most enclosing popup as transient parent.
32
for
(
GtkWidget
*parent =
gtk_widget_get_parent
(widget); parent; parent =
gtk_widget_get_parent
(parent))
33
if
(
GTK_IS_POPOVER
(parent))
relative
= parent;
34
35
if
(
rect
)
36
{
37
rect
->
x
= 0;
38
rect
->
y
= 0;
39
rect
->
width
=
MAX
(
gtk_widget_get_allocated_width
(widget), 1);
40
rect
->height =
MAX
(
gtk_widget_get_allocated_height
(widget), 1);
41
42
if
(
relative
!= widget
43
&& !
gtk_widget_translate_coordinates
(widget,
relative
, 0, 0, &
rect
->
x
, &
rect
->
y
))
44
{
45
rect
->
x
= 0;
46
rect
->
y
= 0;
47
}
48
}
49
50
return
relative
;
51
}
52
53
void
dt_gui_menu_popup
(
GtkMenu
*menu,
GtkWidget
*button,
GdkGravity
widget_anchor
,
GdkGravity
menu_anchor
)
54
{
55
gtk_widget_show_all
(
GTK_WIDGET
(menu));
56
57
GdkEvent
*
event
=
gtk_get_current_event
();
58
if
(button)
59
{
60
GdkRectangle
rect
= { 0 };
61
GtkWidget
*
relative
=
dt_gui_get_popup_relative_widget
(button, &
rect
);
62
63
if
(
relative
&&
relative
!= button &&
gtk_widget_get_window
(
relative
))
64
gtk_menu_popup_at_rect
(menu,
gtk_widget_get_window
(
relative
), &
rect
,
widget_anchor
,
menu_anchor
, event);
65
else
66
gtk_menu_popup_at_widget
(menu, button,
widget_anchor
,
menu_anchor
, event);
67
}
68
else
69
{
70
if
(
IS_NULL_PTR
(event))
71
{
72
event
=
gdk_event_new
(
GDK_BUTTON_PRESS
);
73
event
->button.device =
gdk_seat_get_pointer
(
gdk_display_get_default_seat
(
gdk_display_get_default
()));
74
event
->button.window =
gtk_widget_get_window
(
dt_widget_root_window
());
75
g_object_ref
(event->button.window);
76
}
77
78
gtk_menu_popup_at_pointer
(menu, event);
79
}
80
gdk_event_free
(event);
81
}
82
83
static
void
_popover_set_relative_to_topmost_parent
(
GtkPopover
*
popover
,
GtkWidget
*button)
84
{
85
GdkRectangle
rect
= { 0 };
86
GtkWidget
*
relative
=
dt_gui_get_popup_relative_widget
(button, &
rect
);
87
gtk_popover_set_relative_to
(
popover
,
relative
?
relative
: button);
88
gtk_popover_set_pointing_to
(
popover
, &
rect
);
89
}
90
91
GtkBox *
attach_popover
(
GtkWidget
*widget,
const
char
*icon,
GtkWidget
*content)
92
{
93
// Create the wrapping box and add the original widget to it
94
GtkWidget
*box =
gtk_box_new
(
GTK_ORIENTATION_HORIZONTAL
,
DT_GUI_BOX_SPACING
);
95
gtk_box_pack_start
(
GTK_BOX
(box), widget,
FALSE
,
FALSE
, 0);
96
97
// Create the info icon button that will trigger the popover
98
GtkWidget
*button =
gtk_menu_button_new
();
99
dt_gui_add_class
(button,
"popover-button"
);
100
GtkWidget
*image =
gtk_image_new_from_icon_name
(icon,
GTK_ICON_SIZE_BUTTON
);
101
gtk_button_set_image
(
GTK_BUTTON
(button), image);
102
gtk_widget_set_hexpand
(button,
FALSE
);
103
gtk_widget_set_vexpand
(button,
FALSE
);
104
gtk_widget_set_size_request
(button,
DT_PIXEL_APPLY_DPI
(16),
DT_PIXEL_APPLY_DPI
(16));
105
gtk_box_pack_start
(
GTK_BOX
(box), button,
FALSE
,
FALSE
, 0);
106
107
// Create the content of the popover
108
GtkWidget
*
popover_box
=
gtk_box_new
(
GTK_ORIENTATION_VERTICAL
,
DT_GUI_BOX_SPACING
);
109
gtk_box_pack_start
(
GTK_BOX
(
popover_box
), content,
FALSE
,
FALSE
, 0);
110
111
// Wrap the content into a popover and attach it to the button
112
GtkWidget
*
popover
=
gtk_popover_new
(button);
113
gtk_container_add
(
GTK_CONTAINER
(
popover
),
popover_box
);
114
gtk_popover_set_modal
(
GTK_POPOVER
(
popover
),
FALSE
);
115
g_signal_connect
(
G_OBJECT
(
popover
),
"show"
,
G_CALLBACK
(
_popover_set_relative_to_topmost_parent
), button);
116
gtk_menu_button_set_popover
(
GTK_MENU_BUTTON
(button),
popover
);
117
gtk_widget_show_all
(
popover_box
);
118
119
return
GTK_BOX
(box);
120
}
121
122
GtkBox *
attach_help_popover
(
GtkWidget
*widget,
const
char
*label)
123
{
124
// Create the content of the popover
125
GtkWidget
*
popover_label
=
gtk_label_new
(label);
126
gtk_label_set_line_wrap
(
GTK_LABEL
(
popover_label
),
TRUE
);
127
gtk_label_set_max_width_chars
(
GTK_LABEL
(
popover_label
), 60);
128
return
attach_popover
(widget,
"help-about"
,
popover_label
);
129
}
130
131
// clang-format off
132
// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
133
// vim: shiftwidth=2 expandtab tabstop=2 cindent
134
// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
135
// clang-format on
TRUE
#define TRUE
Definition
ashift_lsd.c:162
FALSE
#define FALSE
Definition
ashift_lsd.c:158
GtkWidget
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition
colorspaces.h:98
L
const float L
Definition
colorspaces_inline_conversions.h:494
macros.h
IS_NULL_PTR
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition
macros.h:65
attach_help_popover
GtkBox * attach_help_popover(GtkWidget *widget, const char *label)
Definition
popup.c:122
dt_gui_menu_popup
void dt_gui_menu_popup(GtkMenu *menu, GtkWidget *button, GdkGravity widget_anchor, GdkGravity menu_anchor)
Definition
popup.c:53
dt_gui_get_popup_relative_widget
GtkWidget * dt_gui_get_popup_relative_widget(GtkWidget *widget, GdkRectangle *rect)
Resolve the widget to use as parent for a nested popup on Wayland.
Definition
popup.c:25
attach_popover
GtkBox * attach_popover(GtkWidget *widget, const char *icon, GtkWidget *content)
Definition
popup.c:91
_popover_set_relative_to_topmost_parent
static void _popover_set_relative_to_topmost_parent(GtkPopover *popover, GtkWidget *button)
Definition
popup.c:83
popup.h
rect
Definition
ashift_lsd.c:1229
rect::x
double x
Definition
ashift_lsd.c:1232
rect::width
double width
Definition
ashift_lsd.c:1231
rect::y
double y
Definition
ashift_lsd.c:1232
MAX
#define MAX(a, b)
Definition
thinplate.c:29
dt_widget_root_window
GtkWidget * dt_widget_root_window(void)
Definition
widget_settings.c:113
widget_settings.h
DT_GUI_BOX_SPACING
#define DT_GUI_BOX_SPACING
Definition
widget_settings.h:255
DT_PIXEL_APPLY_DPI
#define DT_PIXEL_APPLY_DPI(value)
Definition
widget_settings.h:246
dt_gui_add_class
void dt_gui_add_class(GtkWidget *widget, const gchar *class_name)
Definition
widget_style.c:32
widget_style.h
src
widgets
popup.c
Generated by
1.9.8