1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /**
3 * @file
4 * Calligraphy aux toolbar
5 */
6 /* Authors:
7 * MenTaLguY <mental@rydia.net>
8 * Lauris Kaplinski <lauris@kaplinski.com>
9 * bulia byak <buliabyak@users.sf.net>
10 * Frank Felfe <innerspace@iname.com>
11 * John Cliff <simarilius@yahoo.com>
12 * David Turner <novalis@gnu.org>
13 * Josh Andler <scislac@scislac.com>
14 * Jon A. Cruz <jon@joncruz.org>
15 * Maximilian Albert <maximilian.albert@gmail.com>
16 * Tavmjong Bah <tavmjong@free.fr>
17 * Abhishek Sharma
18 * Kris De Gussem <Kris.DeGussem@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 "calligraphy-toolbar.h"
29
30 #include <glibmm/i18n.h>
31 #include <gtkmm/comboboxtext.h>
32 #include <gtkmm/separatortoolitem.h>
33
34 #include "desktop.h"
35 #include "document-undo.h"
36 #include "ui/dialog/calligraphic-profile-rename.h"
37 #include "ui/icon-names.h"
38 #include "ui/simple-pref-pusher.h"
39 #include "ui/uxmanager.h"
40 #include "ui/widget/canvas.h"
41 #include "ui/widget/combo-tool-item.h"
42 #include "ui/widget/spin-button-tool-item.h"
43 #include "ui/widget/unit-tracker.h"
44
45 using Inkscape::DocumentUndo;
46 using Inkscape::UI::Widget::UnitTracker;
47 using Inkscape::Util::Quantity;
48 using Inkscape::Util::Unit;
49 using Inkscape::Util::unit_table;
50
get_presets_list()51 std::vector<Glib::ustring> get_presets_list() {
52
53 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
54
55 std::vector<Glib::ustring> presets = prefs->getAllDirs("/tools/calligraphic/preset");
56
57 return presets;
58 }
59
60 namespace Inkscape {
61 namespace UI {
62 namespace Toolbar {
63
CalligraphyToolbar(SPDesktop * desktop)64 CalligraphyToolbar::CalligraphyToolbar(SPDesktop *desktop)
65 : Toolbar(desktop)
66 , _tracker(new UnitTracker(Inkscape::Util::UNIT_TYPE_LINEAR))
67 , _presets_blocked(false)
68 {
69 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
70 _tracker->prependUnit(unit_table.getUnit("px"));
71 _tracker->changeLabel("%", 0, true);
72 prefs->getBool("/tools/calligraphic/abs_width")
73 ? _tracker->setActiveUnitByLabel(prefs->getString("/tools/calligraphic/unit"))
74 : _tracker->setActiveUnitByLabel("%");
75
76 /*calligraphic profile */
77 {
78 _profile_selector_combo = Gtk::manage(new Gtk::ComboBoxText());
79 _profile_selector_combo->set_tooltip_text(_("Choose a preset"));
80
81 build_presets_list();
82
83 auto profile_selector_ti = Gtk::manage(new Gtk::ToolItem());
84 profile_selector_ti->add(*_profile_selector_combo);
85 add(*profile_selector_ti);
86
87 _profile_selector_combo->signal_changed().connect(sigc::mem_fun(*this, &CalligraphyToolbar::change_profile));
88 }
89
90 /*calligraphic profile editor */
91 {
92 auto profile_edit_item = Gtk::manage(new Gtk::ToolButton(_("Add/Edit Profile")));
93 profile_edit_item->set_tooltip_text(_("Add or edit calligraphic profile"));
94 profile_edit_item->set_icon_name(INKSCAPE_ICON("document-properties"));
95 profile_edit_item->signal_clicked().connect(sigc::mem_fun(*this, &CalligraphyToolbar::edit_profile));
96 add(*profile_edit_item);
97 }
98
99 add(* Gtk::manage(new Gtk::SeparatorToolItem()));
100
101 {
102 /* Width */
103 std::vector<Glib::ustring> labels = {_("(hairline)"), "", "", "", _("(default)"), "", "", "", "", _("(broad stroke)")};
104 std::vector<double> values = { 1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
105 auto width_val = prefs->getDouble("/tools/calligraphic/width", 15.118);
106 Unit const *unit = unit_table.getUnit(prefs->getString("/tools/calligraphic/unit"));
107 _width_adj = Gtk::Adjustment::create(Quantity::convert(width_val, "px", unit), 0.001, 100, 1.0, 10.0);
108 auto width_item =
109 Gtk::manage(new UI::Widget::SpinButtonToolItem("calligraphy-width", _("Width:"), _width_adj, 0.001, 3));
110 width_item->set_tooltip_text(_("The width of the calligraphic pen (relative to the visible canvas area)"));
111 width_item->set_custom_numeric_menu_data(values, labels);
112 width_item->set_focus_widget(desktop->canvas);
113 _width_adj->signal_value_changed().connect(sigc::mem_fun(*this, &CalligraphyToolbar::width_value_changed));
114 _widget_map["width"] = G_OBJECT(_width_adj->gobj());
115 // ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
116 add(*width_item);
117 _tracker->addAdjustment(_width_adj->gobj());
118 width_item->set_sensitive(true);
119 }
120
121 /* Unit Menu */
122 {
123 auto unit_menu_ti = _tracker->create_tool_item(_("Units"), "");
124 add(*unit_menu_ti);
125 unit_menu_ti->signal_changed_after().connect(sigc::mem_fun(*this, &CalligraphyToolbar::unit_changed));
126 }
127
128 /* Use Pressure button */
129 {
130 _usepressure = add_toggle_button(_("Pressure"),
131 _("Use the pressure of the input device to alter the width of the pen"));
132 _usepressure->set_icon_name(INKSCAPE_ICON("draw-use-pressure"));
133 _widget_map["usepressure"] = G_OBJECT(_usepressure->gobj());
134 _usepressure_pusher.reset(new SimplePrefPusher(_usepressure, "/tools/calligraphic/usepressure"));
135 _usepressure->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &CalligraphyToolbar::on_pref_toggled),
136 _usepressure,
137 "/tools/calligraphic/usepressure"));
138 }
139
140 /* Trace Background button */
141 {
142 _tracebackground = add_toggle_button(_("Trace Background"),
143 _("Trace the lightness of the background by the width of the pen (white - minimum width, black - maximum width)"));
144 _tracebackground->set_icon_name(INKSCAPE_ICON("draw-trace-background"));
145 _widget_map["tracebackground"] = G_OBJECT(_tracebackground->gobj());
146 _tracebackground_pusher.reset(new SimplePrefPusher(_tracebackground, "/tools/calligraphic/tracebackground"));
147 _tracebackground->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &CalligraphyToolbar::on_pref_toggled),
148 _tracebackground,
149 "/tools/calligraphic/tracebackground"));
150 }
151
152 {
153 /* Thinning */
154 std::vector<Glib::ustring> labels = {_("(speed blows up stroke)"), "", "", _("(slight widening)"), _("(constant width)"), _("(slight thinning, default)"), "", "", _("(speed deflates stroke)")};
155 std::vector<double> values = { -100, -40, -20, -10, 0, 10, 20, 40, 100};
156 auto thinning_val = prefs->getDouble("/tools/calligraphic/thinning", 10);
157 _thinning_adj = Gtk::Adjustment::create(thinning_val, -100, 100, 1, 10.0);
158 auto thinning_item = Gtk::manage(new UI::Widget::SpinButtonToolItem("calligraphy-thinning", _("Thinning:"), _thinning_adj, 1, 0));
159 thinning_item->set_tooltip_text(("How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 makes them broader, 0 makes width independent of velocity)"));
160 thinning_item->set_custom_numeric_menu_data(values, labels);
161 thinning_item->set_focus_widget(desktop->canvas);
162 _thinning_adj->signal_value_changed().connect(sigc::mem_fun(*this, &CalligraphyToolbar::velthin_value_changed));
163 _widget_map["thinning"] = G_OBJECT(_thinning_adj->gobj());
164 add(*thinning_item);
165 thinning_item->set_sensitive(true);
166 }
167
168 {
169 /* Mass */
170 std::vector<Glib::ustring> labels = {_("(no inertia)"), _("(slight smoothing, default)"), _("(noticeable lagging)"), "", "", _("(maximum inertia)")};
171 std::vector<double> values = { 0.0, 2, 10, 20, 50, 100};
172 auto mass_val = prefs->getDouble("/tools/calligraphic/mass", 2.0);
173 _mass_adj = Gtk::Adjustment::create(mass_val, 0.0, 100, 1, 10.0);
174 auto mass_item = Gtk::manage(new UI::Widget::SpinButtonToolItem("calligraphy-mass", _("Mass:"), _mass_adj, 1, 0));
175 mass_item->set_tooltip_text(_("Increase to make the pen drag behind, as if slowed by inertia"));
176 mass_item->set_custom_numeric_menu_data(values, labels);
177 mass_item->set_focus_widget(desktop->canvas);
178 _mass_adj->signal_value_changed().connect(sigc::mem_fun(*this, &CalligraphyToolbar::mass_value_changed));
179 _widget_map["mass"] = G_OBJECT(_mass_adj->gobj());
180 // ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
181 add(*mass_item);
182 mass_item->set_sensitive(true);
183 }
184
185 add(* Gtk::manage(new Gtk::SeparatorToolItem()));
186
187 {
188 /* Angle */
189 std::vector<Glib::ustring> labels = {_("(left edge up)"), "", "", _("(horizontal)"), _("(default)"), "", _("(right edge up)")};
190 std::vector<double> values = { -90, -60, -30, 0, 30, 60, 90};
191 auto angle_val = prefs->getDouble("/tools/calligraphic/angle", 30);
192 _angle_adj = Gtk::Adjustment::create(angle_val, -90.0, 90.0, 1.0, 10.0);
193 _angle_item = Gtk::manage(new UI::Widget::SpinButtonToolItem("calligraphy-angle", _("Angle:"), _angle_adj, 1, 0));
194 _angle_item->set_tooltip_text(_("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"));
195 _angle_item->set_custom_numeric_menu_data(values, labels);
196 _angle_item->set_focus_widget(desktop->canvas);
197 _angle_adj->signal_value_changed().connect(sigc::mem_fun(*this, &CalligraphyToolbar::angle_value_changed));
198 _widget_map["angle"] = G_OBJECT(_angle_adj->gobj());
199 add(*_angle_item);
200 _angle_item->set_sensitive(true);
201 }
202
203 /* Use Tilt button */
204 {
205 _usetilt = add_toggle_button(_("Tilt"),
206 _("Use the tilt of the input device to alter the angle of the pen's nib"));
207 _usetilt->set_icon_name(INKSCAPE_ICON("draw-use-tilt"));
208 _widget_map["usetilt"] = G_OBJECT(_usetilt->gobj());
209 _usetilt_pusher.reset(new SimplePrefPusher(_usetilt, "/tools/calligraphic/usetilt"));
210 _usetilt->signal_toggled().connect(sigc::mem_fun(*this, &CalligraphyToolbar::tilt_state_changed));
211 _angle_item->set_sensitive(!prefs->getBool("/tools/calligraphic/usetilt", true));
212 _usetilt->set_active(prefs->getBool("/tools/calligraphic/usetilt", true));
213 }
214
215 {
216 /* Fixation */
217 std::vector<Glib::ustring> labels = {_("(perpendicular to stroke, \"brush\")"), "", "", "", _("(almost fixed, default)"), _("(fixed by Angle, \"pen\")")};
218 std::vector<double> values = { 0, 20, 40, 60, 90, 100};
219 auto flatness_val = prefs->getDouble("/tools/calligraphic/flatness", 90);
220 _fixation_adj = Gtk::Adjustment::create(flatness_val, 0.0, 100, 1.0, 10.0);
221 auto flatness_item = Gtk::manage(new UI::Widget::SpinButtonToolItem("calligraphy-fixation", _("Fixation:"), _fixation_adj, 1, 0));
222 flatness_item->set_tooltip_text(_("Angle behavior (0 = nib always perpendicular to stroke direction, 100 = fixed angle)"));
223 flatness_item->set_custom_numeric_menu_data(values, labels);
224 flatness_item->set_focus_widget(desktop->canvas);
225 _fixation_adj->signal_value_changed().connect(sigc::mem_fun(*this, &CalligraphyToolbar::flatness_value_changed));
226 _widget_map["flatness"] = G_OBJECT(_fixation_adj->gobj());
227 add(*flatness_item);
228 flatness_item->set_sensitive(true);
229 }
230
231 add(* Gtk::manage(new Gtk::SeparatorToolItem()));
232
233 {
234 /* Cap Rounding */
235 std::vector<Glib::ustring> labels = {_("(blunt caps, default)"), _("(slightly bulging)"), "", "", _("(approximately round)"), _("(long protruding caps)")};
236 std::vector<double> values = { 0, 0.3, 0.5, 1.0, 1.4, 5.0};
237 auto cap_rounding_val = prefs->getDouble("/tools/calligraphic/cap_rounding", 0.0);
238 _cap_rounding_adj = Gtk::Adjustment::create(cap_rounding_val, 0.0, 5.0, 0.01, 0.1);
239 auto cap_rounding_item = Gtk::manage(new UI::Widget::SpinButtonToolItem("calligraphy-cap-rounding", _("Caps:"), _cap_rounding_adj, 0.01, 2));
240
241 // TRANSLATORS: "cap" means "end" (both start and finish) here
242 cap_rounding_item->set_tooltip_text(_("Increase to make caps at the ends of strokes protrude more (0 = no caps, 1 = round caps)"));
243 cap_rounding_item->set_custom_numeric_menu_data(values, labels);
244 cap_rounding_item->set_focus_widget(desktop->canvas);
245 _cap_rounding_adj->signal_value_changed().connect(sigc::mem_fun(*this, &CalligraphyToolbar::cap_rounding_value_changed));
246 _widget_map["cap_rounding"] = G_OBJECT(_cap_rounding_adj->gobj());
247 add(*cap_rounding_item);
248 cap_rounding_item->set_sensitive(true);
249 }
250
251 add(* Gtk::manage(new Gtk::SeparatorToolItem()));
252
253 {
254 /* Tremor */
255 std::vector<Glib::ustring> labels = {_("(smooth line)"), _("(slight tremor)"), _("(noticeable tremor)"), "", "", _("(maximum tremor)")};
256 std::vector<double> values = { 0, 10, 20, 40, 60, 100};
257 auto tremor_val = prefs->getDouble("/tools/calligraphic/tremor", 0.0);
258 _tremor_adj = Gtk::Adjustment::create(tremor_val, 0.0, 100, 1, 10.0);
259 auto tremor_item = Gtk::manage(new UI::Widget::SpinButtonToolItem("calligraphy-tremor", _("Tremor:"), _tremor_adj, 1, 0));
260 tremor_item->set_tooltip_text(_("Increase to make strokes rugged and trembling"));
261 tremor_item->set_custom_numeric_menu_data(values, labels);
262 tremor_item->set_focus_widget(desktop->canvas);
263 _tremor_adj->signal_value_changed().connect(sigc::mem_fun(*this, &CalligraphyToolbar::tremor_value_changed));
264 _widget_map["tremor"] = G_OBJECT(_tremor_adj->gobj());
265 // ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
266 add(*tremor_item);
267 tremor_item->set_sensitive(true);
268 }
269
270 {
271 /* Wiggle */
272 std::vector<Glib::ustring> labels = {_("(no wiggle)"), _("(slight deviation)"), "", "", _("(wild waves and curls)")};
273 std::vector<double> values = { 0, 20, 40, 60, 100};
274 auto wiggle_val = prefs->getDouble("/tools/calligraphic/wiggle", 0.0);
275 _wiggle_adj = Gtk::Adjustment::create(wiggle_val, 0.0, 100, 1, 10.0);
276 auto wiggle_item = Gtk::manage(new UI::Widget::SpinButtonToolItem("calligraphy-wiggle", _("Wiggle:"), _wiggle_adj, 1, 0));
277 wiggle_item->set_tooltip_text(_("Increase to make the pen waver and wiggle"));
278 wiggle_item->set_custom_numeric_menu_data(values, labels);
279 wiggle_item->set_focus_widget(desktop->canvas);
280 _wiggle_adj->signal_value_changed().connect(sigc::mem_fun(*this, &CalligraphyToolbar::wiggle_value_changed));
281 _widget_map["wiggle"] = G_OBJECT(_wiggle_adj->gobj());
282 // ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
283 add(*wiggle_item);
284 wiggle_item->set_sensitive(true);
285 }
286
287 show_all();
288 }
289
290 GtkWidget *
create(SPDesktop * desktop)291 CalligraphyToolbar::create(SPDesktop *desktop)
292 {
293 auto toolbar = new CalligraphyToolbar(desktop);
294 return GTK_WIDGET(toolbar->gobj());
295 }
296
297 void
width_value_changed()298 CalligraphyToolbar::width_value_changed()
299 {
300 Unit const *unit = _tracker->getActiveUnit();
301 g_return_if_fail(unit != nullptr);
302 auto prefs = Inkscape::Preferences::get();
303 _tracker->getCurrentLabel() == "%" ? prefs->setBool("/tools/calligraphic/abs_width", false)
304 : prefs->setBool("/tools/calligraphic/abs_width", true);
305 prefs->setDouble("/tools/calligraphic/width", Quantity::convert(_width_adj->get_value(), unit, "px"));
306 update_presets_list();
307 }
308
309 void
velthin_value_changed()310 CalligraphyToolbar::velthin_value_changed()
311 {
312 auto prefs = Inkscape::Preferences::get();
313 prefs->setDouble("/tools/calligraphic/thinning", _thinning_adj->get_value() );
314 update_presets_list();
315 }
316
317 void
angle_value_changed()318 CalligraphyToolbar::angle_value_changed()
319 {
320 auto prefs = Inkscape::Preferences::get();
321 prefs->setDouble( "/tools/calligraphic/angle", _angle_adj->get_value() );
322 update_presets_list();
323 }
324
325 void
flatness_value_changed()326 CalligraphyToolbar::flatness_value_changed()
327 {
328 auto prefs = Inkscape::Preferences::get();
329 prefs->setDouble( "/tools/calligraphic/flatness", _fixation_adj->get_value() );
330 update_presets_list();
331 }
332
333 void
cap_rounding_value_changed()334 CalligraphyToolbar::cap_rounding_value_changed()
335 {
336 auto prefs = Inkscape::Preferences::get();
337 prefs->setDouble( "/tools/calligraphic/cap_rounding", _cap_rounding_adj->get_value() );
338 update_presets_list();
339 }
340
341 void
tremor_value_changed()342 CalligraphyToolbar::tremor_value_changed()
343 {
344 auto prefs = Inkscape::Preferences::get();
345 prefs->setDouble( "/tools/calligraphic/tremor", _tremor_adj->get_value() );
346 update_presets_list();
347 }
348
349 void
wiggle_value_changed()350 CalligraphyToolbar::wiggle_value_changed()
351 {
352 auto prefs = Inkscape::Preferences::get();
353 prefs->setDouble( "/tools/calligraphic/wiggle", _wiggle_adj->get_value() );
354 update_presets_list();
355 }
356
357 void
mass_value_changed()358 CalligraphyToolbar::mass_value_changed()
359 {
360 auto prefs = Inkscape::Preferences::get();
361 prefs->setDouble( "/tools/calligraphic/mass", _mass_adj->get_value() );
362 update_presets_list();
363 }
364
365 void
on_pref_toggled(Gtk::ToggleToolButton * item,const Glib::ustring & path)366 CalligraphyToolbar::on_pref_toggled(Gtk::ToggleToolButton *item,
367 const Glib::ustring& path)
368 {
369 auto prefs = Inkscape::Preferences::get();
370 prefs->setBool(path, item->get_active());
371 update_presets_list();
372 }
373
374 void
update_presets_list()375 CalligraphyToolbar::update_presets_list()
376 {
377 if (_presets_blocked) {
378 return;
379 }
380
381 auto prefs = Inkscape::Preferences::get();
382 auto presets = get_presets_list();
383
384 int index = 1; // 0 is for no preset.
385 for (auto i = presets.begin(); i != presets.end(); ++i, ++index) {
386 bool match = true;
387
388 auto preset = prefs->getAllEntries(*i);
389 for (auto & j : preset) {
390 Glib::ustring entry_name = j.getEntryName();
391 if (entry_name == "id" || entry_name == "name") {
392 continue;
393 }
394
395 void *widget = _widget_map[entry_name.data()];
396 if (widget) {
397 if (GTK_IS_ADJUSTMENT(widget)) {
398 double v = j.getDouble();
399 GtkAdjustment* adj = static_cast<GtkAdjustment *>(widget);
400 //std::cout << "compared adj " << attr_name << gtk_adjustment_get_value(adj) << " to " << v << "\n";
401 if (fabs(gtk_adjustment_get_value(adj) - v) > 1e-6) {
402 match = false;
403 break;
404 }
405 } else if (GTK_IS_TOGGLE_TOOL_BUTTON(widget)) {
406 bool v = j.getBool();
407 auto toggle = GTK_TOGGLE_TOOL_BUTTON(widget);
408 //std::cout << "compared toggle " << attr_name << gtk_toggle_action_get_active(toggle) << " to " << v << "\n";
409 if ( static_cast<bool>(gtk_toggle_tool_button_get_active(toggle)) != v ) {
410 match = false;
411 break;
412 }
413 }
414 }
415 }
416
417 if (match) {
418 // newly added item is at the same index as the
419 // save command, so we need to change twice for it to take effect
420 _profile_selector_combo->set_active(0);
421 _profile_selector_combo->set_active(index);
422 return;
423 }
424 }
425
426 // no match found
427 _profile_selector_combo->set_active(0);
428 }
429
430 void
tilt_state_changed()431 CalligraphyToolbar::tilt_state_changed()
432 {
433 _angle_item->set_sensitive(!_usetilt->get_active());
434 on_pref_toggled(_usetilt, "/tools/calligraphic/usetilt");
435 }
436
437 void
build_presets_list()438 CalligraphyToolbar::build_presets_list()
439 {
440 _presets_blocked = true;
441
442 _profile_selector_combo->remove_all();
443 _profile_selector_combo->append(_("No preset"));
444
445 // iterate over all presets to populate the list
446 auto prefs = Inkscape::Preferences::get();
447 auto presets = get_presets_list();
448
449 for (auto & preset : presets) {
450 Glib::ustring preset_name = prefs->getString(preset + "/name");
451
452 if (!preset_name.empty()) {
453 _profile_selector_combo->append(_(preset_name.data()));
454 }
455 }
456
457 _presets_blocked = false;
458
459 update_presets_list();
460 }
461
462 void
change_profile()463 CalligraphyToolbar::change_profile()
464 {
465 auto mode = _profile_selector_combo->get_active_row_number();
466 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
467
468 if (_presets_blocked) {
469 return;
470 }
471
472 // mode is one-based so we subtract 1
473 std::vector<Glib::ustring> presets = get_presets_list();
474
475 Glib::ustring preset_path = "";
476 if (mode - 1 < presets.size()) {
477 preset_path = presets.at(mode - 1);
478 }
479
480 if (!preset_path.empty()) {
481 _presets_blocked = true; //temporarily block the selector so no one will updadte it while we're reading it
482
483 std::vector<Inkscape::Preferences::Entry> preset = prefs->getAllEntries(preset_path);
484
485 // Shouldn't this be std::map?
486 for (auto & i : preset) {
487 Glib::ustring entry_name = i.getEntryName();
488 if (entry_name == "id" || entry_name == "name") {
489 continue;
490 }
491 void *widget = _widget_map[entry_name.data()];
492 if (widget) {
493 if (GTK_IS_ADJUSTMENT(widget)) {
494 GtkAdjustment* adj = static_cast<GtkAdjustment *>(widget);
495 gtk_adjustment_set_value(adj, i.getDouble());
496 //std::cout << "set adj " << attr_name << " to " << v << "\n";
497 } else if (GTK_IS_TOGGLE_TOOL_BUTTON(widget)) {
498 auto toggle = GTK_TOGGLE_TOOL_BUTTON(widget);
499 gtk_toggle_tool_button_set_active(toggle, i.getBool());
500 //std::cout << "set toggle " << attr_name << " to " << v << "\n";
501 } else {
502 g_warning("Unknown widget type for preset: %s\n", entry_name.data());
503 }
504 } else {
505 g_warning("Bad key found in a preset record: %s\n", entry_name.data());
506 }
507 }
508 _presets_blocked = false;
509 }
510 }
511
512 void
edit_profile()513 CalligraphyToolbar::edit_profile()
514 {
515 save_profile(nullptr);
516 }
517
unit_changed(int)518 void CalligraphyToolbar::unit_changed(int /* NotUsed */)
519 {
520 Unit const *unit = _tracker->getActiveUnit();
521 g_return_if_fail(unit != nullptr);
522 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
523 _tracker->getCurrentLabel() == "%" ? prefs->setBool("/tools/calligraphic/abs_width", false)
524 : prefs->setBool("/tools/calligraphic/abs_width", true);
525 prefs->setDouble("/tools/calligraphic/width",
526 CLAMP(prefs->getDouble("/tools/calligraphic/width"), Quantity::convert(0.001, unit, "px"),
527 Quantity::convert(100, unit, "px")));
528 prefs->setString("/tools/calligraphic/unit", unit->abbr);
529 }
530
save_profile(GtkWidget *)531 void CalligraphyToolbar::save_profile(GtkWidget * /*widget*/)
532 {
533 using Inkscape::UI::Dialog::CalligraphicProfileRename;
534 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
535 if (! _desktop) {
536 return;
537 }
538
539 if (_presets_blocked) {
540 return;
541 }
542
543 Glib::ustring current_profile_name = _profile_selector_combo->get_active_text();
544
545 if (current_profile_name == _("No preset")) {
546 current_profile_name = "";
547 }
548
549 CalligraphicProfileRename::show(_desktop, current_profile_name);
550 if ( !CalligraphicProfileRename::applied()) {
551 // dialog cancelled
552 update_presets_list();
553 return;
554 }
555 Glib::ustring new_profile_name = CalligraphicProfileRename::getProfileName();
556
557 if (new_profile_name.empty()) {
558 // empty name entered
559 update_presets_list ();
560 return;
561 }
562
563 _presets_blocked = true;
564
565 // If there's a preset with the given name, find it and set save_path appropriately
566 auto presets = get_presets_list();
567 int total_presets = presets.size();
568 int new_index = -1;
569 Glib::ustring save_path; // profile pref path without a trailing slash
570
571 int temp_index = 0;
572 for (std::vector<Glib::ustring>::iterator i = presets.begin(); i != presets.end(); ++i, ++temp_index) {
573 Glib::ustring name = prefs->getString(*i + "/name");
574 if (!name.empty() && (new_profile_name == name || current_profile_name == name)) {
575 new_index = temp_index;
576 save_path = *i;
577 break;
578 }
579 }
580
581 if ( CalligraphicProfileRename::deleted() && new_index != -1) {
582 prefs->remove(save_path);
583 _presets_blocked = false;
584 build_presets_list();
585 return;
586 }
587
588 if (new_index == -1) {
589 // no preset with this name, create
590 new_index = total_presets + 1;
591 gchar *profile_id = g_strdup_printf("/dcc%d", new_index);
592 save_path = Glib::ustring("/tools/calligraphic/preset") + profile_id;
593 g_free(profile_id);
594 }
595
596 for (auto map_item : _widget_map) {
597 auto widget_name = map_item.first;
598 auto widget = map_item.second;
599
600 if (widget) {
601 if (GTK_IS_ADJUSTMENT(widget)) {
602 GtkAdjustment* adj = GTK_ADJUSTMENT(widget);
603 prefs->setDouble(save_path + "/" + widget_name, gtk_adjustment_get_value(adj));
604 //std::cout << "wrote adj " << widget_name << ": " << v << "\n";
605 } else if (GTK_IS_TOGGLE_TOOL_BUTTON(widget)) {
606 auto toggle = GTK_TOGGLE_TOOL_BUTTON(widget);
607 prefs->setBool(save_path + "/" + widget_name, gtk_toggle_tool_button_get_active(toggle));
608 //std::cout << "wrote tog " << widget_name << ": " << v << "\n";
609 } else {
610 g_warning("Unknown widget type for preset: %s\n", widget_name.c_str());
611 }
612 } else {
613 g_warning("Bad key when writing preset: %s\n", widget_name.c_str());
614 }
615 }
616 prefs->setString(save_path + "/name", new_profile_name);
617
618 _presets_blocked = true;
619 build_presets_list();
620 }
621
622 }
623 }
624 }
625
626
627 /*
628 Local Variables:
629 mode:c++
630 c-file-style:"stroustrup"
631 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
632 indent-tabs-mode:nil
633 fill-column:99
634 End:
635 */
636 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
637