Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
dialog-window.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
13#include "dialog-window.h"
14
15#include <glibmm/i18n.h>
16
17#include "document.h"
18#include "inkscape.h"
19#include "inkscape-window.h"
22#include "ui/pack.h"
23#include "ui/shortcuts.h"
24#include "ui/themes.h"
25
26// Sizing constants
27static constexpr int MINIMUM_WINDOW_WIDTH = 210;
28static constexpr int MINIMUM_WINDOW_HEIGHT = 320;
29static constexpr int INITIAL_WINDOW_WIDTH = 360;
30static constexpr int INITIAL_WINDOW_HEIGHT = 520;
31static constexpr int WINDOW_DROPZONE_SIZE = 10;
32static constexpr int WINDOW_DROPZONE_SIZE_LARGE = 16;
33static constexpr int NOTEBOOK_TAB_HEIGHT = 36;
34
35namespace Inkscape::UI::Dialog {
36
37[[nodiscard]] static auto get_max_margin(Gtk::Widget const &widget)
38{
39 return std::max({widget.get_margin_top(), widget.get_margin_bottom(),
40 widget.get_margin_start(), widget.get_margin_end()});
41}
42
43// Create a dialog window and move page from old notebook.
44DialogWindow::DialogWindow(InkscapeWindow *inkscape_window, Gtk::Widget *page)
45 : Gtk::Window()
46 , _app(InkscapeApplication::instance())
47 , _inkscape_window(inkscape_window)
48 , _title(_("Dialog Window"))
49{
50 g_assert(_app != nullptr);
51 g_assert(_inkscape_window != nullptr);
52
53 // ============ Initialization ===============
54 set_name("DialogWindow");
55 set_transient_for(*inkscape_window);
56 _app->gtk_app()->add_window(*this);
57
58 signal_close_request().connect([this]{
60 delete this;
61 return true;
62 }, false); // before GTKʼs default handler, so it wonʼt try to double-delete
63
64 // ================ Window ==================
65 set_title(_title);
66 set_name(_title);
67 int window_width = INITIAL_WINDOW_WIDTH;
68 int window_height = INITIAL_WINDOW_HEIGHT;
69
70 // ================ Shortcuts ================
71 auto& shortcuts_instance = Inkscape::Shortcuts::getInstance();
72 auto shortcut_controller = Gtk::ShortcutController::create(shortcuts_instance.get_liststore());
73 shortcut_controller->set_propagation_phase(Gtk::PropagationPhase::BUBBLE);
74 add_controller(shortcut_controller);
75
76 // =============== Outer Box ================
77 auto const box_outer = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL);
78 set_child(*box_outer);
79
80 // =============== Container ================
81 _container = Gtk::make_managed<DialogContainer>(inkscape_window);
83 auto drop_size = Inkscape::Preferences::get()->getBool("/options/dockingzone/value", true) ? WINDOW_DROPZONE_SIZE / 2 : WINDOW_DROPZONE_SIZE;
84 columns->set_dropzone_sizes(drop_size, drop_size);
85 UI::pack_end(*box_outer, *_container);
86
87 // If there is no page, create an empty Dialogwindow to be populated later
88 if (page) {
89 // ============= Initial Column =============
90 auto col = _container->create_column();
91 auto const column = col.get();
92 columns->append(std::move(col));
93
94 // ============== New Notebook ==============
95 auto nb = std::make_unique<DialogNotebook>(_container);
96 auto const dialog_notebook = nb.get();
97 column->append(std::move(nb));
98 column->set_dropzone_sizes(drop_size, drop_size);
99 dialog_notebook->move_page(*page);
100
101 // Set window title
102 DialogBase *dialog = dynamic_cast<DialogBase *>(page);
103 if (dialog) {
104 _title = dialog->get_name();
105 set_title(_title);
106 }
107
108 // Set window size considering what the dialog needs
109 Gtk::Requisition minimum_size, natural_size;
110 dialog->get_preferred_size(minimum_size, natural_size);
111 int overhead = 2 * (drop_size + get_max_margin(*dialog));
112 int width = natural_size.get_width() + overhead;
113 int height = natural_size.get_height() + overhead + NOTEBOOK_TAB_HEIGHT;
114 window_width = std::max(width, window_width);
115 window_height = std::max(height, window_height);
116 }
117
118 // Set window sizing
120 set_default_size(window_width, window_height);
121
122 if (page) {
124 }
125
126 // To get right symbolic/regular class & other theming, apply themechange after adding children
127 auto const themecontext = INKSCAPE.themecontext;
128 g_assert(themecontext);
129 themecontext->themechangecallback();
130
131 // TODO: Double-check the phase. This needs to be called after default Window handlerʼs CAPTURE
132 auto const key = Gtk::EventControllerKey::create();
133 key->set_propagation_phase(Gtk::PropagationPhase::TARGET);
134 key->signal_key_pressed().connect([this, &key = *key](auto &&...args) { return on_key_pressed(key, args...); }, true);
135 add_controller(key);
136
137 // window is created hidden; don't show it now, its size needs to be restored
138}
139
144{
145 if (!inkscape_window) {
146 std::cerr << "DialogWindow::set_inkscape_window: no inkscape_window!" << std::endl;
147 return;
148 }
149
150 _inkscape_window = inkscape_window;
152}
153
158{
159 g_assert(_app != nullptr);
160 g_assert(_container != nullptr);
161 g_assert(_inkscape_window != nullptr);
162
164 _container->update_dialogs(); // Updating dialogs is not using the _app reference here.
165
166 // Set window title.
167 auto const &dialogs = _container->get_dialogs();
168 if (dialogs.size() > 1) {
169 _title = "Multiple dialogs";
170 } else if (dialogs.size() == 1) {
171 _title = dialogs.begin()->second->get_name();
172 } else {
173 // Should not happen... but does on closing a window!
174 // std::cerr << "DialogWindow::update_dialogs(): No dialogs!" << std::endl;
175 _title = "";
176 }
177
178 auto document_name = _inkscape_window->get_document()->getDocumentName();
179 if (document_name) {
180 set_title(_title + " - " + Glib::ustring(document_name));
181 }
182
183 auto win_action_group = dynamic_cast<Gio::ActionGroup *>(_inkscape_window);
184 if (win_action_group) {
185 // C++ API requires Glib::RefPtr<Gio::ActionGroup>, use C API here.
186 gtk_widget_insert_action_group(Gtk::Widget::gobj(), "win", win_action_group->gobj());
187 } else {
188 std::cerr << "DialogWindow::DialogWindow: Can't find InkscapeWindow Gio:ActionGroup!" << std::endl;
189 }
190
191 insert_action_group("doc", _inkscape_window->get_document()->getActionGroup());
192}
193
200{
201 // Declare variables
202 int width = 0, height = 0;
203 int overhead = 0;
204
205 // Read needed data
206 auto allocation = get_allocation();
207 auto const &dialogs = _container->get_dialogs();
208
209 // Get largest sizes for dialogs
210 for (auto const &[name, dialog] : dialogs) {
211 Gtk::Requisition minimum_size, natural_size;
212 dialog->get_preferred_size(minimum_size, natural_size);
213 width = std::max(natural_size.get_width(), width);
214 height = std::max(natural_size.get_height(), height);
215 overhead = std::max(overhead, get_max_margin(*dialog));
216 }
217
218 // Compute sizes including overhead
219 overhead = 2 * (WINDOW_DROPZONE_SIZE_LARGE + overhead);
220 width += overhead;
221 height += overhead + NOTEBOOK_TAB_HEIGHT;
222
223 // If sizes are lower then current, don't change them
224 if (allocation.get_width() >= width && allocation.get_height() >= height) {
225 return;
226 }
227
228 // Compute largest sizes on both axis
229 width = std::max(width, allocation.get_width());
230 height = std::max(height, allocation.get_height());
231
232 // Resize window
233 set_default_size(width, height);
234
235 // Note: This function also used to maintain the center of the window
236 // before GTK4 removed the ability to do that.
237}
238
239bool DialogWindow::on_key_pressed(Gtk::EventControllerKey &controller,
240 unsigned keyval, unsigned keycode, Gdk::ModifierType state)
241{
242 assert(_inkscape_window);
243 return controller.forward(*_inkscape_window);
244}
245
246} // namespace Inkscape::UI::Dialog
247
248/*
249 Local Variables:
250 mode:c++
251 c-file-style:"stroustrup"
252 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
253 indent-tabs-mode:nil
254 fill-column:99
255 End:
256*/
257// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
uint64_t page
Definition canvas.cpp:171
Gtk::Application * gtk_app()
The Gtk application instance, or NULL if running headless without display.
SPDocument * get_document()
bool getBool(Glib::ustring const &pref_path, bool def=false)
Retrieve a Boolean value.
static Preferences * get()
Access the singleton Preferences object.
static Shortcuts & getInstance(bool init=true)
Definition shortcuts.h:66
DialogBase is the base class for the dialog system.
Definition dialog-base.h:40
Glib::ustring const & get_name() const
Definition dialog-base.h:62
void set_inkscape_window(InkscapeWindow *inkscape_window)
std::multimap< Glib::ustring, DialogBase * > const & get_dialogs() const
std::unique_ptr< DialogMultipaned > create_column()
static DialogManager & singleton()
void store_state(DialogWindow &wnd)
void set_dropzone_sizes(int start, int end)
Set the sizes of the DialogMultipaned dropzones.
void append(std::unique_ptr< Gtk::Widget > child)
void update_dialogs()
Update all dialogs that are owned by the DialogWindow's _container.
DialogWindow(InkscapeWindow *window, Gtk::Widget *page=nullptr)
void set_inkscape_window(InkscapeWindow *window)
Change InkscapeWindow that DialogWindow is linked to.
void update_window_size_to_fit_children()
Update window width and height in order to fit all dialogs inisde its container.
bool on_key_pressed(Gtk::EventControllerKey &controller, unsigned keyval, unsigned keycode, Gdk::ModifierType state)
InkscapeWindow * _inkscape_window
The Inkscape window that dialog window is attached to.
Glib::RefPtr< Gio::SimpleActionGroup > getActionGroup()
Definition document.h:371
char const * getDocumentName() const
basename or other human-readable label for the document.
Definition document.h:236
A base class for all dialogs.
A widget with multiple panes.
static constexpr int INITIAL_WINDOW_HEIGHT
static constexpr int INITIAL_WINDOW_WIDTH
static constexpr int WINDOW_DROPZONE_SIZE
static constexpr int MINIMUM_WINDOW_HEIGHT
static constexpr int WINDOW_DROPZONE_SIZE_LARGE
static constexpr int NOTEBOOK_TAB_HEIGHT
static constexpr int MINIMUM_WINDOW_WIDTH
A window for floating docks.
Inkscape - An SVG editor.
Definition desktop.h:50
Dialog code.
Definition desktop.h:117
static auto get_max_margin(Gtk::Widget const &widget)
static constexpr int height
void pack_end(Gtk::Box &box, Gtk::Widget &child, bool const expand, bool const fill, unsigned const padding)
Adds child to box, packed with reference to the end of box.
Definition pack.cpp:153
static cairo_user_data_key_t key
Helpers for using Gtk::Boxes, encapsulating large changes between GTK3 & GTK4.
double width
Gtk <themes> helper code.
Glib::ustring name
Definition toolbars.cpp:55