Enhance save as template and new from template dialogs
[inkscape.git] / src / ui / popup-menu.cpp
blobf43a3771769342209ab6ffccf9b82f57afbb10f1
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /** @file
3 * Helpers to connect signals to events that popup a menu in both GTK3 and GTK4.
4 * Plus miscellaneous helpers primarily useful with widgets used as popop menus.
5 */
6 /*
7 * Authors:
8 * Daniel Boles <dboles.src+inkscape@gmail.com>
10 * Copyright (C) 2023 Daniel Boles
12 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
15 #include "popup-menu.h"
17 #include <utility>
18 #include <2geom/point.h>
19 #include <gtkmm/accelerator.h>
20 #include <gtkmm/eventcontrollerkey.h>
21 #include <gtkmm/gestureclick.h>
22 #include <gdkmm/rectangle.h>
23 #include <gtkmm/popover.h>
24 #include <gtkmm/widget.h>
26 #include "controller.h"
27 #include "ui/util.h"
29 namespace Inkscape::UI {
31 static bool on_key_pressed(unsigned const keyval, unsigned /*keycode*/, Gdk::ModifierType state,
32 PopupMenuSlot const &slot)
34 if (keyval == GDK_KEY_Menu) {
35 return slot(std::nullopt);
38 state &= Gtk::Accelerator::get_default_mod_mask();
39 if (keyval == GDK_KEY_F10 && Controller::has_flag(state, Gdk::ModifierType::SHIFT_MASK)) {
40 return slot(std::nullopt);
43 return false;
46 static void on_click_pressed(int n_press, double x, double y, Gtk::GestureClick &click, PopupMenuSlot const &slot)
48 auto const event = click.get_current_event();
49 if (event->triggers_context_menu()) {
50 auto const mc = PopupMenuClick{n_press, x, y};
51 if (slot(mc)) {
52 click.set_state(Gtk::EventSequenceState::CLAIMED);
57 void on_popup_menu(Gtk::Widget &widget, PopupMenuSlot slot)
59 auto key = Gtk::EventControllerKey::create();
60 key->signal_key_pressed().connect(sigc::bind(&on_key_pressed, slot), true); // after
61 widget.add_controller(key);
63 auto click = Gtk::GestureClick::create();
64 click->set_button(0);
65 click->set_propagation_phase(Gtk::PropagationPhase::CAPTURE); // before GTK's popup handler
66 click->signal_pressed().connect(sigc::bind(&on_click_pressed, std::ref(*click), std::move(slot)));
67 widget.add_controller(click);
70 static void popup_at(Gtk::Popover &popover, Gtk::Widget &widget,
71 double const x_offset, double const y_offset,
72 int width, int height)
74 popover.set_visible(false);
76 auto const parent = popover.get_parent();
77 g_return_if_fail(parent);
78 g_return_if_fail(&widget == parent || is_descendant_of(widget, *parent));
80 auto const allocation = widget.get_allocation();
81 if (!width ) width = x_offset ? 1 : allocation.get_width ();
82 if (!height) height = y_offset ? 1 : allocation.get_height();
83 double x{}, y{};
84 widget.translate_coordinates(*parent, 0, 0, x, y);
85 x += x_offset;
86 y += y_offset;
87 auto const ix = static_cast<int>(x + 0.5), iy = static_cast<int>(y + 0.5);
88 popover.set_pointing_to({ix, iy, width, height});
90 popover.popup();
93 void popup_at(Gtk::Popover &popover, Gtk::Widget &widget,
94 double const x_offset, double const y_offset)
96 popup_at(popover, widget, x_offset, y_offset, 0, 0);
99 void popup_at(Gtk::Popover &popover, Gtk::Widget &widget,
100 std::optional<Geom::Point> const &offset)
102 auto const x_offset = offset ? offset->x() : 0;
103 auto const y_offset = offset ? offset->y() : 0;
104 popup_at(popover, widget, x_offset, y_offset);
107 void popup_at_center(Gtk::Popover &popover, Gtk::Widget &widget)
109 auto const x_offset = widget.get_width () / 2;
110 auto const y_offset = widget.get_height() / 2;
111 popup_at(popover, widget, x_offset, y_offset);
114 void popup_at(Gtk::Popover &popover, Gtk::Widget &widget, Gdk::Rectangle const &rect)
116 popup_at(popover, widget, rect.get_x(), rect.get_y(), rect.get_width(), rect.get_height());
119 } // namespace Inkscape::UI
122 Local Variables:
123 mode:c++
124 c-file-style:"stroustrup"
125 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
126 indent-tabs-mode:nil
127 fill-column:99
128 End:
130 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :