1 /**
2 * \brief Scalar Unit Widget - A labelled text box, with spin buttons and
3 * optional icon or suffix, for entering the values of various unit
4 * types.
5 *
6 * A ScalarUnit is a control for entering, viewing, or manipulating
7 * numbers with units. This differs from ordinary numbers like 2 or
8 * 3.14 because the number portion of a scalar *only* has meaning
9 * when considered with its unit type. For instance, 12 m and 12 in
10 * have very different actual values, but 1 m and 100 cm have the same
11 * value. The ScalarUnit allows us to abstract the presentation of
12 * the scalar to the user from the internal representations used by
13 * the program.
14 *
15 * Authors:
16 * Bryce Harrington <bryce@bryceharrington.org>
17 * Derek P. Moore <derekm@hackunix.org>
18 * buliabyak@gmail.com
19 *
20 * Copyright (C) 2004-2005 Authors
21 *
22 * Released under GNU GPL. Read the file 'COPYING' for more information.
23 */
25 #ifdef HAVE_CONFIG_H
26 # include <config.h>
27 #endif
29 #include "scalar-unit.h"
31 namespace Inkscape {
32 namespace UI {
33 namespace Widget {
35 /**
36 * Construct a ScalarUnit
37 *
38 * \param label Label.
39 * \param unit_type Unit type (defaults to UNIT_TYPE_LINEAR).
40 * \param suffix Suffix, placed after the widget (defaults to "").
41 * \param icon Icon filename, placed before the label (defaults to "").
42 * \param unit_menu UnitMenu drop down; if not specified, one will be created
43 * and displayed after the widget (defaults to NULL).
44 * \param mnemonic Mnemonic toggle; if true, an underscore (_) in the label
45 * indicates the next character should be used for the
46 * mnemonic accelerator key (defaults to true).
47 */
48 ScalarUnit::ScalarUnit(Glib::ustring const &label, Glib::ustring const &tooltip,
49 UnitType unit_type,
50 Glib::ustring const &suffix,
51 Glib::ustring const &icon,
52 UnitMenu *unit_menu,
53 bool mnemonic)
54 : Scalar(label, tooltip, suffix, icon, mnemonic),
55 _unit_menu(unit_menu),
56 _hundred_percent(0),
57 _absolute_is_increment(false),
58 _percentage_is_increment(false)
59 {
60 if (_unit_menu == NULL) {
61 _unit_menu = new UnitMenu();
62 g_assert(_unit_menu);
63 _unit_menu->setUnitType(unit_type);
64 pack_start(*Gtk::manage(_unit_menu), false, false, 4);
65 }
66 _unit_menu->signal_changed()
67 .connect_notify(sigc::mem_fun(*this, &ScalarUnit::on_unit_changed));
68 }
70 /**
71 * Initializes the scalar based on the settings in _unit_menu.
72 * Requires that _unit_menu has already been initialized.
73 */
74 void
75 ScalarUnit::initScalar(double min_value, double max_value)
76 {
77 g_assert(_unit_menu != NULL);
78 Scalar::setDigits(_unit_menu->getDefaultDigits());
79 Scalar::setIncrements(_unit_menu->getDefaultStep(),
80 _unit_menu->getDefaultPage());
81 Scalar::setRange(min_value, max_value);
82 }
84 /** Sets the unit for the ScalarUnit widget */
85 bool
86 ScalarUnit::setUnit(Glib::ustring const &unit) {
87 g_assert(_unit_menu != NULL);
88 // First set the unit
89 if (!_unit_menu->setUnit(unit)) {
90 return false;
91 }
92 lastUnits = unit;
93 return true;
94 }
96 /** Gets the object for the currently selected unit */
97 Unit
98 ScalarUnit::getUnit() const {
99 g_assert(_unit_menu != NULL);
100 return _unit_menu->getUnit();
101 }
103 /** Gets the UnitType ID for the unit */
104 UnitType
105 ScalarUnit::getUnitType() const {
106 g_assert(_unit_menu);
107 return _unit_menu->getUnitType();
108 }
110 /** Sets the number and unit system */
111 void
112 ScalarUnit::setValue(double number, Glib::ustring const &units) {
113 g_assert(_unit_menu != NULL);
114 _unit_menu->setUnit(units);
115 Scalar::setValue(number);
116 }
118 /** Sets the number only */
119 void
120 ScalarUnit::setValue(double number) {
121 Scalar::setValue(number);
122 }
124 /** Returns the value in the given unit system */
125 double
126 ScalarUnit::getValue(Glib::ustring const &unit_name) const {
127 g_assert(_unit_menu != NULL);
128 if (unit_name == "") {
129 // Return the value in the default units
130 return Scalar::getValue();
131 } else {
132 double conversion = _unit_menu->getConversion(unit_name);
133 return conversion * Scalar::getValue();
134 }
135 }
137 void
138 ScalarUnit::setHundredPercent(double number)
139 {
140 _hundred_percent = number;
141 }
143 void
144 ScalarUnit::setAbsoluteIsIncrement(bool value)
145 {
146 _absolute_is_increment = value;
147 }
149 void
150 ScalarUnit::setPercentageIsIncrement(bool value)
151 {
152 _percentage_is_increment = value;
153 }
155 /** Convert value from % to absolute, using _hundred_percent and *_is_increment flags */
156 double
157 ScalarUnit::PercentageToAbsolute(double value)
158 {
159 // convert from percent to absolute
160 double convertedVal = 0;
161 double hundred_converted = _hundred_percent / _unit_menu->getConversion("px"); // _hundred_percent is in px
162 if (_percentage_is_increment)
163 value += 100;
164 convertedVal = 0.01 * hundred_converted * value;
165 if (_absolute_is_increment)
166 convertedVal -= hundred_converted;
168 return convertedVal;
169 }
171 /** Convert value from absolute to %, using _hundred_percent and *_is_increment flags */
172 double
173 ScalarUnit::AbsoluteToPercentage(double value)
174 {
175 double convertedVal = 0;
176 // convert from absolute to percent
177 if (_hundred_percent == 0) {
178 if (_percentage_is_increment)
179 convertedVal = 0;
180 else
181 convertedVal = 100;
182 } else {
183 double hundred_converted = _hundred_percent / _unit_menu->getConversion("px", lastUnits); // _hundred_percent is in px
184 if (_absolute_is_increment)
185 value += hundred_converted;
186 convertedVal = 100 * value / hundred_converted;
187 if (_percentage_is_increment)
188 convertedVal -= 100;
189 }
191 return convertedVal;
192 }
194 /** Assuming the current unit is absolute, get the corresponding % value */
195 double
196 ScalarUnit::getAsPercentage()
197 {
198 double convertedVal = AbsoluteToPercentage(Scalar::getValue());
199 return convertedVal;
200 }
203 /** Assuming the current unit is absolute, set the value corresponding to a given % */
204 void
205 ScalarUnit::setFromPercentage(double value)
206 {
207 double absolute = PercentageToAbsolute(value);
208 Scalar::setValue(absolute);
209 }
212 /** Signal handler for updating the value and suffix label when unit is changed */
213 void
214 ScalarUnit::on_unit_changed()
215 {
216 g_assert(_unit_menu != NULL);
218 Glib::ustring abbr = _unit_menu->getUnitAbbr();
219 _suffix->set_label(abbr);
221 Inkscape::Util::UnitTable &table = _unit_menu->getUnitTable();
222 Inkscape::Util::Unit new_unit = (table.getUnit(abbr));
223 Inkscape::Util::Unit old_unit = (table.getUnit(lastUnits));
225 double convertedVal = 0;
226 if (old_unit.type == UNIT_TYPE_DIMENSIONLESS && new_unit.type == UNIT_TYPE_LINEAR) {
227 convertedVal = PercentageToAbsolute(Scalar::getValue());
228 } else if (old_unit.type == UNIT_TYPE_LINEAR && new_unit.type == UNIT_TYPE_DIMENSIONLESS) {
229 convertedVal = AbsoluteToPercentage(Scalar::getValue());
230 } else {
231 double conversion = _unit_menu->getConversion(lastUnits);
232 convertedVal = Scalar::getValue() / conversion;
233 }
234 Scalar::setValue(convertedVal);
236 lastUnits = abbr;
237 }
239 } // namespace Widget
240 } // namespace UI
241 } // namespace Inkscape
243 /*
244 Local Variables:
245 mode:c++
246 c-file-style:"stroustrup"
247 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
248 indent-tabs-mode:nil
249 fill-column:99
250 End:
251 */
252 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :