Inkscape
Vector Graphics Editor
unit-tracker.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Inkscape::UI::Widget::UnitTracker
4 * Simple mediator to synchronize changes to unit menus
5 *
6 * Authors:
7 * Jon A. Cruz <jon@joncruz.org>
8 * Matthew Petroff <matthew@mpetroff.net>
9 *
10 * Copyright (C) 2007 Jon A. Cruz
11 * Copyright (C) 2013 Matthew Petroff
12 * Copyright (C) 2018 Tavmjong Bah
13 *
14 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
15 */
16
17#include "unit-tracker.h"
18
19#include <algorithm>
20#include <iostream>
21#include <gtkmm/liststore.h>
22
23#include "combo-tool-item.h"
24
25#define COLUMN_STRING 0
26
27namespace Inkscape::UI::Widget {
28
30 _active(0),
31 _isUpdating(false),
32 _activeUnit(nullptr),
33 _activeUnitInitialized(false),
34 _store(nullptr),
35 _priorValues()
36{
37 auto const &m = Util::UnitTable::get().units(unit_type);
38
41 Gtk::TreeModel::Row row;
42
43 for (auto & m_iter : m) {
44
45 Glib::ustring unit = m_iter.first;
46
47 row = *(_store->append());
48 row[columns.col_label ] = unit;
49 row[columns.col_value ] = unit;
50 row[columns.col_tooltip ] = ("");
51 row[columns.col_icon ] = "NotUsed";
52 row[columns.col_sensitive] = true;
53 }
54
55 // Why?
56 gint count = _store->children().size();
57 if ((count > 0) && (_active > count)) {
58 _setActive(--count);
59 } else {
61 }
62}
63
65{
66 _combo_list.clear();
67
68 // Unhook weak references to GtkAdjustments
69 for (auto i : _adjList) {
70 g_object_weak_unref(G_OBJECT(i), _adjustmentFinalizedCB, this);
71 }
72 _adjList.clear();
73}
74
76{
77 return _isUpdating;
78}
79
81{
82 return _activeUnit;
83}
84
86{
88 return _store->children()[_active][columns.col_label];
89}
90
91void UnitTracker::changeLabel(Glib::ustring new_label, gint pos, bool onlylabel)
92{
94 _store->children()[pos][columns.col_label] = new_label;
95 if (!onlylabel) {
96 _store->children()[pos][columns.col_value] = new_label;
97 }
98}
99
101{
102 if (unit) {
103
104 ComboToolItemColumns columns;
105 int index = 0;
106 for (auto& row: _store->children() ) {
107 Glib::ustring storedUnit = row[columns.col_value];
108 if (!unit->abbr.compare (storedUnit)) {
109 _setActive (index);
110 break;
111 }
112 index++;
113 }
114 }
115}
116
117void UnitTracker::setActiveUnitByLabel(Glib::ustring label)
118{
119 ComboToolItemColumns columns;
120 int index = 0;
121 for (auto &row : _store->children()) {
122 Glib::ustring storedUnit = row[columns.col_label];
123 if (!label.compare(storedUnit)) {
124 _setActive(index);
125 break;
126 }
127 index++;
128 }
129}
130
131void UnitTracker::setActiveUnitByAbbr(gchar const *abbr)
132{
133 auto u = Util::UnitTable::get().getUnit(abbr);
134 setActiveUnit(u);
135}
136
138{
139 if (std::find(_adjList.begin(),_adjList.end(),adj) == _adjList.end()) {
140 g_object_weak_ref(G_OBJECT(adj), _adjustmentFinalizedCB, this);
141 _adjList.push_back(adj);
142 } else {
143 std::cerr << "UnitTracker::addAjustment: Adjustment already added!" << std::endl;
144 }
145}
146
148{
149 ComboToolItemColumns columns;
150
151 Gtk::TreeModel::Row row;
152 row = *(_store->append());
153 row[columns.col_label ] = u ? u->abbr.c_str() : "";
154 row[columns.col_value ] = u ? u->abbr.c_str() : "";
155 row[columns.col_tooltip ] = ("");
156 row[columns.col_icon ] = "NotUsed";
157 row[columns.col_sensitive] = true;
158}
159
161{
162 ComboToolItemColumns columns;
163
164 Gtk::TreeModel::Row row;
165 row = *(_store->prepend());
166 row[columns.col_label ] = u ? u->abbr.c_str() : "";
167 row[columns.col_value ] = u ? u->abbr.c_str() : "";
168 row[columns.col_tooltip ] = ("");
169 row[columns.col_icon ] = "NotUsed";
170 row[columns.col_sensitive] = true;
171
172 /* Re-shuffle our default selection here (_active gets out of sync) */
174
175}
176
177void UnitTracker::setFullVal(GtkAdjustment * const adj, double const val)
178{
179 _priorValues[adj] = val;
180}
181
183UnitTracker::create_tool_item(Glib::ustring const &label,
184 Glib::ustring const &tooltip)
185{
186 auto combo = ComboToolItem::create(label, tooltip, "NotUsed", _store);
187 combo->set_active(_active);
188 combo->signal_changed().connect(sigc::mem_fun(*this, &UnitTracker::_unitChangedCB));
189 combo->set_name("unit-tracker");
190 combo->set_data(Glib::Quark("unit-tracker"), this);
191 _combo_list.push_back(combo);
192 return combo;
193}
194
196{
197 _setActive(active);
198}
199
200void UnitTracker::_adjustmentFinalizedCB(gpointer data, GObject *where_the_object_was)
201{
202 if (data && where_the_object_was) {
203 UnitTracker *self = reinterpret_cast<UnitTracker *>(data);
204 self->_adjustmentFinalized(where_the_object_was);
205 }
206}
207
209{
210 GtkAdjustment* adj = (GtkAdjustment*)(where_the_object_was);
211 auto it = std::find(_adjList.begin(),_adjList.end(), adj);
212 if (it != _adjList.end()) {
213 _adjList.erase(it);
214 } else {
215 g_warning("Received a finalization callback for unknown object %p", where_the_object_was);
216 }
217}
218
219void UnitTracker::_setActive(gint active)
220{
221 auto const &unit_table = Util::UnitTable::get();
222
223 if ( active != _active || !_activeUnitInitialized ) {
224 gint oldActive = _active;
225
226 if (_store) {
227
228 // Find old and new units
229 ComboToolItemColumns columns;
230 int index = 0;
231 Glib::ustring oldAbbr( "NotFound" );
232 Glib::ustring newAbbr( "NotFound" );
233 for (auto& row: _store->children() ) {
234 if (index == _active) {
235 oldAbbr = row[columns.col_value];
236 }
237 if (index == active) {
238 newAbbr = row[columns.col_value];
239 }
240 if (newAbbr != "NotFound" && oldAbbr != "NotFound") break;
241 ++index;
242 }
243
244 if (oldAbbr != "NotFound") {
245
246 if (newAbbr != "NotFound") {
247 Inkscape::Util::Unit const *oldUnit = unit_table.getUnit(oldAbbr);
248 Inkscape::Util::Unit const *newUnit = unit_table.getUnit(newAbbr);
249 _activeUnit = newUnit;
250
251 if (!_adjList.empty()) {
252 _fixupAdjustments(oldUnit, newUnit);
253 }
254 } else {
255 std::cerr << "UnitTracker::_setActive: Did not find new unit: " << active << std::endl;
256 }
257
258 } else {
259 std::cerr << "UnitTracker::_setActive: Did not find old unit: " << oldActive
260 << " new: " << active << std::endl;
261 }
262 }
263 _active = active;
264
265 for (auto combo : _combo_list) {
266 if(combo) combo->set_active(active);
267 }
268
270 }
271}
272
274{
275 _isUpdating = true;
276 for ( auto adj : _adjList ) {
277 auto const oldVal = gtk_adjustment_get_value(adj);
278 auto val = oldVal;
279
282 {
283 val = newUnit->factor * 100;
284 _priorValues[adj] = Inkscape::Util::Quantity::convert(oldVal, oldUnit, "px");
285 } else if ( (oldUnit->type == Inkscape::Util::UNIT_TYPE_DIMENSIONLESS)
287 {
288 if (_priorValues.find(adj) != _priorValues.end()) {
290 }
291 } else {
292 val = Inkscape::Util::Quantity::convert(oldVal, oldUnit, newUnit);
293 }
294
295 gtk_adjustment_set_value(adj, val);
296 }
297 _isUpdating = false;
298}
299
300} // namespace Inkscape::UI::Widget
301
302/*
303 Local Variables:
304 mode:c++
305 c-file-style:"stroustrup"
306 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
307 indent-tabs-mode:nil
308 fill-column:99
309 End:
310*/
311// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8 :
Gtk::TreeModelColumn< Glib::ustring > col_icon
Gtk::TreeModelColumn< Glib::ustring > col_value
Gtk::TreeModelColumn< Glib::ustring > col_tooltip
Gtk::TreeModelColumn< bool > col_sensitive
Gtk::TreeModelColumn< Glib::ustring > col_label
static ComboToolItem * create(const Glib::ustring &label, const Glib::ustring &tooltip, const Glib::ustring &stock_id, Glib::RefPtr< Gtk::ListStore > store, bool has_entry=false)
std::vector< GtkAdjustment * > _adjList
Definition: unit-tracker.h:83
void prependUnit(Inkscape::Util::Unit const *u)
void setFullVal(GtkAdjustment *adj, double val)
std::vector< ComboToolItem * > _combo_list
Definition: unit-tracker.h:82
Glib::RefPtr< Gtk::ListStore > _store
Definition: unit-tracker.h:81
void _adjustmentFinalized(GObject *where_the_object_was)
void addAdjustment(GtkAdjustment *adj)
void setActiveUnit(Inkscape::Util::Unit const *unit)
void _fixupAdjustments(Inkscape::Util::Unit const *oldUnit, Inkscape::Util::Unit const *newUnit)
static void _adjustmentFinalizedCB(gpointer data, GObject *where_the_object_was)
void setActiveUnitByLabel(Glib::ustring label)
void changeLabel(Glib::ustring new_label, gint pos, bool onlylabel=false)
ComboToolItem * create_tool_item(Glib::ustring const &label, Glib::ustring const &tooltip)
Inkscape::Util::Unit const * getActiveUnit() const
void addUnit(Inkscape::Util::Unit const *u)
Inkscape::Util::Unit const * _activeUnit
Definition: unit-tracker.h:78
std::map< GtkAdjustment *, double > _priorValues
Definition: unit-tracker.h:84
void setActiveUnitByAbbr(gchar const *abbr)
static double convert(double from_dist, Unit const *from, Unit const *to)
Convert distances.
Definition: units.cpp:525
UnitMap units(UnitType type) const
Provides an iterable list of items in the given unit table.
Definition: units.cpp:375
static UnitTable & get()
Definition: units.cpp:410
Unit const * getUnit(Glib::ustring const &name) const
Retrieve a given unit based on its string identifier.
Definition: units.cpp:285
UnitType type
Definition: units.h:72
Glib::ustring abbr
Definition: units.h:76
A combobox that can be displayed in a toolbar.
SymmetricMatrix< N > adj(const ConstBaseSymmetricMatrix< N > &S)
static const Triplet m[3]
Definition: hsluv.cpp:44
Custom widgets.
Definition: desktop.h:127
@ UNIT_TYPE_DIMENSIONLESS
Definition: units.h:33
unsigned char * data
std::unique_ptr< Toolbar >(* create)(SPDesktop *desktop)
Definition: toolbars.cpp:63
struct _GObject GObject
Definition: unit-tracker.h:28
struct _GtkAdjustment GtkAdjustment
Definition: unit-tracker.h:29