Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
dialog-base.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
13#include "dialog-base.h"
14
15#include <gtkmm/eventcontrollerkey.h>
16#include <gtkmm/eventcontrollerscroll.h>
17#include <gtkmm/scrolledwindow.h>
18#include <gtkmm/viewport.h>
19
20#include "desktop.h"
21#include "inkscape.h"
22#include "selection.h"
23#include "ui/dialog-events.h"
25#include "ui/tools/tool-base.h" // get_latin_keyval
26#include "ui/util.h"
27#include "ui/widget/canvas.h"
28
29namespace Inkscape::UI::Dialog {
30
31static void remove_first(Glib::ustring &name, Glib::ustring const &pattern)
32{
33 if (auto const pos = name.find(pattern); pos != name.npos) {
34 name.erase(pos, pattern.size());
35 }
36}
37
44DialogBase::DialogBase(char const * const prefs_path, Glib::ustring dialog_type)
45 : Gtk::Box(Gtk::Orientation::VERTICAL)
46 , _name("DialogBase")
47 , _prefs_path(prefs_path)
48 , _dialog_type{std::move(dialog_type)}
49 , _app(InkscapeApplication::instance())
50{
51 auto const &dialog_data = get_dialog_data();
52 // Derive a pretty display name for the dialog.
53 if (auto const it = dialog_data.find(_dialog_type); it != dialog_data.end()) {
54 _name = it->second.label; // Already translated
55 // remove ellipsis and mnemonics
56 remove_first(_name, "...");
57 remove_first(_name, "…" );
58 remove_first(_name, "_" );
59 _icon_name = it->second.icon_name;
60 }
61
62 set_name(_dialog_type); // Essential for dialog functionality
63 set_margin(1); // Essential for dialog UI
64
65 auto const key = Gtk::EventControllerKey::create();
66 key->set_propagation_phase(Gtk::PropagationPhase::CAPTURE);
67 key->signal_key_pressed().connect([this, &key = *key](auto &&...args) { return on_key_pressed(key, args...); }, true);
68 add_controller(key);
69}
70
75
77 // Update asks the dialogs if they need their Gtk widgets updated.
78 update();
79 // Set the desktop on_map, although we might want to be smarter about this.
80 // Note: Inkscape::Application::instance().active_desktop() is used here, as it contains current desktop at
81 // the time of dialog creation. Formerly used _app.get_active_view() did not at application start-up.
83 parent_type::on_map();
84}
85
86bool DialogBase::on_key_pressed(Gtk::EventControllerKey const &controller,
87 unsigned keyval, unsigned keycode, Gdk::ModifierType state)
88{
89 switch (Inkscape::UI::Tools::get_latin_keyval(controller, keyval, keycode, state)) {
90 case GDK_KEY_Escape:
92 return true;
93 }
94
95 return false;
96}
97
102{
103 Gtk::Notebook *notebook = dynamic_cast<Gtk::Notebook *>(get_parent()->get_parent());
104 if (notebook) {
105 // Switch notebook to this dialog.
106 notebook->set_current_page(notebook->page_num(*this));
107 notebook->add_css_class("blink");
108
109 // Add timer to turn off blink.
110 sigc::slot<bool ()> slot = sigc::mem_fun(*this, &DialogBase::blink_off);
111 sigc::connection connection = Glib::signal_timeout().connect(slot, 1000); // msec
112 }
113}
114
116 set_visible(true);
117 if (auto window = dynamic_cast<Gtk::Window*>(get_root())) {
118 window->present();
119 }
120 // widget that had focus, if any
121 if (auto child = get_focus_child()) {
122 child->grab_focus();
123 } else {
124 // find first focusable widget
125 if (auto const child = find_focusable_widget(*this)) {
126 child->grab_focus();
127 }
128 }
129
130}
131
133 if (auto wnd = dynamic_cast<Gtk::Window*>(get_root())) {
134 // defocus floating dialog:
136
137 // for docked dialogs, move focus to canvas
138 if (auto desktop = getDesktop()) {
139 desktop->getCanvas()->grab_focus();
140 }
141 }
142}
143
148{
149 Gtk::Notebook *notebook = dynamic_cast<Gtk::Notebook *>(get_parent()->get_parent());
150 if (notebook) {
151 notebook->remove_css_class("blink");
152 }
153 return false;
154}
155
160{
161 if (desktop == new_desktop) {
162 return;
163 }
164
165 unsetDesktop();
166
167 if (new_desktop) {
168 desktop = new_desktop;
169
170 if (auto sel = desktop->getSelection()) {
171 selection = sel;
174 if (_showing)
176 });
179 _modified_flags = flags;
180 if (_showing)
182 });
183 }
184
185 _doc_replaced = desktop->connectDocumentReplaced(sigc::hide<0>(sigc::mem_fun(*this, &DialogBase::setDocument)));
188
189 if (desktop->getSelection()) {
191 }
192 set_sensitive(true);
193 } else {
195 }
196
198}
199
200void DialogBase::fix_inner_scroll(Gtk::ScrolledWindow &scrollwin)
201{
202 Gtk::Widget *child = nullptr;
203 if (auto const viewport = dynamic_cast<Gtk::Viewport *>(scrollwin.get_child())) {
204 child = viewport->get_child();
205 } else {
206 child = scrollwin.get_child();
207 }
208 if (!child) {
209 return;
210 }
211
212 auto controller = Gtk::EventControllerScroll::create();
213 controller->set_flags(Gtk::EventControllerScroll::Flags::VERTICAL);
214 controller->signal_scroll().connect(
215 [this, adj = scrollwin.get_vadjustment()](double dx, double dy) -> bool {
216 auto const parentscroll = dynamic_cast<Gtk::ScrolledWindow *>(get_first_child());
217 if (!parentscroll) {
218 return false;
219 }
220
221 if (dy > 0 && adj->get_value() + adj->get_page_size() == adj->get_upper() ||
222 dy < 0 && adj->get_value() == adj->get_lower()) {
223 auto parent_adj = parentscroll->get_vadjustment();
224 if (parent_adj) {
225 double new_value = parent_adj->get_value() + dy * parent_adj->get_step_increment();
226 new_value = std::max(parent_adj->get_lower(),
227 std::min(parent_adj->get_upper() - parent_adj->get_page_size(), new_value));
228 parent_adj->set_value(new_value);
229 }
230 return true;
231 }
232 return false;
233 },
234 false);
235 child->add_controller(controller);
236}
237
241void
242DialogBase::setShowing(bool showing) {
243 _showing = showing;
244 if (showing && _changed_while_hidden) {
245 selectionChanged(getSelection());
246 _changed_while_hidden = false;
247 }
248 if (showing && _modified_while_hidden) {
249 selectionModified(getSelection(), _modified_flags);
250 _modified_while_hidden = false;
251 }
252}
253
257void DialogBase::unsetDesktop()
258{
259 desktop = nullptr;
260 document = nullptr;
261 selection = nullptr;
262 _desktop_destroyed.disconnect();
263 _doc_replaced.disconnect();
264 _select_changed.disconnect();
265 _select_modified.disconnect();
266}
267
268void DialogBase::desktopDestroyed(SPDesktop* old_desktop)
269{
270 if (old_desktop == desktop && desktop) {
271 unsetDesktop();
272 documentReplaced();
273 desktopReplaced();
274 set_sensitive(false);
275 }
276}
277
281void DialogBase::setDocument(SPDocument *new_document)
282{
283 if (document != new_document) {
284 document = new_document;
285 documentReplaced();
286 }
287}
288
289} // namespace Inkscape::UI::Dialog
290
291/*
292 Local Variables:
293 mode:c++
294 c-file-style:"stroustrup"
295 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
296 indent-tabs-mode:nil
297 fill-column:99
298 End:
299*/
300// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
Inkscape canvas widget.
static Application & instance()
Returns the current Inkscape::Application global object.
Definition inkscape.cpp:152
The set of selected SPObjects for a given document and layer model.
Definition selection.h:80
sigc::connection connectChanged(sigc::slot< void(Selection *)> slot)
Connects a slot to be notified of selection changes.
Definition selection.h:179
sigc::connection connectModified(sigc::slot< void(Selection *, unsigned)> slot)
Connects a slot to be notified of selected object modifications.
Definition selection.h:232
void setDesktop(SPDesktop *new_desktop)
Called when the desktop might have changed for this dialog.
void blink()
Highlight notebook where dialog already exists.
virtual void selectionChanged(Inkscape::Selection *selection)
bool blink_off()
Callback to reset the dialog highlight.
void unsetDesktop()
Called to destruct desktops, must not call virtuals.
virtual void update()
The update() method is essential to Gtk state management.
Definition dialog-base.h:55
void setDocument(SPDocument *new_document)
Called when the document might have changed, called from setDesktop too.
bool on_key_pressed(Gtk::EventControllerKey const &controller, unsigned keyval, unsigned keycode, Gdk::ModifierType state)
void desktopDestroyed(SPDesktop *old_desktop)
virtual void selectionModified(Inkscape::Selection *selection, guint flags)
DialogBase(char const *prefs_path=nullptr, Glib::ustring dialog_type={})
DialogBase constructor.
virtual void desktopReplaced()
Called when the desktop has certainly changed.
void fix_inner_scroll(Gtk::ScrolledWindow &scrollwin)
sigc::connection _desktop_destroyed
SPDesktop * getDesktop() const
Definition dialog-base.h:77
Glib::ustring const _dialog_type
Definition dialog-base.h:87
To do: update description of desktop.
Definition desktop.h:149
Inkscape::UI::Widget::Canvas * getCanvas() const
Definition desktop.h:190
sigc::connection connectDocumentReplaced(F &&slot)
Definition desktop.h:257
SPDocument * getDocument() const
Definition desktop.h:189
Inkscape::Selection * getSelection() const
Definition desktop.h:188
sigc::connection connectDestroy(F &&slot)
Definition desktop.h:253
Typed SVG document implementation.
Definition document.h:101
Editable view implementation.
A base class for all dialogs.
const std::map< std::string, DialogData > & get_dialog_data()
Get the data about all existing dialogs.
Basic dialog info.
void sp_dialog_defocus(Gtk::Window *win)
Remove focus from window to whoever it is transient for.
Event handler for dialog windows.
Definition desktop.h:50
Dialog code.
Definition desktop.h:117
static void set_sensitive(Gtk::SearchEntry2 &entry, bool const sensitive)
static void remove_first(Glib::ustring &name, Glib::ustring const &pattern)
static Glib::ustring const prefs_path
unsigned get_latin_keyval(GtkEventControllerKey const *const controller, unsigned const keyval, unsigned const keycode, GdkModifierType const state, unsigned *consumed_modifiers)
Return the keyval corresponding to the event controller key in Latin group.
Gtk::Widget * find_focusable_widget(Gtk::Widget &parent)
This function traverses a tree of widgets searching for first focusable widget.
Definition util.cpp:185
STL namespace.
static cairo_user_data_key_t key
Ocnode * child[8]
Definition quantize.cpp:33
SPDesktop * desktop
Glib::ustring name
Definition toolbars.cpp:55