Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
tool-toolbar.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
6/* Authors:
7 * Mike Kowalski (Popovers)
8 * Martin Owens (Tool button categories)
9 * Jonathon Neuhauser (Open tool preferences)
10 * Tavmjong Bah
11 *
12 * Copyright (C) 2023 Tavmjong Bah
13 *
14 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
15 */
16
17#include <utility>
18#include <glibmm/i18n.h>
19#include <giomm/menu.h>
20#include <giomm/simpleactiongroup.h>
21#include <gtkmm/builder.h>
22#include <gtkmm/button.h>
23#include <gtkmm/flowbox.h>
24#include <gtkmm/gestureclick.h>
25#include <gtkmm/popover.h>
26#include <gtkmm/togglebutton.h>
27#include <gtkmm/scrolledwindow.h>
28#include <gtkmm/separator.h>
29
30#include "tool-toolbar.h"
31#include "actions/actions-tools.h" // Function to open tool preferences.
32#include "inkscape-window.h"
33#include "ui/builder-utils.h"
34#include "ui/controller.h"
35#include "ui/util.h"
38#include "widgets/spw-utilities.h" // Find action target
39
40namespace Inkscape::UI::Toolbar {
41
43 : _context_menu{makeContextMenu(window)}
44{
45 set_name("ToolToolbar");
46
47 auto builder = Inkscape::UI::create_builder("toolbar-tool.ui");
48 auto &tool_toolbar = UI::get_widget<Gtk::ScrolledWindow>(builder, "tool-toolbar");
49 tool_toolbar.set_halign(Gtk::Align::FILL);
50
51 attachHandlers(builder, window);
52
53 _popoverbin.setChild(&tool_toolbar);
55 _popoverbin.set_hexpand(true);
57
58 // Hide/show buttons based on preferences.
61 set_visible_buttons(tool_toolbar); // Must come after pack_start()
62}
63
65
66void ToolToolbar::set_visible_buttons(Gtk::ScrolledWindow &tool_toolbar)
67{
68 int buttons_before_separator = 0;
69 Gtk::Widget* last_sep = nullptr;
70 Gtk::FlowBox* last_box = nullptr;
72
73 // We recurse from the ScrolledWindow, not this, to skip context PopoverMenu
74 for_each_descendant(tool_toolbar, [&](Gtk::Widget &widget) {
75 if (auto const flowbox = dynamic_cast<Gtk::FlowBox *>(&widget)) {
76 flowbox->set_visible(true);
77 flowbox->set_max_children_per_line(1);
78 last_box = flowbox;
79 } else if (auto const btn = dynamic_cast<Gtk::Button *>(&widget)) {
80 auto const name = sp_get_action_target(btn);
81 auto show = prefs->getBool(get_tool_visible_button_path(name), true);
82 auto const parent = btn->get_parent();
83 if (show) {
84 parent->set_visible(true);
85 ++buttons_before_separator;
86 // keep the max_children up to date improves display.
87 last_box->set_max_children_per_line(buttons_before_separator);
88 last_sep = nullptr;
89 } else {
90 parent->set_visible(false);
91 }
92 } else if (auto const sep = dynamic_cast<Gtk::Separator *>(&widget)) {
93 if (buttons_before_separator <= 0) {
94 sep->set_visible(false);
95 } else {
96 sep->set_visible(true);
97 buttons_before_separator = 0;
98 last_sep = sep;
99 }
100 }
102 });
103
104 if (last_sep) {
105 // hide trailing separator
106 last_sep->set_visible(false);
107 }
108}
109
110// We should avoid passing in the window in Gtk4 by turning "tool_preferences()" into an action.
111std::unique_ptr<UI::Widget::PopoverMenu> ToolToolbar::makeContextMenu(InkscapeWindow *window)
112{
113 Glib::ustring icon_name;
115 if (prefs->getInt("/theme/menuIcons", true)) {
116 icon_name = "preferences-system";
117 }
118
119 auto &item = *Gtk::make_managed<UI::Widget::PopoverMenuItem>(_("Open tool preferences"), false, icon_name);
120 item.signal_activate().connect([=, this] {
123 });
124
125 auto menu = std::make_unique<UI::Widget::PopoverMenu>(Gtk::PositionType::BOTTOM);
126 menu->append(item);
127 return menu;
128}
129
130void ToolToolbar::showContextMenu(InkscapeWindow *window, Gtk::Button &button, Glib::ustring const &tool_name)
131{
132 _context_menu_tool_name = tool_name;
133 _context_menu->popup_at_center(button);
134}
135
143void ToolToolbar::attachHandlers(Glib::RefPtr<Gtk::Builder> builder, InkscapeWindow *window)
144{
145 for (auto &object : builder->get_objects()) {
146 auto const radio = dynamic_cast<Gtk::ToggleButton *>(object.get());
147 if (!radio) {
148 continue;
149 }
150
151 Glib::VariantBase action_target;
152 radio->get_property("action-target", action_target);
153 if (!action_target.is_of_type(Glib::VARIANT_TYPE_STRING)) {
154 continue;
155 }
156
157 auto tool_name = Glib::ustring((gchar const *)action_target.get_data());
158 auto on_click_pressed = [=, this, tool_name = std::move(tool_name)]
159 (Gtk::GestureClick const &click,
160 int const n_press, double /*x*/, double /*y*/)
161 {
162 // Open tool preferences upon double click
163 auto const button = click.get_current_button();
164 if (button == 1 && n_press == 2) {
165 tool_preferences(tool_name, window);
166 return Gtk::EventSequenceState::CLAIMED;
167 }
168 if (button == 3) {
169 showContextMenu(window, *radio, tool_name);
170 return Gtk::EventSequenceState::CLAIMED;
171 }
172 return Gtk::EventSequenceState::NONE;
173 };
174
175 const auto click = Gtk::GestureClick::create();
176 click->set_button(0); // any
177 click->signal_pressed().connect(Controller::use_state(std::move(on_click_pressed), *click), true);
178 radio->add_controller(click);
179 }
180}
181
182Glib::ustring ToolToolbar::get_tool_visible_button_path(const Glib::ustring& button_action_name) {
183 return Glib::ustring(tools_button_path) + "/show" + button_action_name;
184}
185
186} // namespace Inkscape::UI::Toolbar
187
188/*
189 Local Variables:
190 mode:c++
191 c-file-style:"stroustrup"
192 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
193 indent-tabs-mode:nil
194 fill-column:99
195 End:
196*/
197// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
void tool_preferences(Glib::ustring const &tool, InkscapeWindow *win)
Open preferences page for tool.
Gtk builder utilities.
Preference storage class.
Definition preferences.h:61
bool getBool(Glib::ustring const &pref_path, bool def=false)
Retrieve a Boolean value.
static Preferences * get()
Access the singleton Preferences object.
int getInt(Glib::ustring const &pref_path, int def=0)
Retrieve an integer.
std::unique_ptr< PreferencesObserver > createObserver(Glib::ustring path, std::function< void(const Preferences::Entry &new_value)> callback)
Create an observer watching preference 'path' and calling provided function when preference changes.
void attachHandlers(Glib::RefPtr< Gtk::Builder > builder, InkscapeWindow *window)
Attach handlers to all tool buttons, so that double-clicking on a tool in the toolbar opens up that t...
ToolToolbar(InkscapeWindow *window)
std::unique_ptr< UI::Widget::PopoverMenu > _context_menu
Inkscape::PrefObserver buttons_pref_observer
static constexpr const char * tools_button_path
void set_visible_buttons(Gtk::ScrolledWindow &tool_toolbar)
void showContextMenu(InkscapeWindow *window, Gtk::Button &button, Glib::ustring const &tool_name)
std::unique_ptr< UI::Widget::PopoverMenu > makeContextMenu(InkscapeWindow *window)
static Glib::ustring get_tool_visible_button_path(const Glib::ustring &button_action_name)
UI::Widget::PopoverBin _popoverbin
void setPopover(Gtk::Popover *popover)
Definition popover-bin.h:24
void setChild(Gtk::Widget *child)
Definition popover-bin.h:23
Utilities to more easily use Gtk::EventController & subclasses like Gesture.
static char const *const parent
Definition dir-util.cpp:70
SPItem * item
Inkscape - An SVG editor.
auto use_state(Slot &&slot)
Definition controller.h:43
static void on_click_pressed(int n_press, double x, double y, Gtk::GestureClick &click, PopupMenuSlot const &slot)
Gtk::Widget * for_each_descendant(Gtk::Widget &widget, Func &&func)
Like for_each_child() but also tests the initial widget & recurses through childrenʼs children.
Definition util.h:119
Glib::RefPtr< Gtk::Builder > create_builder(const char *filename)
static void append(std::vector< T > &target, std::vector< T > &&source)
A replacement for GTK3ʼs Gtk::MenuItem, as removed in GTK4.
A replacement for GTK3ʼs Gtk::Menu, as removed in GTK4.
Glib::ustring sp_get_action_target(Gtk::Widget *widget)
Get string action target, if available.
Glib::ustring name
Definition toolbars.cpp:55
Glib::RefPtr< Gtk::Builder > builder