Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
rect-toolbar.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
5/* Authors:
6 * MenTaLguY <mental@rydia.net>
7 * Lauris Kaplinski <lauris@kaplinski.com>
8 * bulia byak <buliabyak@users.sf.net>
9 * Frank Felfe <innerspace@iname.com>
10 * John Cliff <simarilius@yahoo.com>
11 * David Turner <novalis@gnu.org>
12 * Josh Andler <scislac@scislac.com>
13 * Jon A. Cruz <jon@joncruz.org>
14 * Maximilian Albert <maximilian.albert@gmail.com>
15 * Tavmjong Bah <tavmjong@free.fr>
16 * Abhishek Sharma
17 * Kris De Gussem <Kris.DeGussem@gmail.com>
18 * Vaibhav Malik <vaibhavmalik2018@gmail.com>
19 *
20 * Copyright (C) 2004 David Turner
21 * Copyright (C) 2003 MenTaLguY
22 * Copyright (C) 1999-2011 authors
23 * Copyright (C) 2001-2002 Ximian, Inc.
24 *
25 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
26 */
27
28#include "rect-toolbar.h"
29
30#include <glibmm/i18n.h>
31#include <gtkmm/adjustment.h>
32#include <gtkmm/box.h>
33#include <gtkmm/builder.h>
34#include <gtkmm/button.h>
35#include <gtkmm/label.h>
36
37#include "desktop.h"
38#include "document-undo.h"
39#include "object/sp-namedview.h"
40#include "object/sp-rect.h"
41#include "selection.h"
42#include "ui/builder-utils.h"
43#include "ui/icon-names.h"
44#include "ui/tools/rect-tool.h"
45#include "ui/util.h"
50
55
56namespace Inkscape::UI::Toolbar {
57
58struct RectToolbar::DerivedSpinButton : UI::Widget::SpinButton
59{
60 using Getter = double (SPRect::*)() const;
61 using Setter = void (SPRect::*)(double);
62
63 DerivedSpinButton(BaseObjectType *cobject, Glib::RefPtr<Gtk::Builder> const &, char const *name, Getter getter, Setter setter)
64 : UI::Widget::SpinButton(cobject)
65 , name{name}
66 , getter{getter}
67 , setter{setter}
68 {}
69
70 char const *name;
71 Getter getter;
72 Setter setter;
73};
74
76 : RectToolbar{create_builder("toolbar-rect.ui")}
77{}
78
79RectToolbar::RectToolbar(Glib::RefPtr<Gtk::Builder> const &builder)
80 : Toolbar{get_widget<Gtk::Box>(builder, "rect-toolbar")}
81 , _tracker{std::make_unique<UnitTracker>(Util::UNIT_TYPE_LINEAR)}
82 , _mode_item{UI::get_widget<Gtk::Label>(builder, "_mode_item")}
83 , _not_rounded{UI::get_widget<Gtk::Button>(builder, "_not_rounded")}
84 , _width_item{UI::get_derived_widget<DerivedSpinButton>(builder, "_width_item", "width", &SPRect::getVisibleWidth, &SPRect::setVisibleWidth)}
85 , _height_item{UI::get_derived_widget<DerivedSpinButton>(builder, "_height_item", "height", &SPRect::getVisibleHeight, &SPRect::setVisibleHeight)}
86 , _rx_item{UI::get_derived_widget<DerivedSpinButton>(builder, "_rx_item", "rx", &SPRect::getVisibleRx, &SPRect::setVisibleRx)}
87 , _ry_item{UI::get_derived_widget<DerivedSpinButton>(builder, "_ry_item", "ry", &SPRect::getVisibleRy, &SPRect::setVisibleRy)}
88{
89 auto unit_menu = _tracker->create_tool_item(_("Units"), (""));
90 get_widget<Gtk::Box>(builder, "unit_menu_box").append(*unit_menu);
91
92 _not_rounded.signal_clicked().connect([this] { _setDefaults(); });
93
94 for (auto sb : _getDerivedSpinButtons()) {
95 auto const adj = sb->get_adjustment();
96 auto const path = Glib::ustring{"/tools/shapes/rect/"} + sb->name;
97 auto const val = Preferences::get()->getDouble(path, 0);
98 adj->set_value(Quantity::convert(val, "px", _tracker->getActiveUnit()));
99 adj->signal_value_changed().connect([this, sb] { _valueChanged(*sb); });
100 _tracker->addAdjustment(adj->gobj());
101 sb->addUnitTracker(_tracker.get());
102 sb->setDefocusTarget(this);
103 }
104
105 _width_item.set_custom_numeric_menu_data({
106 {1, ""},
107 {2, ""},
108 {3, ""},
109 {5, ""},
110 {10, ""},
111 {20, ""},
112 {50, ""},
113 {100, ""},
114 {200, ""},
115 {500, ""}
116 });
117
118 _height_item.set_custom_numeric_menu_data({
119 {1, ""},
120 {2, ""},
121 {3, ""},
122 {5, ""},
123 {10, ""},
124 {20, ""},
125 {50, ""},
126 {100, ""},
127 {200, ""},
128 {500, ""}
129 });
130
131 _rx_item.set_custom_numeric_menu_data({
132 {0.5, _("not rounded")},
133 {1, ""},
134 {2, ""},
135 {3, ""},
136 {5, ""},
137 {10, ""},
138 {20, ""},
139 {50, ""},
140 {100, ""}
141 });
142
143 _ry_item.set_custom_numeric_menu_data({
144 {0.5, _("not rounded")},
145 {1, ""},
146 {2, ""},
147 {3, ""},
148 {5, ""},
149 {10, ""},
150 {20, ""},
151 {50, ""},
152 {100, ""}
153 });
154
156}
157
158RectToolbar::~RectToolbar() = default;
159
161{
162 if (_desktop) {
163 _selection_changed_conn.disconnect();
164
165 if (_repr) {
166 _detachRepr();
167 }
168 }
169
171
172 if (_desktop) {
173 auto sel = _desktop->getSelection();
175 _selectionChanged(sel); // Synthesize an emission to trigger the update
176
177 _sensitivize();
178 }
179}
180
182{
183 _tracker->setActiveUnit(unit);
184}
185
187{
188 assert(!_repr);
189 _repr = repr;
190 _rect = rect;
192 _repr->addObserver(*this);
193}
194
196{
197 assert(_repr);
198 _repr->removeObserver(*this);
200 _repr = nullptr;
201 _rect = nullptr;
203}
204
205void RectToolbar::_valueChanged(DerivedSpinButton &btn)
206{
207 // quit if run by the XML listener or a unit change
208 if (_blocker.pending() || _tracker->isUpdating()) {
209 return;
210 }
211
212 // in turn, prevent XML listener from responding
213 auto guard = _blocker.block();
214
215 auto const adj = btn.get_adjustment();
216
218 auto const path = Glib::ustring{"/tools/shapes/rect/"} + btn.name;
219 Preferences::get()->setDouble(path, Quantity::convert(adj->get_value(), _tracker->getActiveUnit(), "px"));
220 }
221
222 bool modified = false;
223 for (auto item : _desktop->getSelection()->items()) {
224 if (auto rect = cast<SPRect>(item)) {
225 if (adj->get_value() != 0) {
226 (rect->*btn.setter)(Quantity::convert(adj->get_value(), _tracker->getActiveUnit(), "px"));
227 } else {
228 rect->removeAttribute(btn.name);
229 }
230 modified = true;
231 }
232 }
233
234 _sensitivize();
235
236 if (modified) {
237 DocumentUndo::done(_desktop->getDocument(), _("Change rectangle"), INKSCAPE_ICON("draw-rectangle"));
238 }
239}
240
242{
243 bool disabled = _rx_item.get_adjustment()->get_value() == 0 &&
244 _ry_item.get_adjustment()->get_value() == 0 &&
245 _single; // only for a single selected rect (for now)
246 _not_rounded.set_sensitive(!disabled);
247}
248
250{
251 _rx_item.get_adjustment()->set_value(0.0);
252 _ry_item.get_adjustment()->set_value(0.0);
253 _sensitivize();
254}
255
257{
258 if (_repr) {
259 _detachRepr();
260 }
261
262 int n_selected = 0;
263 XML::Node *repr = nullptr;
264 SPRect *rect = nullptr;
265
266 for (auto item : selection->items()) {
267 if (auto r = cast<SPRect>(item)) {
268 n_selected++;
269 repr = r->getRepr();
270 rect = r;
271 }
272 }
273
274 _single = n_selected == 1;
275
276 if (_single) {
277 _attachRepr(repr, rect);
278 _queueUpdate();
279 }
280
281 _mode_item.set_markup(n_selected == 0 ? _("<b>New:</b>") : _("<b>Change:</b>"));
282 _width_item.set_sensitive(n_selected > 0);
283 _height_item.set_sensitive(n_selected > 0);
284
285 if (!_single) { // otherwise handled by _queueUpdate
286 _sensitivize();
287 }
288}
289
291{
292 assert(_repr);
293 assert(_rect);
294
295 // quit if run by the UI callbacks
296 if (_blocker.pending()) {
297 return;
298 }
299
300 _queueUpdate();
301}
302
303// Todo: Code duplication; move into Toolbar container
304// Todo: Similarly for setDefocusWidget() handling.
306{
307 if (_tick_callback) {
308 return;
309 }
310
311 _tick_callback = add_tick_callback([this] (Glib::RefPtr<Gdk::FrameClock> const &) {
312 _update();
313 _tick_callback = 0;
314 return false;
315 });
316}
317
319{
320 if (!_tick_callback) {
321 return;
322 }
323
324 remove_tick_callback(_tick_callback);
325 _tick_callback = 0;
326}
327
329{
330 assert(_repr);
331 assert(_rect);
332
333 // prevent UI callbacks from responding
334 auto guard = _blocker.block();
335
336 for (auto sb : _getDerivedSpinButtons()) {
337 sb->get_adjustment()->set_value(Quantity::convert((_rect->*sb->getter)(), "px", _tracker->getActiveUnit()));
338 }
339
340 _sensitivize();
341}
342
343} // namespace Inkscape::UI::Toolbar
344
345/*
346 Local Variables:
347 mode:c++
348 c-file-style:"stroustrup"
349 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
350 indent-tabs-mode:nil
351 fill-column:99
352 End:
353*/
354// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8 :
Gtk builder utilities.
static void done(SPDocument *document, Glib::ustring const &event_description, Glib::ustring const &undo_icon, unsigned int object_modified_tag=0)
static bool getUndoSensitive(SPDocument const *document)
SPItemRange items()
Returns a range of selected SPItems.
Definition object-set.h:255
double getDouble(Glib::ustring const &pref_path, double def=0.0, Glib::ustring const &unit="")
Retrieve a floating point value.
static Preferences * get()
Access the singleton Preferences object.
void setDouble(Glib::ustring const &pref_path, double value)
Set a floating point value.
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
std::unique_ptr< UI::Widget::UnitTracker > _tracker
void _valueChanged(DerivedSpinButton &btn)
void setDesktop(SPDesktop *desktop) override
void setActiveUnit(Util::Unit const *unit) override
sigc::connection _selection_changed_conn
void _attachRepr(XML::Node *repr, SPRect *rect)
void _selectionChanged(Selection *selection)
void notifyAttributeChanged(XML::Node &node, GQuark name, Util::ptr_shared old_value, Util::ptr_shared new_value) override
Attribute change callback.
Base class for all tool toolbars.
Definition toolbar.h:72
virtual void setDesktop(SPDesktop *desktop)
Definition toolbar.h:76
Interface for refcounted XML nodes.
Definition node.h:80
virtual void addObserver(NodeObserver &observer)=0
Add an object that will be notified of the changes to this node.
virtual void removeObserver(NodeObserver &observer)=0
Remove an object from the list of observers.
scoped_block block()
To do: update description of desktop.
Definition desktop.h:149
SPDocument * getDocument() const
Definition desktop.h:189
Inkscape::Selection * getSelection() const
Definition desktop.h:188
A combobox that can be displayed in a toolbar.
Editable view implementation.
TODO: insert short description here.
Macro for icon names used in Inkscape.
SPItem * item
Definition desktop.h:50
static R & anchor(R &r)
Increments the reference count of a anchored object.
Definition gc-anchored.h:92
static R & release(R &r)
Decrements the reference count of a anchored object.
W & get_widget(const Glib::RefPtr< Gtk::Builder > &builder, const char *id)
W & get_derived_widget(const Glib::RefPtr< Gtk::Builder > &builder, const char *id, Args &&... args)
Glib::RefPtr< Gtk::Builder > create_builder(const char *filename)
Miscellaneous supporting code.
Definition document.h:93
STL namespace.
guint32 GQuark
SPDesktop * desktop
Glib::ustring name
Definition toolbars.cpp:55
Glib::RefPtr< Gtk::Builder > builder
TODO: insert short description here.