Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
box3d-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 "box3d-toolbar.h"
29
30#include <glibmm/i18n.h>
31#include <gtkmm/adjustment.h>
32#include <gtkmm/togglebutton.h>
33
34#include "desktop.h"
35#include "document-undo.h"
36#include "document.h"
37#include "object/box3d.h"
38#include "object/persp3d.h"
39#include "selection.h"
40#include "ui/builder-utils.h"
41#include "ui/icon-names.h"
42#include "ui/tools/box3d-tool.h"
44
46
47namespace Inkscape::UI::Toolbar {
48
52
53Box3DToolbar::Box3DToolbar(Glib::RefPtr<Gtk::Builder> const &builder)
54 : Toolbar{get_widget<Gtk::Box>(builder, "box3d-toolbar")}
55 , _angle_x_item{get_derived_widget<UI::Widget::SpinButton>(builder, "_angle_x_item")}
56 , _vp_x_state_btn{get_widget<Gtk::ToggleButton>(builder, "_vp_x_state_btn")}
57 , _angle_y_item{get_derived_widget<UI::Widget::SpinButton>(builder, "_angle_y_item")}
58 , _vp_y_state_btn{get_widget<Gtk::ToggleButton>(builder, "_vp_y_state_btn")}
59 , _angle_z_item{get_derived_widget<UI::Widget::SpinButton>(builder, "_angle_z_item")}
60 , _vp_z_state_btn{get_widget<Gtk::ToggleButton>(builder, "_vp_z_state_btn")}
61{
62 auto prefs = Preferences::get();
63
64 _vp_x_state_btn.set_active(prefs->getBool("/tools/shapes/3dbox/vp_x_state", true));
65 _vp_x_state_btn.signal_toggled().connect(
66 sigc::bind(sigc::mem_fun(*this, &Box3DToolbar::vp_state_changed), Proj::X));
67
68 _vp_y_state_btn.set_active(prefs->getBool("/tools/shapes/3dbox/vp_y_state", true));
69 _vp_y_state_btn.signal_toggled().connect(
70 sigc::bind(sigc::mem_fun(*this, &Box3DToolbar::vp_state_changed), Proj::Y));
71
72 _vp_z_state_btn.set_active(prefs->getBool("/tools/shapes/3dbox/vp_z_state", true));
73 _vp_z_state_btn.signal_toggled().connect(
74 sigc::bind(sigc::mem_fun(*this, &Box3DToolbar::vp_state_changed), Proj::Z));
75
79
81 {135, ""},
82 {150, ""},
83 {165, ""},
84 {180, ""},
85 {195, ""},
86 {210, ""},
87 {235, ""}
88 });
89
91 {270, ""},
92 });
93
95 {-45, ""},
96 {-30, ""},
97 {-15, ""},
98 {0, ""},
99 {15, ""},
100 {30, ""},
101 {45, ""}
102 });
103
105}
106
108{
109 if (_desktop) {
110 _selection_changed_conn.disconnect();
111
112 if (_repr) {
113 _detachRepr();
114 }
115 }
116
118
119 if (_desktop) {
120 auto sel = _desktop->getSelection();
122 _selectionChanged(sel); // Synthesize an emission to trigger the update
123 }
124}
125
127{
128 assert(!_repr);
129 _repr = repr;
130 _persp = persp;
132 _repr->addObserver(*this);
133}
134
136{
137 assert(_repr);
138 _repr->removeObserver(*this);
140 _repr = nullptr;
141 _persp = nullptr;
143}
144
146{
147 auto const path = "/tools/shapes/3dbox/" + name;
148 auto const val = Preferences::get()->getDouble(path, 30);
149
150 auto adj = btn.get_adjustment();
151 adj->set_value(val);
152
153 adj->signal_value_changed().connect(
154 sigc::bind(sigc::mem_fun(*this, &Box3DToolbar::angle_value_changed), adj, axis));
155
156 btn.setDefocusTarget(this);
157}
158
159void Box3DToolbar::angle_value_changed(Glib::RefPtr<Gtk::Adjustment> const &adj, Proj::Axis axis)
160{
161 auto document = _desktop->getDocument();
162
163 // quit if run by the attr_changed or selection changed listener
164 if (_blocker.pending()) {
165 return;
166 }
167
168 // in turn, prevent listener from responding
169 auto guard = _blocker.block();
170
171 auto const sel_persps = _desktop->getSelection()->perspList();
172 if (sel_persps.empty()) {
173 // this can happen when the document is created; we silently ignore it
174 return;
175 }
176 auto const persp = sel_persps.front();
177
178 persp->perspective_impl->tmat.set_infinite_direction(axis, adj->get_value());
179 persp->updateRepr();
180
181 // TODO: use the correct axis here, too
182 DocumentUndo::maybeDone(document, "perspangle", _("3D Box: Change perspective (angle of infinite axis)"), INKSCAPE_ICON("draw-cuboid"));
183}
184
186{
187 // TODO: Take all selected perspectives into account
188 auto const sel_persps = _desktop->getSelection()->perspList();
189 if (sel_persps.empty()) {
190 // this can happen when the document is created; we silently ignore it
191 return;
192 }
193 auto const persp = sel_persps.front();
194
195 bool set_infinite = false;
196
197 switch(axis) {
198 case Proj::X:
199 set_infinite = _vp_x_state_btn.get_active();
200 break;
201 case Proj::Y:
202 set_infinite = _vp_y_state_btn.get_active();
203 break;
204 case Proj::Z:
205 set_infinite = _vp_z_state_btn.get_active();
206 break;
207 default:
208 return;
209 }
210
211 persp->set_VP_state(axis, set_infinite ? Proj::VP_INFINITE : Proj::VP_FINITE);
212}
213
214// FIXME: This should rather be put into persp3d-reference.cpp or something similar so that it reacts upon each
215// change of the perspective, and not of the current selection (but how to refer to the toolbar then?)
217{
218 // Here the following should be done: If all selected boxes have finite VPs in a certain direction,
219 // disable the angle entry fields for this direction (otherwise entering a value in them should only
220 // update the perspectives with infinite VPs and leave the other ones untouched).
221
222 if (_repr) {
223 _detachRepr();
224 }
225
226 auto box = cast<SPBox3D>(selection->singleItem());
227 if (!box) {
228 return;
229 }
230
231 // FIXME: Also deal with multiple selected boxes
232 auto persp = box->get_perspective();
233 if (!persp) {
234 g_warning("Box has no perspective set!");
235 return;
236 }
237
238 _attachRepr(persp->getRepr(), persp);
239 _queueUpdate();
240
241 selection->document()->setCurrentPersp3D(_persp);
242 Preferences::get()->setString("/tools/shapes/3dbox/persp", _repr->attribute("id"));
243}
244
245void Box3DToolbar::set_button_and_adjustment(Proj::Axis axis, UI::Widget::SpinButton &spin_btn, Gtk::ToggleButton &toggle_btn)
246{
247 // TODO: Take all selected perspectives into account but don't touch the state button if not all of them
248 // have the same state (otherwise a call to box3d_vp_z_state_changed() is triggered and the states
249 // are reset).
250 bool is_infinite = !Persp3D::VP_is_finite(_persp->perspective_impl.get(), axis);
251
252 toggle_btn.set_active(is_infinite);
253 spin_btn.set_sensitive(is_infinite);
254
255 if (is_infinite) {
256 double angle = _persp->get_infinite_angle(axis);
257 if (angle != Geom::infinity()) { // FIXME: We should catch this error earlier (don't show the spinbutton at all)
258 spin_btn.get_adjustment()->set_value(Geom::deg_from_rad(Geom::Angle::from_degrees(angle).radians0()));
259 }
260 }
261}
262
264{
265 assert(_repr);
266 assert(_persp);
267
268 // quit if run by the UI callbacks
269 if (_blocker.pending()) {
270 return;
271 }
272
274 _queueUpdate();
275}
276
278{
279 if (_tick_callback) {
280 return;
281 }
282
283 _tick_callback = add_tick_callback([this] (Glib::RefPtr<Gdk::FrameClock> const &) {
284 _update();
285 _tick_callback = 0;
286 return false;
287 });
288}
289
291{
292 if (!_tick_callback) {
293 return;
294 }
295
296 remove_tick_callback(_tick_callback);
297 _tick_callback = 0;
298}
299
301{
302 assert(_repr);
303 assert(_persp);
304
305 // prevent UI callbacks from responding
306 auto guard = _blocker.block();
307
311}
312
313} // namespace Inkscape::UI::Toolbar
314
315/*
316 Local Variables:
317 mode:c++
318 c-file-style:"stroustrup"
319 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
320 indent-tabs-mode:nil
321 fill-column:99
322 End:
323*/
324// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
Gtk builder utilities.
static Angle from_degrees(Coord d)
Create an angle from its measure in degrees.
Definition angle.h:136
static void maybeDone(SPDocument *document, const gchar *keyconst, Glib::ustring const &event_description, Glib::ustring const &undo_icon, unsigned int object_modified_tag=0)
SPDocument * document()
Returns the document the selection is bound to.
Definition object-set.h:397
SPItem * singleItem()
Returns a single selected item.
std::list< Persp3D * > const perspList()
Returns a list of all perspectives which have a 3D box in the current selection.
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 setString(Glib::ustring const &pref_path, Glib::ustring const &value)
Set an UTF-8 string 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
UI::Widget::SpinButton & _angle_x_item
void _attachRepr(XML::Node *repr, Persp3D *persp)
UI::Widget::SpinButton & _angle_z_item
void setDesktop(SPDesktop *desktop) override
void _selectionChanged(Selection *selection)
void setup_derived_spin_button(UI::Widget::SpinButton &btn, Glib::ustring const &name, Proj::Axis axis)
void angle_value_changed(Glib::RefPtr< Gtk::Adjustment > const &adj, Proj::Axis axis)
void notifyAttributeChanged(XML::Node &node, GQuark name, Util::ptr_shared old_value, Util::ptr_shared new_value) override
Attribute change callback.
UI::Widget::SpinButton & _angle_y_item
void set_button_and_adjustment(Proj::Axis axis, UI::Widget::SpinButton &spin_btn, Gtk::ToggleButton &toggle_btn)
Base class for all tool toolbars.
Definition toolbar.h:72
virtual void setDesktop(SPDesktop *desktop)
Definition toolbar.h:76
SpinButton widget, that allows entry of simple math expressions (also units, when linked with UnitMen...
Definition spinbutton.h:52
void setDefocusTarget(decltype(_defocus_target) target)
Definition spinbutton.h:127
void set_custom_numeric_menu_data(NumericMenuData &&custom_menu_data)
Interface for refcounted XML nodes.
Definition node.h:80
virtual char const * attribute(char const *key) const =0
Get the string representation of a node's attribute.
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()
double get_infinite_angle(Proj::Axis axis) const
Definition persp3d.cpp:334
void update_box_reprs()
Definition persp3d.cpp:444
std::unique_ptr< Persp3DImpl > perspective_impl
Definition persp3d.h:65
static bool VP_is_finite(Persp3DImpl *persp_impl, Proj::Axis axis)
Definition persp3d.cpp:339
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
void setCurrentPersp3D(Persp3D *const persp)
Definition document.cpp:270
Editable view implementation.
TODO: insert short description here.
constexpr Coord infinity()
Get a value representing infinity.
Definition coord.h:88
Macro for icon names used in Inkscape.
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)
@ VP_FINITE
Definition axis-manip.h:24
@ VP_INFINITE
Definition axis-manip.h:25
guint32 GQuark
SPDesktop * desktop
Glib::ustring name
Definition toolbars.cpp:55
Glib::RefPtr< Gtk::Builder > builder