Merge lp:~matthewpetroff/inkscape/gsoc-2013-unit-improvement into lp:~inkscape.dev/inkscape/trunk

Proposed by Matthew Petroff
Status: Merged
Merged at revision: 12554
Proposed branch: lp:~matthewpetroff/inkscape/gsoc-2013-unit-improvement
Merge into: lp:~inkscape.dev/inkscape/trunk
Diff against target: 4078 lines (+1192/-753)
101 files modified
share/templates/A4.svg (+2/-1)
share/templates/A4_landscape.svg (+2/-1)
share/templates/CD_cover_300dpi.svg (+2/-1)
share/templates/Letter.svg (+3/-2)
share/templates/Letter_landscape.svg (+3/-2)
share/templates/business_card_85x54mm.svg (+2/-1)
share/templates/business_card_90x50mm.svg (+2/-1)
share/templates/default.be.svg (+2/-1)
share/templates/default_mm.svg (+2/-1)
share/templates/default_pt.svg (+2/-1)
share/ui/Makefile.am (+0/-1)
share/ui/units.txt (+0/-20)
src/arc-context.cpp (+1/-0)
src/connector-context.cpp (+2/-0)
src/desktop.cpp (+5/-5)
src/document.cpp (+28/-13)
src/document.h (+3/-2)
src/draw-context.cpp (+1/-0)
src/dyna-draw-context.cpp (+4/-0)
src/ege-adjustment-action.cpp (+25/-3)
src/ege-adjustment-action.h (+12/-2)
src/extension/internal/cairo-renderer-pdf-out.cpp (+1/-1)
src/extension/internal/cairo-renderer.cpp (+4/-4)
src/extension/internal/emf-inout.cpp (+2/-2)
src/extension/internal/emf-print.cpp (+3/-3)
src/extension/internal/grid.cpp (+3/-2)
src/extension/internal/latex-pstricks.cpp (+4/-4)
src/extension/internal/latex-text-renderer.cpp (+2/-2)
src/extension/internal/odf.cpp (+2/-1)
src/extension/internal/pdfinput/pdf-parser.cpp (+3/-3)
src/extension/internal/pdfinput/svg-builder.cpp (+1/-1)
src/extension/internal/wmf-inout.cpp (+2/-2)
src/extension/internal/wmf-print.cpp (+2/-2)
src/file.cpp (+2/-2)
src/flood-context.cpp (+2/-2)
src/helper/pixbuf-ops.cpp (+2/-2)
src/helper/png-write.cpp (+2/-1)
src/inkview.cpp (+4/-3)
src/lpe-tool-context.cpp (+2/-2)
src/main.cpp (+4/-4)
src/object-snapper.cpp (+3/-3)
src/persp3d.cpp (+4/-3)
src/rect-context.cpp (+1/-0)
src/selection-chemistry.cpp (+5/-5)
src/shape-editor.cpp (+6/-0)
src/shape-editor.h (+3/-0)
src/sp-ellipse.cpp (+53/-0)
src/sp-ellipse.h (+1/-0)
src/sp-flowtext.cpp (+39/-0)
src/sp-flowtext.h (+7/-0)
src/sp-guide.cpp (+1/-1)
src/sp-item-group.cpp (+78/-0)
src/sp-item-group.h (+1/-0)
src/sp-item.cpp (+4/-2)
src/sp-root.h (+1/-1)
src/sp-spiral.cpp (+52/-1)
src/sp-spiral.h (+1/-0)
src/sp-star.cpp (+49/-0)
src/sp-star.h (+1/-0)
src/sp-text.cpp (+7/-2)
src/sp-text.h (+6/-0)
src/spiral-context.cpp (+1/-0)
src/star-context.cpp (+1/-0)
src/style.cpp (+15/-15)
src/svg-view-widget.cpp (+3/-2)
src/svg-view.cpp (+7/-6)
src/text-context.cpp (+1/-0)
src/ui/clipboard.cpp (+2/-2)
src/ui/dialog/aboutbox.cpp (+3/-2)
src/ui/dialog/document-properties.cpp (+60/-3)
src/ui/dialog/document-properties.h (+3/-0)
src/ui/dialog/export.cpp (+3/-3)
src/ui/dialog/print.cpp (+6/-6)
src/ui/dialog/text-edit.cpp (+1/-1)
src/ui/widget/page-sizer.cpp (+35/-29)
src/ui/widget/page-sizer.h (+6/-2)
src/ui/widget/spinbutton.cpp (+13/-5)
src/ui/widget/spinbutton.h (+5/-0)
src/util/expression-evaluator.cpp (+323/-463)
src/util/expression-evaluator.h (+93/-23)
src/util/units.cpp (+62/-10)
src/util/units.h (+10/-14)
src/widgets/calligraphy-toolbar.cpp (+8/-8)
src/widgets/connector-toolbar.cpp (+3/-3)
src/widgets/desktop-widget.cpp (+2/-2)
src/widgets/eraser-toolbar.cpp (+1/-1)
src/widgets/gradient-toolbar.cpp (+3/-2)
src/widgets/icon.cpp (+2/-1)
src/widgets/mesh-toolbar.cpp (+2/-2)
src/widgets/node-toolbar.cpp (+2/-2)
src/widgets/paintbucket-toolbar.cpp (+2/-2)
src/widgets/pencil-toolbar.cpp (+1/-0)
src/widgets/rect-toolbar.cpp (+10/-9)
src/widgets/select-toolbar.cpp (+3/-2)
src/widgets/spiral-toolbar.cpp (+1/-1)
src/widgets/spray-toolbar.cpp (+6/-6)
src/widgets/star-toolbar.cpp (+2/-2)
src/widgets/text-toolbar.cpp (+6/-0)
src/widgets/toolbox.cpp (+4/-2)
src/widgets/toolbox.h (+5/-0)
src/widgets/tweak-toolbar.cpp (+3/-3)
To merge this branch: bzr merge lp:~matthewpetroff/inkscape/gsoc-2013-unit-improvement
Reviewer Review Type Date Requested Status
Martin Owens code review Approve
Review via email: mp+185928@code.launchpad.net

Description of the change

Implements real world document units using a viewBox, uses real world units for document size, and extends expression evaluator to toolbars

To post a comment you must log in.
Revision history for this message
Martin Owens (doctormo) wrote :

This code looks good. I'm giving this a thumbs up from a code perspective.

review: Approve (code review)
Revision history for this message
su_v (suv-lp) wrote :

Units for rectangle tool don't match document units.

Steps to reproduce:
1) launch branch (default prefs)
2) open template 'A4 Page'
   (this document has a view box, and sets the scale to real units via height and width)
3) switch to the rectangle tool, and draw a rectangle of 10x10mm
   (enter the numbers in the controls bar of the rectangle tool)
4) remove stroke from rectangle (to allow easier comparing of the geometric size)
4) switch to the select tool, and check the size of the rectangle (default unit is 'mm'):
   the select tool claims that the rectangle has the size of 35.433 x 35.433 mm

12503. By Matthew Petroff

Fix bug in rectangle toolbar.

Revision history for this message
Matthew Petroff (matthewpetroff) wrote :

> Units for rectangle tool don't match document units.
>
> Steps to reproduce:
> 1) launch branch (default prefs)
> 2) open template 'A4 Page'
> (this document has a view box, and sets the scale to real units via height
> and width)
> 3) switch to the rectangle tool, and draw a rectangle of 10x10mm
> (enter the numbers in the controls bar of the rectangle tool)
> 4) remove stroke from rectangle (to allow easier comparing of the geometric
> size)
> 4) switch to the select tool, and check the size of the rectangle (default
> unit is 'mm'):
> the select tool claims that the rectangle has the size of 35.433 x 35.433
> mm

The rectangle toolbar was hard coded to pixels. I fixed it, so it now uses the document unit.

12504. By Matthew Petroff

Merge from trunk.

Revision history for this message
su_v (suv-lp) wrote :

On 2013-09-20 19:09 +0200, <email address hidden> wrote:
> The proposal to merge lp:~matthewpetroff/inkscape/gsoc-2013-unit-improvement into lp:inkscape has been updated.
>
> Status: Needs review => Merged

@Matthew - after the merge, building trunk r12552 with dbusapi enabled fails:

  CXX extension/dbus/document-interface.o
../../src/extension/dbus/document-interface.cpp: In function ‘gdouble document_interface_document_get_width(DocumentInterface*)’:
../../src/extension/dbus/document-interface.cpp:546: error: invalid use of incomplete type ‘struct Inkscape::Util::Quantity’
../../src/document.h:50: error: forward declaration of ‘struct Inkscape::Util::Quantity’
../../src/extension/dbus/document-interface.cpp: In function ‘gdouble document_interface_document_get_height(DocumentInterface*)’:
../../src/extension/dbus/document-interface.cpp:552: error: invalid use of incomplete type ‘struct Inkscape::Util::Quantity’
../../src/document.h:50: error: forward declaration of ‘struct Inkscape::Util::Quantity’
make[3]: *** [extension/dbus/document-interface.o] Error 1
make[2]: *** [all] Error 2
make[1]: *** [all-recursive] Error 1
make: *** [all] Error 2

Any chance you could take a look? You probably know best how to fix this ;)

Please let me know if you prefer to have a bug report filed about the build failure.

Revision history for this message
Matthew Petroff (matthewpetroff) wrote :

It should be fixed now. Can you test it? I've never built Inkscape with dbus enabled.

Revision history for this message
su_v (suv-lp) wrote :

On 2013-09-20 20:57 +0200, Matthew Petroff wrote:
> It should be fixed now. Can you test it? I've never built Inkscape with dbus enabled.

Fix confirmed - r12555 builds successfully with dbusapi enabled.

Thank you for the prompt response!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'share/templates/A4.svg'
2--- share/templates/A4.svg 2013-08-10 13:23:01 +0000
3+++ share/templates/A4.svg 2013-09-20 17:05:49 +0000
4@@ -9,7 +9,8 @@
5 xmlns:cc="http://web.resource.org/cc/"
6 xmlns:dc="http://purl.org/dc/elements/1.1/"
7 width="210mm"
8- height="297mm">
9+ height="297mm"
10+ viewBox="0 0 210 297">
11 <defs
12 id="defs3" />
13 <sodipodi:namedview
14
15=== modified file 'share/templates/A4_landscape.svg'
16--- share/templates/A4_landscape.svg 2013-08-10 13:23:01 +0000
17+++ share/templates/A4_landscape.svg 2013-09-20 17:05:49 +0000
18@@ -9,7 +9,8 @@
19 xmlns:cc="http://web.resource.org/cc/"
20 xmlns:dc="http://purl.org/dc/elements/1.1/"
21 width="297mm"
22- height="210mm">
23+ height="210mm"
24+ viewBox="0 0 297 210">
25 <defs />
26 <sodipodi:namedview
27 inkscape:document-units="mm"
28
29=== modified file 'share/templates/CD_cover_300dpi.svg'
30--- share/templates/CD_cover_300dpi.svg 2013-08-10 13:23:01 +0000
31+++ share/templates/CD_cover_300dpi.svg 2013-09-20 17:05:49 +0000
32@@ -9,7 +9,8 @@
33 xmlns:cc="http://web.resource.org/cc/"
34 xmlns:dc="http://purl.org/dc/elements/1.1/"
35 width="343pt"
36- height="340pt">
37+ height="340pt"
38+ viewBox="0 0 343 340">
39 <defs />
40 <sodipodi:namedview
41 pagecolor="#ffffff"
42
43=== modified file 'share/templates/Letter.svg'
44--- share/templates/Letter.svg 2013-08-10 13:23:01 +0000
45+++ share/templates/Letter.svg 2013-09-20 17:05:49 +0000
46@@ -8,8 +8,9 @@
47 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
48 xmlns:cc="http://web.resource.org/cc/"
49 xmlns:dc="http://purl.org/dc/elements/1.1/"
50- width="612pt"
51- height="792pt">
52+ width="8.5in"
53+ height="11in"
54+ viewBox="0 0 8.5 11">
55 <defs />
56 <sodipodi:namedview
57 inkscape:document-units="in"
58
59=== modified file 'share/templates/Letter_landscape.svg'
60--- share/templates/Letter_landscape.svg 2013-08-10 13:23:01 +0000
61+++ share/templates/Letter_landscape.svg 2013-09-20 17:05:49 +0000
62@@ -8,8 +8,9 @@
63 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
64 xmlns:cc="http://web.resource.org/cc/"
65 xmlns:dc="http://purl.org/dc/elements/1.1/"
66- width="792pt"
67- height="612pt">
68+ width="11in"
69+ height="8.5in"
70+ viewBox="0 0 11 8.5">
71 <defs />
72 <sodipodi:namedview
73 inkscape:document-units="in"
74
75=== modified file 'share/templates/business_card_85x54mm.svg'
76--- share/templates/business_card_85x54mm.svg 2013-08-10 13:23:01 +0000
77+++ share/templates/business_card_85x54mm.svg 2013-09-20 17:05:49 +0000
78@@ -9,7 +9,8 @@
79 xmlns:cc="http://web.resource.org/cc/"
80 xmlns:dc="http://purl.org/dc/elements/1.1/"
81 width="85mm"
82- height="54mm">
83+ height="54mm"
84+ viewBox="0 0 85 54">
85 <defs
86 id="defs3" />
87 <sodipodi:namedview
88
89=== modified file 'share/templates/business_card_90x50mm.svg'
90--- share/templates/business_card_90x50mm.svg 2013-08-10 13:23:01 +0000
91+++ share/templates/business_card_90x50mm.svg 2013-09-20 17:05:49 +0000
92@@ -9,7 +9,8 @@
93 xmlns:cc="http://web.resource.org/cc/"
94 xmlns:dc="http://purl.org/dc/elements/1.1/"
95 width="90mm"
96- height="50mm">
97+ height="50mm"
98+ viewBox="0 0 90 50">
99 <defs
100 id="defs3" />
101 <sodipodi:namedview
102
103=== modified file 'share/templates/default.be.svg'
104--- share/templates/default.be.svg 2009-09-29 17:39:54 +0000
105+++ share/templates/default.be.svg 2013-09-20 17:05:49 +0000
106@@ -9,7 +9,8 @@
107 xmlns:cc="http://web.resource.org/cc/"
108 xmlns:dc="http://purl.org/dc/elements/1.1/"
109 width="210mm"
110- height="297mm">
111+ height="297mm"
112+ viewBox="0 0 210 297">
113 <defs />
114 <sodipodi:namedview
115 id="base"
116
117=== modified file 'share/templates/default_mm.svg'
118--- share/templates/default_mm.svg 2006-01-16 02:36:01 +0000
119+++ share/templates/default_mm.svg 2013-09-20 17:05:49 +0000
120@@ -9,7 +9,8 @@
121 xmlns:cc="http://web.resource.org/cc/"
122 xmlns:dc="http://purl.org/dc/elements/1.1/"
123 width="210mm"
124- height="297mm">
125+ height="297mm"
126+ viewBox="0 0 210 297">
127 <defs />
128 <sodipodi:namedview
129 id="base"
130
131=== modified file 'share/templates/default_pt.svg'
132--- share/templates/default_pt.svg 2006-01-16 02:36:01 +0000
133+++ share/templates/default_pt.svg 2013-09-20 17:05:49 +0000
134@@ -9,7 +9,8 @@
135 xmlns:cc="http://web.resource.org/cc/"
136 xmlns:dc="http://purl.org/dc/elements/1.1/"
137 width="210mm"
138- height="297mm">
139+ height="297mm"
140+ viewBox="0 0 595.27558 841.88974">
141 <defs />
142 <sodipodi:namedview
143 id="base"
144
145=== modified file 'share/ui/Makefile.am'
146--- share/ui/Makefile.am 2006-01-16 02:36:01 +0000
147+++ share/ui/Makefile.am 2013-09-20 17:05:49 +0000
148@@ -5,7 +5,6 @@
149 keybindings.rc \
150 menus-bars.xml \
151 toolbox.xml \
152- units.txt \
153 units.xml
154
155 EXTRA_DIST = $(ui_DATA)
156
157=== removed file 'share/ui/units.txt'
158--- share/ui/units.txt 2012-03-22 19:19:09 +0000
159+++ share/ui/units.txt 1970-01-01 00:00:00 +0000
160@@ -1,20 +0,0 @@
161-# Simple unit configuration file
162-#
163-# This is a space-delimited list of unit definitions.
164-
165-# name name_plural abbr type factor PRI description
166-# ---------------------------------------------------------------------------
167- % % % DIMENSIONLESS 1.00 Y Percentage
168- pixel pixels px LINEAR 1.00 Y CSS Pixels (90/inch)
169- point points pt LINEAR 1.25 N PostScript points (72/inch)
170- pica picas pc LINEAR 15.0 N 12 points
171- inch inches in LINEAR 90.0 N Inches (90 px/in)
172- millimeter millimeters mm LINEAR 3.543307 N Millimeters (25.4 mm/in)
173- centimeter centimeters cm LINEAR 35.43307 N Centimeters (10 mm/cm)
174- meter meters m LINEAR 3543.307 N Meters (100 cm/m)
175- foot feet ft LINEAR 1080 N Feet (12 in/ft)
176- degree degrees ° RADIAL 1.00 Y Degrees
177- radian radians rad RADIAL 57.296 N Radians (57.296 deg/rad)
178- font-height font-heights em FONT_HEIGHT 1.00 Y Font height
179- x-height x-heights ex FONT_HEIGHT 0.50 N Height of letter 'x'
180- half-em half-ems en FONT_HEIGHT 0.50 N Half of font height
181
182=== modified file 'src/arc-context.cpp'
183--- src/arc-context.cpp 2013-08-30 21:35:42 +0000
184+++ src/arc-context.cpp 2013-09-20 17:05:49 +0000
185@@ -451,6 +451,7 @@
186 }
187
188 this->arc->updateRepr();
189+ this->arc->doWriteTransform(this->arc->getRepr(), this->arc->transform, NULL, true);
190
191 desktop->canvas->endForcedFullRedraws();
192
193
194=== modified file 'src/connector-context.cpp'
195--- src/connector-context.cpp 2013-07-31 19:11:20 +0000
196+++ src/connector-context.cpp 2013-09-20 17:05:49 +0000
197@@ -998,6 +998,8 @@
198 cc->newconn->updateRepr();
199 }
200
201+ cc->newconn->doWriteTransform(cc->newconn->getRepr(), cc->newconn->transform, NULL, true);
202+
203 // Only set the selection after we are finished with creating the attributes of
204 // the connector. Otherwise, the selection change may alter the defaults for
205 // values like curvature in the connector context, preventing subsequent lookup
206
207=== modified file 'src/desktop.cpp'
208--- src/desktop.cpp 2013-09-19 04:26:02 +0000
209+++ src/desktop.cpp 2013-09-20 17:05:49 +0000
210@@ -242,7 +242,7 @@
211 // display rect and zoom are now handled in sp_desktop_widget_realize()
212
213 Geom::Rect const d(Geom::Point(0.0, 0.0),
214- Geom::Point(document->getWidth(), document->getHeight()));
215+ Geom::Point(document->getWidth().value("px"), document->getHeight().value("px")));
216
217 SP_CTRLRECT(page)->setRectangle(d);
218 SP_CTRLRECT(page_border)->setRectangle(d);
219@@ -259,7 +259,7 @@
220
221
222 /* Connect event for page resize */
223- _doc2dt[5] = document->getHeight();
224+ _doc2dt[5] = document->getHeight().value("px");
225 sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (drawing), _doc2dt);
226
227 _modified_connection = namedview->connectModified(sigc::bind<2>(sigc::ptr_fun(&_namedview_modified), this));
228@@ -1108,7 +1108,7 @@
229 SPDesktop::zoom_page()
230 {
231 Geom::Rect d(Geom::Point(0, 0),
232- Geom::Point(doc()->getWidth(), doc()->getHeight()));
233+ Geom::Point(doc()->getWidth().value("px"), doc()->getHeight().value("px")));
234
235 if (d.minExtent() < 1.0) {
236 return;
237@@ -1125,12 +1125,12 @@
238 {
239 Geom::Rect const a = get_display_area();
240
241- if (doc()->getWidth() < 1.0) {
242+ if (doc()->getWidth().value("px") < 1.0) {
243 return;
244 }
245
246 Geom::Rect d(Geom::Point(0, a.midpoint()[Geom::Y]),
247- Geom::Point(doc()->getWidth(), a.midpoint()[Geom::Y]));
248+ Geom::Point(doc()->getWidth().value("px"), a.midpoint()[Geom::Y]));
249
250 set_display_area(d, 10);
251 }
252
253=== modified file 'src/document.cpp'
254--- src/document.cpp 2013-09-16 17:32:58 +0000
255+++ src/document.cpp 2013-09-20 17:05:49 +0000
256@@ -548,16 +548,20 @@
257 return NULL;
258 }
259
260-gdouble SPDocument::getWidth() const
261+Inkscape::Util::Quantity SPDocument::getWidth() const
262 {
263- g_return_val_if_fail(this->priv != NULL, 0.0);
264- g_return_val_if_fail(this->root != NULL, 0.0);
265+ g_return_val_if_fail(this->priv != NULL, Inkscape::Util::Quantity(0.0, Inkscape::Util::Unit()));
266+ g_return_val_if_fail(this->root != NULL, Inkscape::Util::Quantity(0.0, Inkscape::Util::Unit()));
267
268- gdouble result = root->width.computed;
269+ gdouble result = root->width.value;
270+ SVGLength::Unit u = root->width.unit;
271 if (root->width.unit == SVGLength::PERCENT && root->viewBox_set) {
272 result = root->viewBox.width();
273 }
274- return result;
275+ if (u == SVGLength::NONE) {
276+ u = SVGLength::PX;
277+ }
278+ return Inkscape::Util::Quantity(result, unit_table.getUnit(u));
279 }
280
281 void SPDocument::setWidth(const Inkscape::Util::Quantity &width)
282@@ -584,16 +588,20 @@
283 root->updateRepr();
284 }
285
286-gdouble SPDocument::getHeight() const
287+Inkscape::Util::Quantity SPDocument::getHeight() const
288 {
289- g_return_val_if_fail(this->priv != NULL, 0.0);
290- g_return_val_if_fail(this->root != NULL, 0.0);
291+ g_return_val_if_fail(this->priv != NULL, Inkscape::Util::Quantity(0.0, Inkscape::Util::Unit()));
292+ g_return_val_if_fail(this->root != NULL, Inkscape::Util::Quantity(0.0, Inkscape::Util::Unit()));
293
294- gdouble result = root->height.computed;
295+ gdouble result = root->height.value;
296+ SVGLength::Unit u = root->height.unit;
297 if (root->height.unit == SVGLength::PERCENT && root->viewBox_set) {
298 result = root->viewBox.height();
299 }
300- return result;
301+ if (u == SVGLength::NONE) {
302+ u = SVGLength::PX;
303+ }
304+ return Inkscape::Util::Quantity(result, unit_table.getUnit(u));
305 }
306
307 void SPDocument::setHeight(const Inkscape::Util::Quantity &height)
308@@ -620,9 +628,16 @@
309 root->updateRepr();
310 }
311
312+void SPDocument::setViewBox(const Geom::Rect &viewBox)
313+{
314+ root->viewBox_set = true;
315+ root->viewBox = viewBox;
316+ root->updateRepr();
317+}
318+
319 Geom::Point SPDocument::getDimensions() const
320 {
321- return Geom::Point(getWidth(), getHeight());
322+ return Geom::Point(getWidth().value("px"), getHeight().value("px"));
323 }
324
325 Geom::OptRect SPDocument::preferredBounds() const
326@@ -644,7 +659,7 @@
327 double const w = rect.width();
328 double const h = rect.height();
329
330- double const old_height = getHeight();
331+ double const old_height = getHeight().value("px");
332 Inkscape::Util::Unit const px = unit_table.getUnit("px");
333
334 /* in px */
335@@ -979,7 +994,7 @@
336 if (root->viewBox_set) { // if set, take from viewBox
337 ctx->viewport = root->viewBox;
338 } else { // as a last resort, set size to A4
339- ctx->viewport = Geom::Rect::from_xywh(0, 0, 210 * Inkscape::Util::Quantity::convert(1, "mm", "px"), 297 * Inkscape::Util::Quantity::convert(1, "mm", "px"));
340+ ctx->viewport = Geom::Rect::from_xywh(0, 0, Inkscape::Util::Quantity::convert(210, "mm", "px"), Inkscape::Util::Quantity::convert(297, "mm", "px"));
341 }
342 ctx->i2vp = Geom::identity();
343 }
344
345=== modified file 'src/document.h'
346--- src/document.h 2013-08-30 21:35:42 +0000
347+++ src/document.h 2013-09-20 17:05:49 +0000
348@@ -227,12 +227,13 @@
349
350 SPDocument *doRef();
351 SPDocument *doUnref();
352- gdouble getWidth() const;
353- gdouble getHeight() const;
354+ Inkscape::Util::Quantity getWidth() const;
355+ Inkscape::Util::Quantity getHeight() const;
356 Geom::Point getDimensions() const;
357 Geom::OptRect preferredBounds() const;
358 void setWidth(const Inkscape::Util::Quantity &width);
359 void setHeight(const Inkscape::Util::Quantity &height);
360+ void setViewBox(const Geom::Rect &viewBox);
361 void requestModified();
362 gint ensureUpToDate();
363 bool addResource(const gchar *key, SPObject *object);
364
365=== modified file 'src/draw-context.cpp'
366--- src/draw-context.cpp 2013-08-04 13:09:03 +0000
367+++ src/draw-context.cpp 2013-09-20 17:05:49 +0000
368@@ -599,6 +599,7 @@
369 dc->selection->set(repr);
370 Inkscape::GC::release(repr);
371 item->transform = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse();
372+ item->doWriteTransform(item->getRepr(), item->transform, NULL, true);
373 item->updateRepr();
374 }
375
376
377=== modified file 'src/dyna-draw-context.cpp'
378--- src/dyna-draw-context.cpp 2013-07-31 19:11:20 +0000
379+++ src/dyna-draw-context.cpp 2013-09-20 17:05:49 +0000
380@@ -958,6 +958,10 @@
381 sp_desktop_selection(desktop)->set(this->repr);
382 }
383 }
384+
385+ SPItem *item=SP_ITEM(desktop->doc()->getObjectByRepr(this->repr));
386+ item->doWriteTransform(item->getRepr(), item->transform, NULL, true);
387+
388 } else {
389 if (this->repr) {
390 sp_repr_unparent(this->repr);
391
392=== modified file 'src/ege-adjustment-action.cpp'
393--- src/ege-adjustment-action.cpp 2013-01-26 19:33:04 +0000
394+++ src/ege-adjustment-action.cpp 2013-09-20 17:05:49 +0000
395@@ -115,6 +115,7 @@
396 gchar* appearance;
397 gchar* iconId;
398 Inkscape::IconSize iconSize;
399+ Inkscape::UI::Widget::UnitTracker *unitTracker;
400 };
401
402 #define EGE_ADJUSTMENT_ACTION_GET_PRIVATE( o ) ( G_TYPE_INSTANCE_GET_PRIVATE( (o), EGE_ADJUSTMENT_ACTION_TYPE, EgeAdjustmentActionPrivate ) )
403@@ -128,7 +129,8 @@
404 PROP_TOOL_POST,
405 PROP_APPEARANCE,
406 PROP_ICON_ID,
407- PROP_ICON_SIZE
408+ PROP_ICON_SIZE,
409+ PROP_UNIT_TRACKER
410 };
411
412 enum {
413@@ -234,6 +236,13 @@
414 (int)Inkscape::ICON_SIZE_SMALL_TOOLBAR,
415 (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
416
417+ g_object_class_install_property( objClass,
418+ PROP_UNIT_TRACKER,
419+ g_param_spec_pointer( "unit_tracker",
420+ "Unit Tracker",
421+ "The widget that keeps track of the unit",
422+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
423+
424 g_type_class_add_private( klass, sizeof(EgeAdjustmentActionClass) );
425 }
426 }
427@@ -263,6 +272,7 @@
428 action->private_data->appearance = 0;
429 action->private_data->iconId = 0;
430 action->private_data->iconSize = Inkscape::ICON_SIZE_SMALL_TOOLBAR;
431+ action->private_data->unitTracker = NULL;
432 }
433
434 static void ege_adjustment_action_finalize( GObject* object )
435@@ -292,7 +302,8 @@
436 const gchar *tooltip,
437 const gchar *stock_id,
438 gdouble climb_rate,
439- guint digits )
440+ guint digits,
441+ Inkscape::UI::Widget::UnitTracker *unit_tracker )
442 {
443 GObject* obj = (GObject*)g_object_new( EGE_ADJUSTMENT_ACTION_TYPE,
444 "name", name,
445@@ -302,6 +313,7 @@
446 "adjustment", adjustment,
447 "climb-rate", climb_rate,
448 "digits", digits,
449+ "unit_tracker", unit_tracker,
450 NULL );
451
452 EgeAdjustmentAction* action = EGE_ADJUSTMENT_ACTION( obj );
453@@ -349,6 +361,10 @@
454 g_value_set_int( value, action->private_data->iconSize );
455 break;
456
457+ case PROP_UNIT_TRACKER:
458+ g_value_set_pointer( value, action->private_data->unitTracker );
459+ break;
460+
461 default:
462 G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec );
463 }
464@@ -450,6 +466,12 @@
465 }
466 break;
467
468+ case PROP_UNIT_TRACKER:
469+ {
470+ action->private_data->unitTracker = (Inkscape::UI::Widget::UnitTracker*)g_value_get_pointer( value );
471+ }
472+ break;
473+
474 default:
475 G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec );
476 }
477@@ -812,7 +834,7 @@
478 gtk_scale_button_set_icons( GTK_SCALE_BUTTON(spinbutton), floogles );
479 } else {
480 if ( gFactoryCb ) {
481- spinbutton = gFactoryCb( act->private_data->adj, act->private_data->climbRate, act->private_data->digits );
482+ spinbutton = gFactoryCb( act->private_data->adj, act->private_data->climbRate, act->private_data->digits, act->private_data->unitTracker );
483 } else {
484 spinbutton = gtk_spin_button_new( act->private_data->adj, act->private_data->climbRate, act->private_data->digits );
485 }
486
487=== modified file 'src/ege-adjustment-action.h'
488--- src/ege-adjustment-action.h 2011-06-03 10:44:52 +0000
489+++ src/ege-adjustment-action.h 2013-09-20 17:05:49 +0000
490@@ -63,6 +63,14 @@
491 typedef struct _EgeAdjustmentActionClass EgeAdjustmentActionClass;
492 typedef struct _EgeAdjustmentActionPrivate EgeAdjustmentActionPrivate;
493
494+namespace Inkscape {
495+ namespace UI {
496+ namespace Widget {
497+ class UnitTracker;
498+ }
499+ }
500+}
501+
502 /**
503 * Instance structure of EgeAdjustmentAction.
504 */
505@@ -95,7 +103,7 @@
506 */
507
508 /** Callback type for widgets creation factory */
509-typedef GtkWidget* (*EgeCreateAdjWidgetCB)( GtkAdjustment *adjustment, gdouble climb_rate, guint digits );
510+typedef GtkWidget* (*EgeCreateAdjWidgetCB)( GtkAdjustment *adjustment, gdouble climb_rate, guint digits, Inkscape::UI::Widget::UnitTracker *unit_tracker );
511
512 /**
513 * Sets a factory callback to be used to create the specific widget.
514@@ -117,6 +125,7 @@
515 * @param stock_id Icon id to use.
516 * @param climb_rate Used for created widgets.
517 * @param digits Used for created widgets.
518+ * @param unit_tracker Used to store unit.
519 */
520 EgeAdjustmentAction* ege_adjustment_action_new( GtkAdjustment* adjustment,
521 const gchar *name,
522@@ -124,7 +133,8 @@
523 const gchar *tooltip,
524 const gchar *stock_id,
525 gdouble climb_rate,
526- guint digits
527+ guint digits,
528+ Inkscape::UI::Widget::UnitTracker *unit_tracker
529 );
530 /**
531 * Returns a pointer to the GtkAdjustment represented by the given
532
533=== modified file 'src/extension/internal/cairo-renderer-pdf-out.cpp'
534--- src/extension/internal/cairo-renderer-pdf-out.cpp 2013-08-26 20:03:43 +0000
535+++ src/extension/internal/cairo-renderer-pdf-out.cpp 2013-09-20 17:05:49 +0000
536@@ -197,7 +197,7 @@
537
538 float new_bleedmargin_px = 0.;
539 try {
540- new_bleedmargin_px = mod->get_param_float("bleed") * Inkscape::Util::Quantity::convert(1, "mm", "px");
541+ new_bleedmargin_px = Inkscape::Util::Quantity::convert(mod->get_param_float("bleed"), "mm", "px");
542 }
543 catch(...) {
544 g_warning("Parameter <bleed> might not exist");
545
546=== modified file 'src/extension/internal/cairo-renderer.cpp'
547--- src/extension/internal/cairo-renderer.cpp 2013-09-19 17:03:35 +0000
548+++ src/extension/internal/cairo-renderer.cpp 2013-09-20 17:05:49 +0000
549@@ -463,8 +463,8 @@
550 }
551
552 // The width and height of the bitmap in pixels
553- unsigned width = ceil(bbox->width() * (res / Inkscape::Util::Quantity::convert(1, "in", "px")));
554- unsigned height = ceil(bbox->height() * (res / Inkscape::Util::Quantity::convert(1, "in", "px")));
555+ unsigned width = ceil(bbox->width() * Inkscape::Util::Quantity::convert(res, "px", "in"));
556+ unsigned height = ceil(bbox->height() * Inkscape::Util::Quantity::convert(res, "px", "in"));
557
558 if (width == 0 || height == 0) return;
559
560@@ -638,9 +638,9 @@
561 Geom::Affine tp( Geom::Translate( bleedmargin_px, bleedmargin_px ) );
562 ctx->transform(tp);
563 } else {
564- double high = doc->getHeight();
565+ double high = doc->getHeight().value("px");
566 if (ctx->_vector_based_target)
567- high *= Inkscape::Util::Quantity::convert(1, "px", "pt");
568+ high = Inkscape::Util::Quantity::convert(high, "px", "pt");
569
570 // this transform translates the export drawing to a virtual page (0,0)-(width,height)
571 Geom::Affine tp(Geom::Translate(-d.left() * (ctx->_vector_based_target ? Inkscape::Util::Quantity::convert(1, "pt", "px") : 1.0),
572
573=== modified file 'src/extension/internal/emf-inout.cpp'
574--- src/extension/internal/emf-inout.cpp 2013-09-01 23:39:00 +0000
575+++ src/extension/internal/emf-inout.cpp 2013-09-20 17:05:49 +0000
576@@ -1799,8 +1799,8 @@
577 d->MMX = d->MM100InX / 100.0;
578 d->MMY = d->MM100InY / 100.0;
579
580- d->PixelsOutX = d->MMX * Inkscape::Util::Quantity::convert(1, "mm", "px");
581- d->PixelsOutY = d->MMY * Inkscape::Util::Quantity::convert(1, "mm", "px");
582+ d->PixelsOutX = Inkscape::Util::Quantity::convert(d->MMX, "mm", "px");
583+ d->PixelsOutY = Inkscape::Util::Quantity::convert(d->MMY, "mm", "px");
584
585 // Upper left corner, from header rclBounds, in device units, usually both 0, but not always
586 d->ulCornerInX = pEmr->rclBounds.left;
587
588=== modified file 'src/extension/internal/emf-print.cpp'
589--- src/extension/internal/emf-print.cpp 2013-09-19 00:57:10 +0000
590+++ src/extension/internal/emf-print.cpp 2013-09-20 17:05:49 +0000
591@@ -138,8 +138,8 @@
592
593
594 // width and height in px
595- _width = doc->getWidth();
596- _height = doc->getHeight();
597+ _width = doc->getWidth().value("px");
598+ _height = doc->getHeight().value("px");
599
600 // initialize a few global variables
601 hbrush = hbrushOld = hpen = 0;
602@@ -243,7 +243,7 @@
603 g_error("Fatal programming error in PrintEmf::begin at textcomment_set 1");
604 }
605
606- snprintf(buff, sizeof(buff) - 1, "Drawing=%.1lfx%.1lfpx, %.1lfx%.1lfmm", _width, _height, dwInchesX * Inkscape::Util::Quantity::convert(1, "in", "mm"), dwInchesY * Inkscape::Util::Quantity::convert(1, "in", "mm"));
607+ snprintf(buff, sizeof(buff) - 1, "Drawing=%.1lfx%.1lfpx, %.1lfx%.1lfmm", _width, _height, Inkscape::Util::Quantity::convert(dwInchesX, "in", "mm"), Inkscape::Util::Quantity::convert(dwInchesY, "in", "mm"));
608 rec = textcomment_set(buff);
609 if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
610 g_error("Fatal programming error in PrintEmf::begin at textcomment_set 1");
611
612=== modified file 'src/extension/internal/grid.cpp'
613--- src/extension/internal/grid.cpp 2013-06-07 03:18:19 +0000
614+++ src/extension/internal/grid.cpp 2013-09-20 17:05:49 +0000
615@@ -35,6 +35,7 @@
616 #include "extension/effect.h"
617 #include "extension/system.h"
618
619+#include "util/units.h"
620
621 #include "grid.h"
622
623@@ -97,14 +98,14 @@
624 /* get page size */
625 SPDocument * doc = document->doc();
626 bounding_area = Geom::Rect( Geom::Point(0,0),
627- Geom::Point(doc->getWidth(), doc->getHeight()) );
628+ Geom::Point(doc->getWidth().value("px"), doc->getHeight().value("px")) );
629 } else {
630 Geom::OptRect bounds = selection->visualBounds();
631 if (bounds) {
632 bounding_area = *bounds;
633 }
634
635- gdouble doc_height = (document->doc())->getHeight();
636+ gdouble doc_height = (document->doc())->getHeight().value("px");
637 Geom::Rect temprec = Geom::Rect(Geom::Point(bounding_area.min()[Geom::X], doc_height - bounding_area.min()[Geom::Y]),
638 Geom::Point(bounding_area.max()[Geom::X], doc_height - bounding_area.max()[Geom::Y]));
639
640
641=== modified file 'src/extension/internal/latex-pstricks.cpp'
642--- src/extension/internal/latex-pstricks.cpp 2013-07-31 22:33:03 +0000
643+++ src/extension/internal/latex-pstricks.cpp 2013-09-20 17:05:49 +0000
644@@ -117,8 +117,8 @@
645 }
646
647 // width and height in pt
648- _width = doc->getWidth() * Inkscape::Util::Quantity::convert(1, "px", "pt");
649- _height = doc->getHeight() * Inkscape::Util::Quantity::convert(1, "px", "pt");
650+ _width = doc->getWidth().value("pt");
651+ _height = doc->getHeight().value("pt");
652
653 if (res >= 0) {
654
655@@ -128,10 +128,10 @@
656 os << "\\psset{xunit=.5pt,yunit=.5pt,runit=.5pt}\n";
657 // from now on we can output px, but they will be treated as pt
658
659- os << "\\begin{pspicture}(" << doc->getWidth() << "," << doc->getHeight() << ")\n";
660+ os << "\\begin{pspicture}(" << doc->getWidth().value("px") << "," << doc->getHeight().value("px") << ")\n";
661 }
662
663- m_tr_stack.push( Geom::Scale(1, -1) * Geom::Translate(0, doc->getHeight())); /// @fixme hardcoded doc2dt transform
664+ m_tr_stack.push( Geom::Scale(1, -1) * Geom::Translate(0, doc->getHeight().value("px"))); /// @fixme hardcoded doc2dt transform
665
666 return fprintf(_stream, "%s", os.str().c_str());
667 }
668
669=== modified file 'src/extension/internal/latex-text-renderer.cpp'
670--- src/extension/internal/latex-text-renderer.cpp 2013-09-14 11:09:15 +0000
671+++ src/extension/internal/latex-text-renderer.cpp 2013-09-20 17:05:49 +0000
672@@ -633,7 +633,7 @@
673 }
674
675 // flip y-axis
676- push_transform( Geom::Scale(1,-1) * Geom::Translate(0, doc->getHeight()) ); /// @fixme hardcoded desktop transform!
677+ push_transform( Geom::Scale(1,-1) * Geom::Translate(0, doc->getHeight().value("px")) ); /// @fixme hardcoded desktop transform!
678
679 // write the info to LaTeX
680 Inkscape::SVGOStringStream os;
681@@ -642,7 +642,7 @@
682 // scaling of the image when including it in LaTeX
683
684 os << " \\ifx\\svgwidth\\undefined%\n";
685- os << " \\setlength{\\unitlength}{" << d.width() * Inkscape::Util::Quantity::convert(1, "px", "pt") << "bp}%\n"; // note: 'bp' is the Postscript pt unit in LaTeX, see LP bug #792384
686+ os << " \\setlength{\\unitlength}{" << Inkscape::Util::Quantity::convert(d.width(), "px", "pt") << "bp}%\n"; // note: 'bp' is the Postscript pt unit in LaTeX, see LP bug #792384
687 os << " \\ifx\\svgscale\\undefined%\n";
688 os << " \\relax%\n";
689 os << " \\else%\n";
690
691=== modified file 'src/extension/internal/odf.cpp'
692--- src/extension/internal/odf.cpp 2013-08-03 01:03:43 +0000
693+++ src/extension/internal/odf.cpp 2013-09-20 17:05:49 +0000
694@@ -75,6 +75,7 @@
695 #include "sp-flowtext.h"
696 #include "svg/svg.h"
697 #include "text-editing.h"
698+#include "util/units.h"
699
700
701 //# DOM-specific includes
702@@ -945,7 +946,7 @@
703 //### Get SVG-to-ODF transform
704 Geom::Affine tf (item->i2dt_affine());
705 //Flip Y into document coordinates
706- double doc_height = SP_ACTIVE_DOCUMENT->getHeight();
707+ double doc_height = SP_ACTIVE_DOCUMENT->getHeight().value("px");
708 Geom::Affine doc2dt_tf = Geom::Affine(Geom::Scale(1.0, -1.0)); /// @fixme hardcoded desktop transform
709 doc2dt_tf = doc2dt_tf * Geom::Affine(Geom::Translate(0, doc_height));
710 tf = tf * doc2dt_tf;
711
712=== modified file 'src/extension/internal/pdfinput/pdf-parser.cpp'
713--- src/extension/internal/pdfinput/pdf-parser.cpp 2013-08-06 18:54:40 +0000
714+++ src/extension/internal/pdfinput/pdf-parser.cpp 2013-09-20 17:05:49 +0000
715@@ -279,14 +279,14 @@
716 ignoreUndef = 0;
717 operatorHistory = NULL;
718 builder = builderA;
719- builder->setDocumentSize(state->getPageWidth()*Inkscape::Util::Quantity::convert(1, "pt", "px"),
720- state->getPageHeight()*Inkscape::Util::Quantity::convert(1, "pt", "px"));
721+ builder->setDocumentSize(Inkscape::Util::Quantity::convert(state->getPageWidth(), "pt", "px"),
722+ Inkscape::Util::Quantity::convert(state->getPageHeight(), "pt", "px"));
723
724 double *ctm = state->getCTM();
725 double scaledCTM[6];
726 for (int i = 0; i < 6; ++i) {
727 baseMatrix[i] = ctm[i];
728- scaledCTM[i] = Inkscape::Util::Quantity::convert(1, "pt", "px") * ctm[i];
729+ scaledCTM[i] = Inkscape::Util::Quantity::convert(ctm[i], "pt", "px");
730 }
731 saveState();
732 builder->setTransform((double*)&scaledCTM);
733
734=== modified file 'src/extension/internal/pdfinput/svg-builder.cpp'
735--- src/extension/internal/pdfinput/svg-builder.cpp 2013-08-06 18:54:40 +0000
736+++ src/extension/internal/pdfinput/svg-builder.cpp 2013-09-20 17:05:49 +0000
737@@ -793,7 +793,7 @@
738 Geom::Affine pat_matrix(matrix[0], matrix[1], matrix[2], matrix[3],
739 matrix[4], matrix[5]);
740 if ( !for_shading && _is_top_level ) {
741- Geom::Affine flip(1.0, 0.0, 0.0, -1.0, 0.0, _height * Inkscape::Util::Quantity::convert(1, "px", "pt"));
742+ Geom::Affine flip(1.0, 0.0, 0.0, -1.0, 0.0, Inkscape::Util::Quantity::convert(_height, "px", "pt"));
743 pat_matrix *= flip;
744 }
745 gchar *transform_text = sp_svg_transform_write(pat_matrix);
746
747=== modified file 'src/extension/internal/wmf-inout.cpp'
748--- src/extension/internal/wmf-inout.cpp 2013-09-01 23:39:00 +0000
749+++ src/extension/internal/wmf-inout.cpp 2013-09-20 17:05:49 +0000
750@@ -1742,8 +1742,8 @@
751 tmp_outdef << " version=\"1.0\"\n";
752
753 tmp_outdef <<
754- " width=\"" << d->PixelsOutX/ Inkscape::Util::Quantity::convert(1, "mm", "px") << "mm\"\n" <<
755- " height=\"" << d->PixelsOutY/ Inkscape::Util::Quantity::convert(1, "mm", "px") << "mm\">\n";
756+ " width=\"" << Inkscape::Util::Quantity::convert(d->PixelsOutX, "px", "mm") << "mm\"\n" <<
757+ " height=\"" << Inkscape::Util::Quantity::convert(d->PixelsOutY, "px", "mm") << "mm\">\n";
758 *(d->outdef) += tmp_outdef.str().c_str();
759 *(d->outdef) += "<defs>"; // temporary end of header
760
761
762=== modified file 'src/extension/internal/wmf-print.cpp'
763--- src/extension/internal/wmf-print.cpp 2013-09-19 00:57:10 +0000
764+++ src/extension/internal/wmf-print.cpp 2013-09-20 17:05:49 +0000
765@@ -138,8 +138,8 @@
766
767 // WMF header the only things that can be set are the page size in inches (w,h) and the dpi
768 // width and height in px
769- _width = doc->getWidth();
770- _height = doc->getHeight();
771+ _width = doc->getWidth().value("px");
772+ _height = doc->getHeight().value("px");
773
774 // initialize a few global variables
775 hbrush = hpen = 0;
776
777=== modified file 'src/file.cpp'
778--- src/file.cpp 2013-08-14 18:52:42 +0000
779+++ src/file.cpp 2013-09-20 17:05:49 +0000
780@@ -149,7 +149,7 @@
781 // If the current desktop is empty, open the document there
782 doc->ensureUpToDate(); // TODO this will trigger broken link warnings, etc.
783 desktop->change_document(doc);
784- doc->emitResizedSignal(doc->getWidth(), doc->getHeight());
785+ doc->emitResizedSignal(doc->getWidth().value("px"), doc->getHeight().value("px"));
786 } else {
787 // create a whole new desktop and window
788 SPViewWidget *dtw = sp_desktop_widget_new(sp_document_namedview(doc, NULL)); // TODO this will trigger broken link warnings, etc.
789@@ -291,7 +291,7 @@
790 // If the current desktop is empty, open the document there
791 doc->ensureUpToDate(); // TODO this will trigger broken link warnings, etc.
792 desktop->change_document(doc);
793- doc->emitResizedSignal(doc->getWidth(), doc->getHeight());
794+ doc->emitResizedSignal(doc->getWidth().value("px"), doc->getHeight().value("px"));
795 } else {
796 // create a whole new desktop and window
797 SPViewWidget *dtw = sp_desktop_widget_new(sp_document_namedview(doc, NULL)); // TODO this will trigger broken link warnings, etc.
798
799=== modified file 'src/flood-context.cpp'
800--- src/flood-context.cpp 2013-08-30 21:35:42 +0000
801+++ src/flood-context.cpp 2013-09-20 17:05:49 +0000
802@@ -764,7 +764,7 @@
803 unsigned int height = (int)ceil(screen.height() * zoom_scale * padding);
804
805 Geom::Point origin(screen.min()[Geom::X],
806- document->getHeight() - screen.height() - screen.min()[Geom::Y]);
807+ document->getHeight().value("px") - screen.height() - screen.min()[Geom::Y]);
808
809 origin[Geom::X] += (screen.width() * ((1 - padding) / 2));
810 origin[Geom::Y] += (screen.height() * ((1 - padding) / 2));
811@@ -874,7 +874,7 @@
812 }
813
814 for (unsigned int i = 0; i < fill_points.size(); i++) {
815- Geom::Point pw = Geom::Point(fill_points[i][Geom::X] / zoom_scale, document->getHeight() + (fill_points[i][Geom::Y] / zoom_scale)) * affine;
816+ Geom::Point pw = Geom::Point(fill_points[i][Geom::X] / zoom_scale, document->getHeight().value("px") + (fill_points[i][Geom::Y] / zoom_scale)) * affine;
817
818 pw[Geom::X] = (int)MIN(width - 1, MAX(0, pw[Geom::X]));
819 pw[Geom::Y] = (int)MIN(height - 1, MAX(0, pw[Geom::Y]));
820
821=== modified file 'src/helper/pixbuf-ops.cpp'
822--- src/helper/pixbuf-ops.cpp 2013-09-19 00:57:10 +0000
823+++ src/helper/pixbuf-ops.cpp 2013-09-20 17:05:49 +0000
824@@ -115,12 +115,12 @@
825 double padding = 1.0;
826
827 Geom::Point origin(screen.min()[Geom::X],
828- doc->getHeight() - screen[Geom::Y].extent() - screen.min()[Geom::Y]);
829+ doc->getHeight().value("px") - screen[Geom::Y].extent() - screen.min()[Geom::Y]);
830
831 origin[Geom::X] = origin[Geom::X] + (screen[Geom::X].extent() * ((1 - padding) / 2));
832 origin[Geom::Y] = origin[Geom::Y] + (screen[Geom::Y].extent() * ((1 - padding) / 2));
833
834- Geom::Scale scale( (xdpi / Inkscape::Util::Quantity::convert(1, "in", "px")), (ydpi / Inkscape::Util::Quantity::convert(1, "in", "px")));
835+ Geom::Scale scale(Inkscape::Util::Quantity::convert(xdpi, "px", "in"), Inkscape::Util::Quantity::convert(ydpi, "px", "in"));
836 Geom::Affine affine = scale * Geom::Translate(-origin * scale);
837
838 /* Create ArenaItems and set transform */
839
840=== modified file 'src/helper/png-write.cpp'
841--- src/helper/png-write.cpp 2012-05-24 05:49:41 +0000
842+++ src/helper/png-write.cpp 2013-09-20 17:05:49 +0000
843@@ -34,6 +34,7 @@
844 #include "preferences.h"
845 #include "rdf.h"
846 #include "display/cairo-utils.h"
847+#include "util/units.h"
848
849 /* This is an example of how to use libpng to read and write PNG files.
850 * The file libpng.txt is much more verbose then this. If you have not
851@@ -415,7 +416,7 @@
852 doc->ensureUpToDate();
853
854 /* Calculate translation by transforming to document coordinates (flipping Y)*/
855- Geom::Point translation = Geom::Point(-area[Geom::X][0], area[Geom::Y][1] - doc->getHeight());
856+ Geom::Point translation = Geom::Point(-area[Geom::X][0], area[Geom::Y][1] - doc->getHeight().value("px"));
857
858 /* This calculation is only valid when assumed that (x0,y0)= area.corner(0) and (x1,y1) = area.corner(2)
859 * 1) a[0] * x0 + a[2] * y1 + a[4] = 0.0
860
861=== modified file 'src/inkview.cpp'
862--- src/inkview.cpp 2013-03-25 17:42:31 +0000
863+++ src/inkview.cpp 2013-09-20 17:05:49 +0000
864@@ -54,6 +54,7 @@
865 #include "document.h"
866 #include "svg-view.h"
867 #include "svg-view-widget.h"
868+#include "util/units.h"
869
870 #ifdef WITH_INKJAR
871 #include "io/inkjar.h"
872@@ -308,8 +309,8 @@
873 w = gtk_window_new (GTK_WINDOW_TOPLEVEL);
874 gtk_window_set_title( GTK_WINDOW(w), ss.doc->getName() );
875 gtk_window_set_default_size (GTK_WINDOW (w),
876- MIN ((int)(ss.doc)->getWidth (), (int)gdk_screen_width () - 64),
877- MIN ((int)(ss.doc)->getHeight (), (int)gdk_screen_height () - 64));
878+ MIN ((int)(ss.doc)->getWidth().value("px"), (int)gdk_screen_width() - 64),
879+ MIN ((int)(ss.doc)->getHeight().value("px"), (int)gdk_screen_height() - 64));
880 ss.window = w;
881
882 g_signal_connect (G_OBJECT (w), "delete_event", (GCallback) sp_svgview_main_delete, &ss);
883@@ -318,7 +319,7 @@
884 (ss.doc)->ensureUpToDate();
885 ss.view = sp_svg_view_widget_new (ss.doc);
886 (ss.doc)->doUnref ();
887- SP_SVG_VIEW_WIDGET(ss.view)->setResize( false, ss.doc->getWidth(), ss.doc->getHeight() );
888+ SP_SVG_VIEW_WIDGET(ss.view)->setResize( false, ss.doc->getWidth().value("px"), ss.doc->getHeight().value("px") );
889 gtk_widget_show (ss.view);
890 gtk_container_add (GTK_CONTAINER (w), ss.view);
891
892
893=== modified file 'src/lpe-tool-context.cpp'
894--- src/lpe-tool-context.cpp 2013-08-30 21:35:42 +0000
895+++ src/lpe-tool-context.cpp 2013-09-20 17:05:49 +0000
896@@ -330,8 +330,8 @@
897
898 void
899 lpetool_get_limiting_bbox_corners(SPDocument *document, Geom::Point &A, Geom::Point &B) {
900- Geom::Coord w = document->getWidth();
901- Geom::Coord h = document->getHeight();
902+ Geom::Coord w = document->getWidth().value("px");
903+ Geom::Coord h = document->getHeight().value("px");
904 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
905
906 double ulx = prefs->getDouble("/tools/lpetool/bbox_upperleftx", 0);
907
908=== modified file 'src/main.cpp'
909--- src/main.cpp 2013-08-30 21:35:42 +0000
910+++ src/main.cpp 2013-09-20 17:05:49 +0000
911@@ -1535,7 +1535,7 @@
912 g_warning("Export width %lu out of range (1 - %lu). Nothing exported.", width, (unsigned long int)PNG_UINT_31_MAX);
913 return 1;
914 }
915- dpi = (gdouble) width * Inkscape::Util::Quantity::convert(1, "in", "px") / area.width();
916+ dpi = (gdouble) Inkscape::Util::Quantity::convert(width, "in", "px") / area.width();
917 }
918
919 if (sp_export_height) {
920@@ -1545,15 +1545,15 @@
921 g_warning("Export height %lu out of range (1 - %lu). Nothing exported.", height, (unsigned long int)PNG_UINT_31_MAX);
922 return 1;
923 }
924- dpi = (gdouble) height * Inkscape::Util::Quantity::convert(1, "in", "px") / area.height();
925+ dpi = (gdouble) Inkscape::Util::Quantity::convert(height, "in", "px") / area.height();
926 }
927
928 if (!sp_export_width) {
929- width = (unsigned long int) (area.width() * dpi / Inkscape::Util::Quantity::convert(1, "in", "px") + 0.5);
930+ width = (unsigned long int) (Inkscape::Util::Quantity::convert(area.width(), "px", "in") * dpi + 0.5);
931 }
932
933 if (!sp_export_height) {
934- height = (unsigned long int) (area.height() * dpi / Inkscape::Util::Quantity::convert(1, "in", "px") + 0.5);
935+ height = (unsigned long int) (Inkscape::Util::Quantity::convert(area.height(), "px", "in") * dpi + 0.5);
936 }
937
938 guint32 bgcolor = 0x00000000;
939
940=== modified file 'src/object-snapper.cpp'
941--- src/object-snapper.cpp 2013-08-03 21:30:12 +0000
942+++ src/object-snapper.cpp 2013-09-20 17:05:49 +0000
943@@ -770,7 +770,7 @@
944
945 Geom::PathVector* Inkscape::ObjectSnapper::_getBorderPathv() const
946 {
947- Geom::Rect const border_rect = Geom::Rect(Geom::Point(0,0), Geom::Point((_snapmanager->getDocument())->getWidth(),(_snapmanager->getDocument())->getHeight()));
948+ Geom::Rect const border_rect = Geom::Rect(Geom::Point(0,0), Geom::Point((_snapmanager->getDocument())->getWidth().value("px"),(_snapmanager->getDocument())->getHeight().value("px")));
949 return _getPathvFromRect(border_rect);
950 }
951
952@@ -787,8 +787,8 @@
953
954 void Inkscape::ObjectSnapper::_getBorderNodes(std::vector<SnapCandidatePoint> *points) const
955 {
956- Geom::Coord w = (_snapmanager->getDocument())->getWidth();
957- Geom::Coord h = (_snapmanager->getDocument())->getHeight();
958+ Geom::Coord w = (_snapmanager->getDocument())->getWidth().value("px");
959+ Geom::Coord h = (_snapmanager->getDocument())->getHeight().value("px");
960 points->push_back(SnapCandidatePoint(Geom::Point(0,0), SNAPSOURCE_UNDEFINED, SNAPTARGET_PAGE_CORNER));
961 points->push_back(SnapCandidatePoint(Geom::Point(0,h), SNAPSOURCE_UNDEFINED, SNAPTARGET_PAGE_CORNER));
962 points->push_back(SnapCandidatePoint(Geom::Point(w,h), SNAPSOURCE_UNDEFINED, SNAPTARGET_PAGE_CORNER));
963
964=== modified file 'src/persp3d.cpp'
965--- src/persp3d.cpp 2013-07-31 20:51:23 +0000
966+++ src/persp3d.cpp 2013-09-20 17:05:49 +0000
967@@ -24,6 +24,7 @@
968 #include "desktop-handles.h"
969 #include <glibmm/i18n.h>
970 #include "verbs.h"
971+#include "util/units.h"
972
973 using Inkscape::DocumentUndo;
974
975@@ -168,10 +169,10 @@
976 repr = xml_doc->createElement("inkscape:perspective");
977 repr->setAttribute("sodipodi:type", "inkscape:persp3d");
978
979- Proj::Pt2 proj_vp_x = Proj::Pt2 (0.0, document->getHeight()/2, 1.0);
980+ Proj::Pt2 proj_vp_x = Proj::Pt2 (0.0, document->getHeight().value("px")/2, 1.0);
981 Proj::Pt2 proj_vp_y = Proj::Pt2 (0.0, 1000.0, 0.0);
982- Proj::Pt2 proj_vp_z = Proj::Pt2 (document->getWidth(), document->getHeight()/2, 1.0);
983- Proj::Pt2 proj_origin = Proj::Pt2 (document->getWidth()/2, document->getHeight()/3, 1.0);
984+ Proj::Pt2 proj_vp_z = Proj::Pt2 (document->getWidth().value("px"), document->getHeight().value("px")/2, 1.0);
985+ Proj::Pt2 proj_origin = Proj::Pt2 (document->getWidth().value("px")/2, document->getHeight().value("px")/3, 1.0);
986
987 if (dup) {
988 proj_vp_x = dup->tmat.column (Proj::X);
989
990=== modified file 'src/rect-context.cpp'
991--- src/rect-context.cpp 2013-08-30 21:35:42 +0000
992+++ src/rect-context.cpp 2013-09-20 17:05:49 +0000
993@@ -478,6 +478,7 @@
994 }
995
996 this->rect->updateRepr();
997+ this->rect->doWriteTransform(this->rect->getRepr(), this->rect->transform, NULL, true);
998
999 this->desktop->canvas->endForcedFullRedraws();
1000
1001
1002=== modified file 'src/selection-chemistry.cpp'
1003--- src/selection-chemistry.cpp 2013-09-19 02:05:00 +0000
1004+++ src/selection-chemistry.cpp 2013-09-20 17:05:49 +0000
1005@@ -2809,7 +2809,7 @@
1006 }
1007
1008 // calculate the transform to be applied to objects to move them to 0,0
1009- Geom::Point move_p = Geom::Point(0, doc->getHeight()) - *c;
1010+ Geom::Point move_p = Geom::Point(0, doc->getHeight().value("px")) - *c;
1011 move_p[Geom::Y] = -move_p[Geom::Y];
1012 Geom::Affine move = Geom::Affine(Geom::Translate(move_p));
1013
1014@@ -3093,7 +3093,7 @@
1015 }
1016
1017 // calculate the transform to be applied to objects to move them to 0,0
1018- Geom::Point move_p = Geom::Point(0, doc->getHeight()) - (r->min() + Geom::Point(0, r->dimensions()[Geom::Y]));
1019+ Geom::Point move_p = Geom::Point(0, doc->getHeight().value("px")) - (r->min() + Geom::Point(0, r->dimensions()[Geom::Y]));
1020 move_p[Geom::Y] = -move_p[Geom::Y];
1021 Geom::Affine move = Geom::Affine(Geom::Translate(move_p));
1022
1023@@ -3398,7 +3398,7 @@
1024 res = prefs_res;
1025 } else if (0 < prefs_min) {
1026 // If minsize is given, look up minimum bitmap size (default 250 pixels) and calculate resolution from it
1027- res = Inkscape::Util::Quantity::convert(1, "in", "px") * prefs_min / MIN(bbox->width(), bbox->height());
1028+ res = Inkscape::Util::Quantity::convert(prefs_min, "in", "px") / MIN(bbox->width(), bbox->height());
1029 } else {
1030 float hint_xdpi = 0, hint_ydpi = 0;
1031 Glib::ustring hint_filename;
1032@@ -3419,8 +3419,8 @@
1033 }
1034
1035 // The width and height of the bitmap in pixels
1036- unsigned width = (unsigned) floor(bbox->width() * res / Inkscape::Util::Quantity::convert(1, "in", "px"));
1037- unsigned height =(unsigned) floor(bbox->height() * res / Inkscape::Util::Quantity::convert(1, "in", "px"));
1038+ unsigned width = (unsigned) floor(bbox->width() * Inkscape::Util::Quantity::convert(res, "px", "in"));
1039+ unsigned height =(unsigned) floor(bbox->height() * Inkscape::Util::Quantity::convert(res, "px", "in"));
1040
1041 // Find out if we have to run an external filter
1042 gchar const *run = NULL;
1043
1044=== modified file 'src/shape-editor.cpp'
1045--- src/shape-editor.cpp 2013-08-03 21:39:12 +0000
1046+++ src/shape-editor.cpp 2013-09-20 17:05:49 +0000
1047@@ -35,6 +35,8 @@
1048
1049 using Inkscape::createKnotHolder;
1050
1051+bool ShapeEditor::_blockSetItem = false;
1052+
1053 ShapeEditor::ShapeEditor(SPDesktop *dt) {
1054 this->desktop = dt;
1055 this->knotholder = NULL;
1056@@ -169,6 +171,10 @@
1057
1058
1059 void ShapeEditor::set_item(SPItem *item, SubType type, bool keep_knotholder) {
1060+ if (_blockSetItem) {
1061+ return;
1062+ }
1063+
1064 // this happens (and should only happen) when for an LPEItem having both knotholder and
1065 // nodepath the knotholder is adapted; in this case we don't want to delete the knotholder
1066 // since this freezes the handles
1067
1068=== modified file 'src/shape-editor.h'
1069--- src/shape-editor.h 2011-10-05 07:06:08 +0000
1070+++ src/shape-editor.h 2013-09-20 17:05:49 +0000
1071@@ -65,11 +65,14 @@
1072 void shapeeditor_event_attr_changed(gchar const *name);
1073
1074 bool knot_mouseover();
1075+
1076+ static void blockSetItem(bool b) {_blockSetItem = b;}
1077
1078 private:
1079 bool has_knotholder ();
1080 void reset_item (SubType type, bool keep_knotholder = true);
1081 const SPItem *get_item (SubType type);
1082+ static bool _blockSetItem;
1083
1084 SPDesktop *desktop;
1085 KnotHolder *knotholder;
1086
1087=== modified file 'src/sp-ellipse.cpp'
1088--- src/sp-ellipse.cpp 2013-09-20 04:45:16 +0000
1089+++ src/sp-ellipse.cpp 2013-09-20 17:05:49 +0000
1090@@ -318,6 +318,59 @@
1091 }
1092 }
1093
1094+Geom::Affine SPGenericEllipse::set_transform(Geom::Affine const &xform)
1095+{
1096+ /* Calculate ellipse start in parent coords. */
1097+ Geom::Point pos( Geom::Point(this->cx.computed, this->cy.computed) * xform );
1098+
1099+ /* This function takes care of translation and scaling, we return whatever parts we can't
1100+ handle. */
1101+ Geom::Affine ret(Geom::Affine(xform).withoutTranslation());
1102+ gdouble const sw = hypot(ret[0], ret[1]);
1103+ gdouble const sh = hypot(ret[2], ret[3]);
1104+ if (sw > 1e-9) {
1105+ ret[0] /= sw;
1106+ ret[1] /= sw;
1107+ } else {
1108+ ret[0] = 1.0;
1109+ ret[1] = 0.0;
1110+ }
1111+ if (sh > 1e-9) {
1112+ ret[2] /= sh;
1113+ ret[3] /= sh;
1114+ } else {
1115+ ret[2] = 0.0;
1116+ ret[3] = 1.0;
1117+ }
1118+
1119+ if (this->rx._set) {
1120+ this->rx = this->rx.computed * sw;
1121+ }
1122+ if (this->ry._set) {
1123+ this->ry = this->ry.computed * sh;
1124+ }
1125+
1126+ /* Find start in item coords */
1127+ pos = pos * ret.inverse();
1128+ this->cx = pos[Geom::X];
1129+ this->cy = pos[Geom::Y];
1130+
1131+ this->set_shape();
1132+
1133+ // Adjust stroke width
1134+ this->adjust_stroke(sqrt(fabs(sw * sh)));
1135+
1136+ // Adjust pattern fill
1137+ this->adjust_pattern(xform * ret.inverse());
1138+
1139+ // Adjust gradient fill
1140+ this->adjust_gradient(xform * ret.inverse());
1141+
1142+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
1143+
1144+ return ret;
1145+}
1146+
1147 void
1148 sp_genericellipse_normalize(SPGenericEllipse *ellipse)
1149 {
1150
1151=== modified file 'src/sp-ellipse.h'
1152--- src/sp-ellipse.h 2013-09-20 04:45:16 +0000
1153+++ src/sp-ellipse.h 2013-09-20 17:05:49 +0000
1154@@ -39,6 +39,7 @@
1155
1156 virtual void snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs);
1157 virtual void set_shape();
1158+ virtual Geom::Affine set_transform(Geom::Affine const& xform);
1159
1160 virtual void update_patheffect(bool write);
1161 };
1162
1163=== modified file 'src/sp-flowtext.cpp'
1164--- src/sp-flowtext.cpp 2013-09-20 04:45:16 +0000
1165+++ src/sp-flowtext.cpp 2013-09-20 17:05:49 +0000
1166@@ -28,6 +28,7 @@
1167 #include "text-tag-attributes.h"
1168 #include "text-chemistry.h"
1169 #include "text-editing.h"
1170+#include "sp-text.h"
1171
1172 #include "livarot/Shape.h"
1173
1174@@ -648,6 +649,44 @@
1175 return ft_item;
1176 }
1177
1178+Geom::Affine SPFlowtext::set_transform (Geom::Affine const &xform)
1179+{
1180+ if ((this->_optimizeScaledText && !xform.withoutTranslation().isNonzeroUniformScale())
1181+ || (!this->_optimizeScaledText && !xform.isNonzeroUniformScale())) {
1182+ this->_optimizeScaledText = false;
1183+ return xform;
1184+ }
1185+ this->_optimizeScaledText = false;
1186+
1187+ SPText *text = reinterpret_cast<SPText *>(this);
1188+
1189+ double const ex = xform.descrim();
1190+ if (ex == 0) {
1191+ return xform;
1192+ }
1193+
1194+ Geom::Affine ret(xform);
1195+ ret[0] /= ex;
1196+ ret[1] /= ex;
1197+ ret[2] /= ex;
1198+ ret[3] /= ex;
1199+
1200+ // Adjust font size
1201+ text->_adjustFontsizeRecursive (this, ex);
1202+
1203+ // Adjust stroke width
1204+ this->adjust_stroke_width_recursive (ex);
1205+
1206+ // Adjust pattern fill
1207+ this->adjust_pattern(xform * ret.inverse());
1208+
1209+ // Adjust gradient fill
1210+ this->adjust_gradient(xform * ret.inverse());
1211+
1212+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_TEXT_LAYOUT_MODIFIED_FLAG);
1213+
1214+ return ret;
1215+}
1216
1217 /*
1218 Local Variables:
1219
1220=== modified file 'src/sp-flowtext.h'
1221--- src/sp-flowtext.h 2013-09-20 04:45:16 +0000
1222+++ src/sp-flowtext.h 2013-09-20 17:05:49 +0000
1223@@ -43,6 +43,12 @@
1224
1225 double par_indent;
1226
1227+ bool _optimizeScaledText;
1228+
1229+ /** Optimize scaled flow text on next set_transform. */
1230+ void optimizeScaledText()
1231+ {_optimizeScaledText = true;}
1232+
1233 private:
1234 /** Recursively walks the xml tree adding tags and their contents. */
1235 void _buildLayoutInput(SPObject *root, Shape const *exclusion_shape, std::list<Shape> *shapes, SPObject **pending_line_break_object);
1236@@ -58,6 +64,7 @@
1237 virtual void remove_child(Inkscape::XML::Node* child);
1238
1239 virtual void set(unsigned int key, const gchar* value);
1240+ virtual Geom::Affine set_transform(Geom::Affine const& xform);
1241
1242 virtual void update(SPCtx* ctx, unsigned int flags);
1243 virtual void modified(unsigned int flags);
1244
1245=== modified file 'src/sp-guide.cpp'
1246--- src/sp-guide.cpp 2013-08-30 21:35:42 +0000
1247+++ src/sp-guide.cpp 2013-09-20 17:05:49 +0000
1248@@ -287,7 +287,7 @@
1249 std::list<std::pair<Geom::Point, Geom::Point> > pts;
1250
1251 Geom::Point A(0, 0);
1252- Geom::Point C(doc->getWidth(), doc->getHeight());
1253+ Geom::Point C(doc->getWidth().value("px"), doc->getHeight().value("px"));
1254 Geom::Point B(C[Geom::X], 0);
1255 Geom::Point D(0, C[Geom::Y]);
1256
1257
1258=== modified file 'src/sp-item-group.cpp'
1259--- src/sp-item-group.cpp 2013-09-20 04:45:16 +0000
1260+++ src/sp-item-group.cpp 2013-09-20 17:05:49 +0000
1261@@ -50,6 +50,9 @@
1262 #include "sp-switch.h"
1263 #include "sp-defs.h"
1264 #include "verbs.h"
1265+#include "layer-model.h"
1266+#include "sp-textpath.h"
1267+#include "sp-flowtext.h"
1268
1269 using Inkscape::DocumentUndo;
1270
1271@@ -644,6 +647,81 @@
1272 }
1273 }
1274
1275+// Recursively scale child items around a point
1276+void SPGroup::scaleChildItemsRec(Geom::Scale const &sc, Geom::Point const &p)
1277+{
1278+ if ( hasChildren() ) {
1279+ for (SPObject *o = firstChild() ; o ; o = o->getNext() ) {
1280+ if ( SP_IS_ITEM(o) ) {
1281+ if (SP_IS_GROUP(o) && !SP_IS_BOX3D(o)) {
1282+ SP_GROUP(o)->scaleChildItemsRec(sc, p);
1283+ } else {
1284+ SPItem *item = SP_ITEM(o);
1285+ Geom::OptRect bbox = item->desktopVisualBounds();
1286+ if (bbox) {
1287+ // Scale item
1288+ Geom::Translate const s(p);
1289+ Geom::Affine final = s.inverse() * sc * s;
1290+
1291+ Geom::Point old_center(0,0);
1292+ if (item->isCenterSet()) {
1293+ old_center = item->getCenter();
1294+ }
1295+
1296+ gchar const *conn_type = NULL;
1297+ if (SP_IS_TEXT_TEXTPATH(item)) {
1298+ SP_TEXT(item)->optimizeTextpathText();
1299+ } else if (SP_IS_FLOWTEXT(item)) {
1300+ SP_FLOWTEXT(item)->optimizeScaledText();
1301+ } else if (SP_IS_BOX3D(item)) {
1302+ // Force recalculation from perspective
1303+ box3d_position_set(SP_BOX3D(item));
1304+ } else if (item->getAttribute("inkscape:connector-type") != NULL
1305+ && (item->getAttribute("inkscape:connection-start") == NULL
1306+ || item->getAttribute("inkscape:connection-end") == NULL)) {
1307+ // Remove and store connector type for transform if disconnected
1308+ conn_type = item->getAttribute("inkscape:connector-type");
1309+ item->removeAttribute("inkscape:connector-type");
1310+ }
1311+
1312+ if (SP_IS_PERSP3D(item)) {
1313+ persp3d_apply_affine_transformation(SP_PERSP3D(item), final);
1314+ } else if ((SP_IS_TEXT_TEXTPATH(item) || SP_IS_FLOWTEXT(item)) && !item->transform.isIdentity()) {
1315+ // Save and reset current transform
1316+ Geom::Affine tmp(item->transform);
1317+ item->transform = Geom::Affine();
1318+ // Apply scale
1319+ item->set_i2d_affine(item->i2dt_affine() * sc);
1320+ item->doWriteTransform(item->getRepr(), item->transform, NULL, true);
1321+ // Scale translation and restore original transform
1322+ tmp[4] *= sc[0];
1323+ tmp[5] *= sc[1];
1324+ item->doWriteTransform(item->getRepr(), tmp, NULL, true);
1325+ } else if (SP_IS_USE(item)) {
1326+ // calculate the matrix we need to apply to the clone
1327+ // to cancel its induced transform from its original
1328+ Geom::Affine move = final.inverse() * item->transform * final;
1329+ item->doWriteTransform(item->getRepr(), move, &move, true);
1330+ } else {
1331+ item->set_i2d_affine(item->i2dt_affine() * final);
1332+ item->doWriteTransform(item->getRepr(), item->transform, NULL, true);
1333+ }
1334+
1335+ if (conn_type != NULL) {
1336+ item->setAttribute("inkscape:connector-type", conn_type);
1337+ }
1338+
1339+ if (item->isCenterSet() && !(final.isTranslation() || final.isIdentity())) {
1340+ item->setCenter(old_center * final);
1341+ item->updateRepr();
1342+ }
1343+ }
1344+ }
1345+ }
1346+ }
1347+ }
1348+}
1349+
1350 gint SPGroup::getItemCount() {
1351 gint len = 0;
1352 for (SPObject *o = this->firstChild() ; o ; o = o->getNext() ) {
1353
1354=== modified file 'src/sp-item-group.h'
1355--- src/sp-item-group.h 2013-09-20 04:45:16 +0000
1356+++ src/sp-item-group.h 2013-09-20 17:05:49 +0000
1357@@ -52,6 +52,7 @@
1358 LayerMode layerDisplayMode(unsigned int display_key) const;
1359 void setLayerDisplayMode(unsigned int display_key, LayerMode mode);
1360 void translateChildItems(Geom::Translate const &tr);
1361+ void scaleChildItemsRec(Geom::Scale const &sc, Geom::Point const &p);
1362
1363 gint getItemCount();
1364 void _showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags);
1365
1366=== modified file 'src/sp-item.cpp'
1367--- src/sp-item.cpp 2013-09-20 04:45:16 +0000
1368+++ src/sp-item.cpp 2013-09-20 17:05:49 +0000
1369@@ -73,6 +73,8 @@
1370 #include "live_effects/effect.h"
1371 #include "live_effects/lpeobject-reference.h"
1372
1373+#include "util/units.h"
1374+
1375 #define noSP_ITEM_DEBUG_IDLE
1376
1377
1378@@ -818,7 +820,7 @@
1379 Geom::OptRect SPItem::desktopVisualBounds() const
1380 {
1381 /// @fixme hardcoded desktop transform
1382- Geom::Affine m = Geom::Scale(1, -1) * Geom::Translate(0, document->getHeight());
1383+ Geom::Affine m = Geom::Scale(1, -1) * Geom::Translate(0, document->getHeight().value("px"));
1384 Geom::OptRect ret = documentVisualBounds();
1385 if (ret) *ret *= m;
1386 return ret;
1387@@ -1500,7 +1502,7 @@
1388 // TODO temp code to prevent crashing on command-line launch:
1389 ret = i2doc_affine()
1390 * Geom::Scale(1, -1)
1391- * Geom::Translate(0, document->getHeight());
1392+ * Geom::Translate(0, document->getHeight().value("px"));
1393 }
1394 return ret;
1395 }
1396
1397=== modified file 'src/sp-root.h'
1398--- src/sp-root.h 2013-09-15 00:43:49 +0000
1399+++ src/sp-root.h 2013-09-20 17:05:49 +0000
1400@@ -41,7 +41,7 @@
1401 SVGLength height;
1402
1403 /* viewBox; */
1404- unsigned int viewBox_set : 1;
1405+ bool viewBox_set : true;
1406 Geom::Rect viewBox;
1407
1408 /* preserveAspectRatio */
1409
1410=== modified file 'src/sp-spiral.cpp'
1411--- src/sp-spiral.cpp 2013-09-20 04:45:16 +0000
1412+++ src/sp-spiral.cpp 2013-09-20 17:05:49 +0000
1413@@ -28,7 +28,6 @@
1414
1415 #include "sp-spiral.h"
1416
1417-
1418 #include "sp-factory.h"
1419
1420 namespace {
1421@@ -435,6 +434,58 @@
1422 }
1423
1424 /**
1425+ * Set spiral transform
1426+ */
1427+Geom::Affine SPSpiral::set_transform(Geom::Affine const &xform)
1428+{
1429+ // Only set transform with proportional scaling
1430+ if (!xform.withoutTranslation().isUniformScale()) {
1431+ return xform;
1432+ }
1433+
1434+ /* Calculate spiral start in parent coords. */
1435+ Geom::Point pos( Geom::Point(this->cx, this->cy) * xform );
1436+
1437+ /* This function takes care of translation and scaling, we return whatever parts we can't
1438+ handle. */
1439+ Geom::Affine ret(Geom::Affine(xform).withoutTranslation());
1440+ gdouble const s = hypot(ret[0], ret[1]);
1441+ if (s > 1e-9) {
1442+ ret[0] /= s;
1443+ ret[1] /= s;
1444+ ret[2] /= s;
1445+ ret[3] /= s;
1446+ } else {
1447+ ret[0] = 1.0;
1448+ ret[1] = 0.0;
1449+ ret[2] = 0.0;
1450+ ret[3] = 1.0;
1451+ }
1452+
1453+ this->rad *= s;
1454+
1455+ /* Find start in item coords */
1456+ pos = pos * ret.inverse();
1457+ this->cx = pos[Geom::X];
1458+ this->cy = pos[Geom::Y];
1459+
1460+ this->set_shape();
1461+
1462+ // Adjust stroke width
1463+ this->adjust_stroke(s);
1464+
1465+ // Adjust pattern fill
1466+ this->adjust_pattern(xform * ret.inverse());
1467+
1468+ // Adjust gradient fill
1469+ this->adjust_gradient(xform * ret.inverse());
1470+
1471+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
1472+
1473+ return ret;
1474+}
1475+
1476+/**
1477 * Return one of the points on the spiral.
1478 *
1479 * \param t specifies how far along the spiral.
1480
1481=== modified file 'src/sp-spiral.h'
1482--- src/sp-spiral.h 2013-09-20 04:45:16 +0000
1483+++ src/sp-spiral.h 2013-09-20 17:05:49 +0000
1484@@ -53,6 +53,7 @@
1485
1486 /* Lowlevel interface */
1487 void setPosition(gdouble cx, gdouble cy, gdouble exp, gdouble revo, gdouble rad, gdouble arg, gdouble t0);
1488+ virtual Geom::Affine set_transform(Geom::Affine const& xform);
1489
1490 Geom::Point getXY(gdouble t) const;
1491
1492
1493=== modified file 'src/sp-star.cpp'
1494--- src/sp-star.cpp 2013-09-20 04:45:16 +0000
1495+++ src/sp-star.cpp 2013-09-20 17:05:49 +0000
1496@@ -514,6 +514,55 @@
1497 }
1498 }
1499
1500+Geom::Affine SPStar::set_transform(Geom::Affine const &xform)
1501+{
1502+ // Only set transform with proportional scaling
1503+ if (!xform.withoutTranslation().isUniformScale()) {
1504+ return xform;
1505+ }
1506+
1507+ /* Calculate star start in parent coords. */
1508+ Geom::Point pos( this->center * xform );
1509+
1510+ /* This function takes care of translation and scaling, we return whatever parts we can't
1511+ handle. */
1512+ Geom::Affine ret(Geom::Affine(xform).withoutTranslation());
1513+ gdouble const s = hypot(ret[0], ret[1]);
1514+ if (s > 1e-9) {
1515+ ret[0] /= s;
1516+ ret[1] /= s;
1517+ ret[2] /= s;
1518+ ret[3] /= s;
1519+ } else {
1520+ ret[0] = 1.0;
1521+ ret[1] = 0.0;
1522+ ret[2] = 0.0;
1523+ ret[3] = 1.0;
1524+ }
1525+
1526+ this->r[0] *= s;
1527+ this->r[1] *= s;
1528+
1529+ /* Find start in item coords */
1530+ pos = pos * ret.inverse();
1531+ this->center = pos;
1532+
1533+ this->set_shape();
1534+
1535+ // Adjust stroke width
1536+ this->adjust_stroke(s);
1537+
1538+ // Adjust pattern fill
1539+ this->adjust_pattern(xform * ret.inverse());
1540+
1541+ // Adjust gradient fill
1542+ this->adjust_gradient(xform * ret.inverse());
1543+
1544+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
1545+
1546+ return ret;
1547+}
1548+
1549 /**
1550 * sp_star_get_xy: Get X-Y value as item coordinate system
1551 * @star: star item
1552
1553=== modified file 'src/sp-star.h'
1554--- src/sp-star.h 2013-09-20 04:45:16 +0000
1555+++ src/sp-star.h 2013-09-20 17:05:49 +0000
1556@@ -56,6 +56,7 @@
1557
1558 virtual void update_patheffect(bool write);
1559 virtual void set_shape();
1560+ virtual Geom::Affine set_transform(Geom::Affine const& xform);
1561 };
1562
1563 void sp_star_position_set (SPStar *star, gint sides, Geom::Point center, gdouble r1, gdouble r2, gdouble arg1, gdouble arg2, bool isflat, double rounded, double randomized);
1564
1565=== modified file 'src/sp-text.cpp'
1566--- src/sp-text.cpp 2013-09-20 04:45:16 +0000
1567+++ src/sp-text.cpp 2013-09-20 17:05:49 +0000
1568@@ -377,8 +377,13 @@
1569
1570 Geom::Affine SPText::set_transform(Geom::Affine const &xform) {
1571 // we cannot optimize textpath because changing its fontsize will break its match to the path
1572- if (SP_IS_TEXT_TEXTPATH (this))
1573- return xform;
1574+ if (SP_IS_TEXT_TEXTPATH (this)) {
1575+ if (!this->_optimizeTextpathText) {
1576+ return xform;
1577+ } else {
1578+ this->_optimizeTextpathText = false;
1579+ }
1580+ }
1581
1582 /* This function takes care of scaling & translation only, we return whatever parts we can't
1583 handle. */
1584
1585=== modified file 'src/sp-text.h'
1586--- src/sp-text.h 2013-09-20 04:45:16 +0000
1587+++ src/sp-text.h 2013-09-20 17:05:49 +0000
1588@@ -58,6 +58,8 @@
1589 /** discards the drawing objects representing this text. */
1590 void _clearFlow(Inkscape::DrawingGroup *in_arena);
1591
1592+ bool _optimizeTextpathText;
1593+
1594 private:
1595 /** Recursively walks the xml tree adding tags and their contents. The
1596 non-trivial code does two things: firstly, it manages the positioning
1597@@ -67,6 +69,10 @@
1598 unsigned _buildLayoutInput(SPObject *root, Inkscape::Text::Layout::OptionalTextTagAttrs const &parent_optional_attrs, unsigned parent_attrs_offset, bool in_textpath);
1599
1600 public:
1601+ /** Optimize textpath text on next set_transform. */
1602+ void optimizeTextpathText()
1603+ {_optimizeTextpathText = true;}
1604+
1605 virtual void build(SPDocument* doc, Inkscape::XML::Node* repr);
1606 virtual void release();
1607 virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref);
1608
1609=== modified file 'src/spiral-context.cpp'
1610--- src/spiral-context.cpp 2013-08-30 21:35:42 +0000
1611+++ src/spiral-context.cpp 2013-09-20 17:05:49 +0000
1612@@ -417,6 +417,7 @@
1613
1614 spiral->set_shape();
1615 spiral->updateRepr(SP_OBJECT_WRITE_EXT);
1616+ spiral->doWriteTransform(spiral->getRepr(), spiral->transform, NULL, true);
1617
1618 this->desktop->canvas->endForcedFullRedraws();
1619
1620
1621=== modified file 'src/star-context.cpp'
1622--- src/star-context.cpp 2013-08-30 21:35:42 +0000
1623+++ src/star-context.cpp 2013-09-20 17:05:49 +0000
1624@@ -443,6 +443,7 @@
1625 this->star->setCenter(this->center);
1626 this->star->set_shape();
1627 this->star->updateRepr(SP_OBJECT_WRITE_EXT);
1628+ this->star->doWriteTransform(this->star->getRepr(), this->star->transform, NULL, true);
1629
1630 desktop->canvas->endForcedFullRedraws();
1631
1632
1633=== modified file 'src/style.cpp'
1634--- src/style.cpp 2013-09-18 19:16:05 +0000
1635+++ src/style.cpp 2013-09-20 17:05:49 +0000
1636@@ -2523,11 +2523,11 @@
1637
1638 case SP_CSS_UNIT_NONE: unit_size = size; break;
1639 case SP_CSS_UNIT_PX: unit_size = size; break;
1640- case SP_CSS_UNIT_PT: unit_size = size * Inkscape::Util::Quantity::convert(1, "px", "pt"); break;
1641- case SP_CSS_UNIT_PC: unit_size = size * (Inkscape::Util::Quantity::convert(1, "px", "pt") / Inkscape::Util::Quantity::convert(1, "pc", "pt")); break;
1642- case SP_CSS_UNIT_MM: unit_size = size * Inkscape::Util::Quantity::convert(1, "px", "mm"); break;
1643- case SP_CSS_UNIT_CM: unit_size = size * Inkscape::Util::Quantity::convert(1, "px", "cm"); break;
1644- case SP_CSS_UNIT_IN: unit_size = size * Inkscape::Util::Quantity::convert(1, "px", "in"); break;
1645+ case SP_CSS_UNIT_PT: unit_size = Inkscape::Util::Quantity::convert(size, "px", "pt"); break;
1646+ case SP_CSS_UNIT_PC: unit_size = Inkscape::Util::Quantity::convert(size, "px", "pc"); break;
1647+ case SP_CSS_UNIT_MM: unit_size = Inkscape::Util::Quantity::convert(size, "px", "mm"); break;
1648+ case SP_CSS_UNIT_CM: unit_size = Inkscape::Util::Quantity::convert(size, "px", "cm"); break;
1649+ case SP_CSS_UNIT_IN: unit_size = Inkscape::Util::Quantity::convert(size, "px", "in"); break;
1650 case SP_CSS_UNIT_EM: unit_size = size / SP_CSS_FONT_SIZE_DEFAULT; break;
1651 case SP_CSS_UNIT_EX: unit_size = size * 2.0 / SP_CSS_FONT_SIZE_DEFAULT ; break;
1652 case SP_CSS_UNIT_PERCENT: unit_size = size * 100.0 / SP_CSS_FONT_SIZE_DEFAULT; break;
1653@@ -3530,19 +3530,19 @@
1654 } else if (!strcmp(e, "pt")) {
1655 /* Userspace / DEVICESCALE */
1656 val->unit = SP_CSS_UNIT_PT;
1657- val->computed = value * Inkscape::Util::Quantity::convert(1, "pt", "px");
1658+ val->computed = Inkscape::Util::Quantity::convert(value, "pt", "px");
1659 } else if (!strcmp(e, "pc")) {
1660 val->unit = SP_CSS_UNIT_PC;
1661- val->computed = value * Inkscape::Util::Quantity::convert(1, "pc", "px");
1662+ val->computed = Inkscape::Util::Quantity::convert(value, "pc", "px");
1663 } else if (!strcmp(e, "mm")) {
1664 val->unit = SP_CSS_UNIT_MM;
1665- val->computed = value * Inkscape::Util::Quantity::convert(1, "mm", "px");
1666+ val->computed = Inkscape::Util::Quantity::convert(value, "mm", "px");
1667 } else if (!strcmp(e, "cm")) {
1668 val->unit = SP_CSS_UNIT_CM;
1669- val->computed = value * Inkscape::Util::Quantity::convert(1, "cm", "px");
1670+ val->computed = Inkscape::Util::Quantity::convert(value, "cm", "px");
1671 } else if (!strcmp(e, "in")) {
1672 val->unit = SP_CSS_UNIT_IN;
1673- val->computed = value * Inkscape::Util::Quantity::convert(1, "in", "px");
1674+ val->computed = Inkscape::Util::Quantity::convert(value, "in", "px");
1675 } else if (!strcmp(e, "em")) {
1676 /* EM square */
1677 val->unit = SP_CSS_UNIT_EM;
1678@@ -4204,23 +4204,23 @@
1679 return g_strlcpy(p, os.str().c_str(), len);
1680 break;
1681 case SP_CSS_UNIT_PT:
1682- os << key << ":" << val->computed * Inkscape::Util::Quantity::convert(1, "px", "pt") << "pt;";
1683+ os << key << ":" << Inkscape::Util::Quantity::convert(val->computed, "px", "pt") << "pt;";
1684 return g_strlcpy(p, os.str().c_str(), len);
1685 break;
1686 case SP_CSS_UNIT_PC:
1687- os << key << ":" << val->computed * Inkscape::Util::Quantity::convert(1, "px", "pt") / 12.0 << "pc;";
1688+ os << key << ":" << Inkscape::Util::Quantity::convert(val->computed, "px", "pc") << "pc;";
1689 return g_strlcpy(p, os.str().c_str(), len);
1690 break;
1691 case SP_CSS_UNIT_MM:
1692- os << key << ":" << val->computed * Inkscape::Util::Quantity::convert(1, "px", "mm") << "mm;";
1693+ os << key << ":" << Inkscape::Util::Quantity::convert(val->computed, "px", "mm") << "mm;";
1694 return g_strlcpy(p, os.str().c_str(), len);
1695 break;
1696 case SP_CSS_UNIT_CM:
1697- os << key << ":" << val->computed * Inkscape::Util::Quantity::convert(1, "px", "cm") << "cm;";
1698+ os << key << ":" << Inkscape::Util::Quantity::convert(val->computed, "px", "cm") << "cm;";
1699 return g_strlcpy(p, os.str().c_str(), len);
1700 break;
1701 case SP_CSS_UNIT_IN:
1702- os << key << ":" << val->computed * Inkscape::Util::Quantity::convert(1, "px", "in") << "in;";
1703+ os << key << ":" << Inkscape::Util::Quantity::convert(val->computed, "px", "in") << "in;";
1704 return g_strlcpy(p, os.str().c_str(), len);
1705 break;
1706 case SP_CSS_UNIT_EM:
1707
1708=== modified file 'src/svg-view-widget.cpp'
1709--- src/svg-view-widget.cpp 2012-06-09 20:37:17 +0000
1710+++ src/svg-view-widget.cpp 2013-09-20 17:05:49 +0000
1711@@ -21,6 +21,7 @@
1712 #include "document.h"
1713 #include "svg-view.h"
1714 #include "svg-view-widget.h"
1715+#include "util/units.h"
1716
1717 static void sp_svg_view_widget_class_init (SPSVGSPViewWidgetClass *klass);
1718 static void sp_svg_view_widget_init (SPSVGSPViewWidget *widget);
1719@@ -175,8 +176,8 @@
1720 gdouble width, height;
1721
1722 svgv = static_cast<SPSVGView*> (v);
1723- width = (v->doc())->getWidth () * svgv->_hscale;
1724- height = (v->doc())->getHeight () * svgv->_vscale;
1725+ width = (v->doc())->getWidth().value("px") * svgv->_hscale;
1726+ height = (v->doc())->getHeight().value("px") * svgv->_vscale;
1727
1728 if (width <= vw->maxwidth) {
1729 hpol = GTK_POLICY_NEVER;
1730
1731=== modified file 'src/svg-view.cpp'
1732--- src/svg-view.cpp 2012-04-09 17:19:31 +0000
1733+++ src/svg-view.cpp 2013-09-20 17:05:49 +0000
1734@@ -20,6 +20,7 @@
1735 #include "sp-item.h"
1736 #include "svg-view.h"
1737 #include "sp-root.h"
1738+#include "util/units.h"
1739
1740 SPSVGView::SPSVGView(SPCanvasGroup *parent)
1741 {
1742@@ -71,16 +72,16 @@
1743 if (!doc()) {
1744 return;
1745 }
1746- if (doc()->getWidth () < 1e-9) {
1747+ if (doc()->getWidth().value("px") < 1e-9) {
1748 return;
1749 }
1750- if (doc()->getHeight () < 1e-9) {
1751+ if (doc()->getHeight().value("px") < 1e-9) {
1752 return;
1753 }
1754
1755 if (_rescale) {
1756- _hscale = _width / doc()->getWidth ();
1757- _vscale = _height / doc()->getHeight ();
1758+ _hscale = _width / doc()->getWidth().value("px");
1759+ _vscale = _height / doc()->getHeight().value("px");
1760 if (_keepaspect) {
1761 if (_hscale > _vscale) {
1762 _hscale = _vscale;
1763@@ -95,8 +96,8 @@
1764 }
1765
1766 if (event) {
1767- emitResized (doc()->getWidth () * _hscale,
1768- doc()->getHeight () * _vscale);
1769+ emitResized (doc()->getWidth().value("px") * _hscale,
1770+ doc()->getHeight().value("px") * _vscale);
1771 }
1772 }
1773
1774
1775=== modified file 'src/text-context.cpp'
1776--- src/text-context.cpp 2013-08-30 21:35:42 +0000
1777+++ src/text-context.cpp 2013-09-20 17:05:49 +0000
1778@@ -441,6 +441,7 @@
1779 text_item->transform = SP_ITEM(ec->desktop->currentLayer())->i2doc_affine().inverse();
1780
1781 text_item->updateRepr();
1782+ text_item->doWriteTransform(text_item->getRepr(), text_item->transform, NULL, true);
1783 DocumentUndo::done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT,
1784 _("Create text"));
1785 }
1786
1787=== modified file 'src/ui/clipboard.cpp'
1788--- src/ui/clipboard.cpp 2013-09-14 11:09:15 +0000
1789+++ src/ui/clipboard.cpp 2013-09-20 17:05:49 +0000
1790@@ -1087,8 +1087,8 @@
1791 Geom::Point origin (_clipboardSPDoc->getRoot()->x.computed, _clipboardSPDoc->getRoot()->y.computed);
1792 Geom::Rect area = Geom::Rect(origin, origin + _clipboardSPDoc->getDimensions());
1793
1794- unsigned long int width = (unsigned long int) (area.width() * dpi / Inkscape::Util::Quantity::convert(1, "in", "px") + 0.5);
1795- unsigned long int height = (unsigned long int) (area.height() * dpi / Inkscape::Util::Quantity::convert(1, "in", "px") + 0.5);
1796+ unsigned long int width = (unsigned long int) (Inkscape::Util::Quantity::convert(area.width(), "px", "in") * dpi + 0.5);
1797+ unsigned long int height = (unsigned long int) (Inkscape::Util::Quantity::convert(area.height(), "in", "px") * dpi + 0.5);
1798
1799 // read from namedview
1800 Inkscape::XML::Node *nv = sp_repr_lookup_name (_clipboardSPDoc->rroot, "sodipodi:namedview");
1801
1802=== modified file 'src/ui/dialog/aboutbox.cpp'
1803--- src/ui/dialog/aboutbox.cpp 2013-06-17 22:53:50 +0000
1804+++ src/ui/dialog/aboutbox.cpp 2013-09-20 17:05:49 +0000
1805@@ -34,6 +34,7 @@
1806 #include "svg-view-widget.h"
1807 #include "sp-text.h"
1808 #include "text-editing.h"
1809+#include "util/units.h"
1810
1811 #include "inkscape-version.h"
1812
1813@@ -175,8 +176,8 @@
1814
1815 GtkWidget *v=sp_svg_view_widget_new(doc);
1816
1817- double width=doc->getWidth();
1818- double height=doc->getHeight();
1819+ double width=doc->getWidth().value("px");
1820+ double height=doc->getHeight().value("px");
1821
1822 doc->doUnref();
1823
1824
1825=== modified file 'src/ui/dialog/document-properties.cpp'
1826--- src/ui/dialog/document-properties.cpp 2013-08-30 21:35:42 +0000
1827+++ src/ui/dialog/document-properties.cpp 2013-09-20 17:05:49 +0000
1828@@ -31,9 +31,12 @@
1829 #include "inkscape.h"
1830 #include "io/sys.h"
1831 #include "preferences.h"
1832+#include "shape-editor.h"
1833 #include "sp-namedview.h"
1834 #include "sp-root.h"
1835 #include "sp-script.h"
1836+#include "svg/stringstream.h"
1837+#include "tools-switch.h"
1838 #include "ui/widget/color-picker.h"
1839 #include "ui/widget/scalar-unit.h"
1840 #include "ui/dialog/filedialog.h"
1841@@ -53,6 +56,8 @@
1842 #include <gtkmm/stock.h>
1843 #include <gtkmm/table.h>
1844
1845+#include <2geom/transforms.h>
1846+
1847 using std::pair;
1848
1849 namespace Inkscape {
1850@@ -168,6 +173,9 @@
1851 signalDocumentReplaced().connect(sigc::mem_fun(*this, &DocumentProperties::_handleDocumentReplaced));
1852 signalActivateDesktop().connect(sigc::mem_fun(*this, &DocumentProperties::_handleActivateDesktop));
1853 signalDeactiveDesktop().connect(sigc::mem_fun(*this, &DocumentProperties::_handleDeactivateDesktop));
1854+
1855+ _rum_deflt._changed_connection.block();
1856+ _rum_deflt.getUnitMenu()->signal_changed().connect(sigc::mem_fun(*this, &DocumentProperties::onDocUnitChange));
1857 }
1858
1859 void DocumentProperties::init()
1860@@ -1432,9 +1440,17 @@
1861 if (nv->doc_units)
1862 _rum_deflt.setUnit (nv->doc_units->abbr);
1863
1864- double const doc_w_px = sp_desktop_document(dt)->getWidth();
1865- double const doc_h_px = sp_desktop_document(dt)->getHeight();
1866- _page_sizer.setDim (doc_w_px, doc_h_px);
1867+ double const doc_w = sp_desktop_document(dt)->getRoot()->width.value;
1868+ Glib::ustring doc_w_unit = unit_table.getUnit(sp_desktop_document(dt)->getRoot()->width.unit).abbr;
1869+ if (doc_w_unit == "") {
1870+ doc_w_unit = "px";
1871+ }
1872+ double const doc_h = sp_desktop_document(dt)->getRoot()->height.value;
1873+ Glib::ustring doc_h_unit = unit_table.getUnit(sp_desktop_document(dt)->getRoot()->height.unit).abbr;
1874+ if (doc_h_unit == "") {
1875+ doc_h_unit = "px";
1876+ }
1877+ _page_sizer.setDim(Inkscape::Util::Quantity(doc_w, doc_w_unit), Inkscape::Util::Quantity(doc_h, doc_h_unit));
1878 _page_sizer.updateFitMarginsUI(nv->getRepr());
1879
1880 //-----------------------------------------------------------guide page
1881@@ -1617,6 +1633,47 @@
1882 }
1883 }
1884
1885+/** Callback for document unit change. */
1886+void DocumentProperties::onDocUnitChange()
1887+{
1888+ SPDocument *doc = SP_ACTIVE_DOCUMENT;
1889+ Inkscape::XML::Node *repr = sp_desktop_namedview(getDesktop())->getRepr();
1890+ Inkscape::Util::Unit old_doc_unit = unit_table.getUnit("px");
1891+ if(repr->attribute("inkscape:document-units")) {
1892+ old_doc_unit = unit_table.getUnit(repr->attribute("inkscape:document-units"));
1893+ }
1894+ Inkscape::Util::Unit doc_unit = _rum_deflt.getUnit();
1895+
1896+ // Don't execute when change is being undone
1897+ if (!DocumentUndo::getUndoSensitive(doc)) {
1898+ return;
1899+ }
1900+
1901+ // Set document unit
1902+ Inkscape::SVGOStringStream os;
1903+ os << doc_unit.abbr;
1904+ repr->setAttribute("inkscape:document-units", os.str().c_str());
1905+
1906+ // Set viewBox
1907+ Inkscape::Util::Quantity width = doc->getWidth();
1908+ Inkscape::Util::Quantity height = doc->getHeight();
1909+ doc->setViewBox(Geom::Rect::from_xywh(0, 0, width.value(doc_unit), height.value(doc_unit)));
1910+
1911+ // TODO: Fix bug in nodes tool instead of switching away from it
1912+ if (tools_active(getDesktop()) == TOOLS_NODES) {
1913+ tools_switch(getDesktop(), TOOLS_SELECT);
1914+ }
1915+
1916+ // Scale and translate objects
1917+ gdouble scale = Inkscape::Util::Quantity::convert(1, old_doc_unit, doc_unit);
1918+ ShapeEditor::blockSetItem(true);
1919+ doc->getRoot()->scaleChildItemsRec(Geom::Scale(scale), Geom::Point(0, doc->getHeight().value("px")));
1920+ ShapeEditor::blockSetItem(false);
1921+
1922+ doc->setModifiedSinceSave();
1923+
1924+ DocumentUndo::done(doc, SP_VERB_NONE, _("Changed document unit"));
1925+}
1926
1927 } // namespace Dialog
1928 } // namespace UI
1929
1930=== modified file 'src/ui/dialog/document-properties.h'
1931--- src/ui/dialog/document-properties.h 2013-03-12 12:20:04 +0000
1932+++ src/ui/dialog/document-properties.h 2013-09-20 17:05:49 +0000
1933@@ -216,6 +216,9 @@
1934 // callback methods for buttons on grids page.
1935 void onNewGrid();
1936 void onRemoveGrid();
1937+
1938+ // callback for document unit change
1939+ void onDocUnitChange();
1940 };
1941
1942 } // namespace Dialog
1943
1944=== modified file 'src/ui/dialog/export.cpp'
1945--- src/ui/dialog/export.cpp 2013-09-01 16:46:33 +0000
1946+++ src/ui/dialog/export.cpp 2013-09-20 17:05:49 +0000
1947@@ -762,7 +762,7 @@
1948 }
1949 case SELECTION_PAGE:
1950 bbox = Geom::Rect(Geom::Point(0.0, 0.0),
1951- Geom::Point(doc->getWidth(), doc->getHeight()));
1952+ Geom::Point(doc->getWidth().value("px"), doc->getHeight().value("px")));
1953
1954 // std::cout << "Using selection: PAGE" << std::endl;
1955 key = SELECTION_PAGE;
1956@@ -1475,8 +1475,8 @@
1957 doc = sp_desktop_document (SP_ACTIVE_DESKTOP);
1958
1959 Geom::Point x(0.0, 0.0);
1960- Geom::Point y(doc->getWidth(),
1961- doc->getHeight());
1962+ Geom::Point y(doc->getWidth().value("px"),
1963+ doc->getHeight().value("px"));
1964 Geom::Rect bbox(x, y);
1965
1966 if (bbox_equal(bbox,current_bbox)) {
1967
1968=== modified file 'src/ui/dialog/print.cpp'
1969--- src/ui/dialog/print.cpp 2013-07-31 22:33:03 +0000
1970+++ src/ui/dialog/print.cpp 2013-09-20 17:05:49 +0000
1971@@ -49,8 +49,8 @@
1972
1973 if (junk->_tab->as_bitmap()) {
1974 // Render as exported PNG
1975- gdouble width = (junk->_doc)->getWidth();
1976- gdouble height = (junk->_doc)->getHeight();
1977+ gdouble width = (junk->_doc)->getWidth().value("px");
1978+ gdouble height = (junk->_doc)->getHeight().value("px");
1979 gdouble dpi = junk->_tab->bitmap_dpi();
1980 std::string tmp_png;
1981 std::string tmp_base = "inkscape-print-png-XXXXXX";
1982@@ -72,8 +72,8 @@
1983
1984 sp_export_png_file(junk->_doc, tmp_png.c_str(), 0.0, 0.0,
1985 width, height,
1986- (unsigned long)(width * dpi / Inkscape::Util::Quantity::convert(1, "in", "px")),
1987- (unsigned long)(height * dpi / Inkscape::Util::Quantity::convert(1, "in", "px")),
1988+ (unsigned long)(Inkscape::Util::Quantity::convert(width, "px", "in") * dpi),
1989+ (unsigned long)(Inkscape::Util::Quantity::convert(height, "px", "in") * dpi),
1990 dpi, dpi, bgcolor, NULL, NULL, true, NULL);
1991
1992 // This doesn't seem to work:
1993@@ -195,8 +195,8 @@
1994 // set up paper size to match the document size
1995 gtk_print_operation_set_unit (_printop, GTK_UNIT_POINTS);
1996 GtkPageSetup *page_setup = gtk_page_setup_new();
1997- gdouble doc_width = _doc->getWidth() * Inkscape::Util::Quantity::convert(1, "px", "pt");
1998- gdouble doc_height = _doc->getHeight() * Inkscape::Util::Quantity::convert(1, "px", "pt");
1999+ gdouble doc_width = _doc->getWidth().value("pt");
2000+ gdouble doc_height = _doc->getHeight().value("pt");
2001 GtkPaperSize *paper_size;
2002 if (doc_width > doc_height) {
2003 gtk_page_setup_set_orientation (page_setup, GTK_PAGE_ORIENTATION_LANDSCAPE);
2004
2005=== modified file 'src/ui/dialog/text-edit.cpp'
2006--- src/ui/dialog/text-edit.cpp 2013-07-31 22:33:03 +0000
2007+++ src/ui/dialog/text-edit.cpp 2013-09-20 17:05:49 +0000
2008@@ -401,7 +401,7 @@
2009
2010 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
2011 int unit = prefs->getInt("/options/font/unitType", SP_CSS_UNIT_PT);
2012- double pt_size = sp_style_css_size_units_to_px(sp_font_selector_get_size(fsel), unit) * Inkscape::Util::Quantity::convert(1, "px", "pt");
2013+ double pt_size = Inkscape::Util::Quantity::convert(sp_style_css_size_units_to_px(sp_font_selector_get_size(fsel), unit), "px", "pt");
2014
2015 // Pango font size is in 1024ths of a point
2016 // C++11: Glib::ustring size = std::to_string( pt_size * PANGO_SCALE );
2017
2018=== modified file 'src/ui/widget/page-sizer.cpp'
2019--- src/ui/widget/page-sizer.cpp 2013-08-06 18:44:23 +0000
2020+++ src/ui/widget/page-sizer.cpp 2013-09-20 17:05:49 +0000
2021@@ -442,6 +442,7 @@
2022 _portrait_connection = _portraitButton.signal_toggled().connect (sigc::mem_fun (*this, &PageSizer::on_portrait));
2023 _changedw_connection = _dimensionWidth.signal_value_changed().connect (sigc::mem_fun (*this, &PageSizer::on_value_changed));
2024 _changedh_connection = _dimensionHeight.signal_value_changed().connect (sigc::mem_fun (*this, &PageSizer::on_value_changed));
2025+ _changedu_connection = _dimensionUnits.getUnitMenu()->signal_changed().connect (sigc::mem_fun (*this, &PageSizer::on_units_changed));
2026 _fitPageButton.signal_clicked().connect(sigc::mem_fun(*this, &PageSizer::fire_fit_canvas_to_selection_or_drawing));
2027
2028 show_all_children();
2029@@ -454,11 +455,11 @@
2030 * 'changeList' is true, then adjust the paperSizeList to show the closest
2031 * standard page size.
2032 *
2033- * \param w, h given in px
2034+ * \param w, h
2035 * \param changeList whether to modify the paper size list
2036 */
2037 void
2038-PageSizer::setDim (double w, double h, bool changeList)
2039+PageSizer::setDim (Inkscape::Util::Quantity w, Inkscape::Util::Quantity h, bool changeList)
2040 {
2041 static bool _called = false;
2042 if (_called) {
2043@@ -475,12 +476,12 @@
2044
2045 if (SP_ACTIVE_DESKTOP && !_widgetRegistry->isUpdating()) {
2046 SPDocument *doc = sp_desktop_document(SP_ACTIVE_DESKTOP);
2047- double const old_height = doc->getHeight();
2048- doc->setWidth (Inkscape::Util::Quantity(w, "px"));
2049- doc->setHeight (Inkscape::Util::Quantity(h, "px"));
2050+ Inkscape::Util::Quantity const old_height = doc->getHeight();
2051+ doc->setWidth (w);
2052+ doc->setHeight (h);
2053 // The origin for the user is in the lower left corner; this point should remain stationary when
2054 // changing the page size. The SVG's origin however is in the upper left corner, so we must compensate for this
2055- Geom::Translate const vert_offset(Geom::Point(0, (old_height - h)));
2056+ Geom::Translate const vert_offset(Geom::Point(0, (old_height.value("px") - h.value("px"))));
2057 doc->getRoot()->translateChildItems(vert_offset);
2058 DocumentUndo::done(doc, SP_VERB_NONE, _("Set page size"));
2059 }
2060@@ -503,9 +504,10 @@
2061 _paperSizeListSelection->select(row);
2062 }
2063
2064- Unit const& unit = _dimensionUnits.getUnit();
2065- _dimensionWidth.setValue (w / unit.factor);
2066- _dimensionHeight.setValue (h / unit.factor);
2067+ _dimensionWidth.setUnit(w.unit->abbr);
2068+ _dimensionWidth.setValue (w.quantity);
2069+ _dimensionHeight.setUnit(h.unit->abbr);
2070+ _dimensionHeight.setValue (h.quantity);
2071
2072 _paper_size_list_connection.unblock();
2073 _landscape_connection.unblock();
2074@@ -547,12 +549,12 @@
2075 * paperSizeListStore->children().end() if no such paper exists.
2076 */
2077 Gtk::ListStore::iterator
2078-PageSizer::find_paper_size (double w, double h) const
2079+PageSizer::find_paper_size (Inkscape::Util::Quantity w, Inkscape::Util::Quantity h) const
2080 {
2081- double smaller = w;
2082- double larger = h;
2083+ double smaller = w.quantity;
2084+ double larger = h.quantity;
2085 if ( h < w ) {
2086- smaller = h; larger = w;
2087+ smaller = h.quantity; larger = w.quantity;
2088 }
2089
2090 g_return_val_if_fail(smaller <= larger, _paperSizeListStore->children().end());
2091@@ -562,8 +564,8 @@
2092 iter != _paperSizeTable.end() ; ++iter) {
2093 PaperSize paper = iter->second;
2094 Inkscape::Util::Unit const &i_unit = paper.unit;
2095- double smallX = Inkscape::Util::Quantity::convert(paper.smaller, i_unit, "px");
2096- double largeX = Inkscape::Util::Quantity::convert(paper.larger, i_unit, "px");
2097+ double smallX = Inkscape::Util::Quantity::convert(paper.smaller, i_unit, *w.unit);
2098+ double largeX = Inkscape::Util::Quantity::convert(paper.larger, i_unit, *w.unit);
2099
2100 g_return_val_if_fail(smallX <= largeX, _paperSizeListStore->children().end());
2101
2102@@ -643,8 +645,8 @@
2103 return;
2104 }
2105 PaperSize paper = piter->second;
2106- double w = paper.smaller;
2107- double h = paper.larger;
2108+ Inkscape::Util::Quantity w = Inkscape::Util::Quantity(paper.smaller, paper.unit);
2109+ Inkscape::Util::Quantity h = Inkscape::Util::Quantity(paper.larger, paper.unit);
2110
2111 if (std::find(lscape_papers.begin(), lscape_papers.end(), paper.name.c_str()) != lscape_papers.end()) {
2112 // enforce landscape mode if this is desired for the given page format
2113@@ -654,9 +656,6 @@
2114 _landscape = _landscapeButton.get_active();
2115 }
2116
2117- w = Inkscape::Util::Quantity::convert(w, paper.unit, "px");
2118- h = Inkscape::Util::Quantity::convert(h, paper.unit, "px");
2119-
2120 if (_landscape)
2121 setDim (h, w, false);
2122 else
2123@@ -673,8 +672,8 @@
2124 {
2125 if (!_portraitButton.get_active())
2126 return;
2127- double w = _dimensionWidth.getValue ("px");
2128- double h = _dimensionHeight.getValue ("px");
2129+ Inkscape::Util::Quantity w = Inkscape::Util::Quantity(_dimensionWidth.getValue(""), _dimensionWidth.getUnit());
2130+ Inkscape::Util::Quantity h = Inkscape::Util::Quantity(_dimensionHeight.getValue(""), _dimensionHeight.getUnit());
2131 if (h < w) {
2132 setDim (h, w);
2133 }
2134@@ -689,8 +688,8 @@
2135 {
2136 if (!_landscapeButton.get_active())
2137 return;
2138- double w = _dimensionWidth.getValue ("px");
2139- double h = _dimensionHeight.getValue ("px");
2140+ Inkscape::Util::Quantity w = Inkscape::Util::Quantity(_dimensionWidth.getValue(""), _dimensionWidth.getUnit());
2141+ Inkscape::Util::Quantity h = Inkscape::Util::Quantity(_dimensionHeight.getValue(""), _dimensionHeight.getUnit());
2142 if (w < h) {
2143 setDim (h, w);
2144 }
2145@@ -703,11 +702,18 @@
2146 PageSizer::on_value_changed()
2147 {
2148 if (_widgetRegistry->isUpdating()) return;
2149-
2150- setDim (_dimensionWidth.getValue("px"),
2151- _dimensionHeight.getValue("px"));
2152-}
2153-
2154+ if (_unit != _dimensionUnits.getUnit().abbr) return;
2155+ setDim (Inkscape::Util::Quantity(_dimensionWidth.getValue(""), _dimensionUnits.getUnit()),
2156+ Inkscape::Util::Quantity(_dimensionHeight.getValue(""), _dimensionUnits.getUnit()));
2157+}
2158+void
2159+PageSizer::on_units_changed()
2160+{
2161+ if (_widgetRegistry->isUpdating()) return;
2162+ _unit = _dimensionUnits.getUnit().abbr;
2163+ setDim (Inkscape::Util::Quantity(_dimensionWidth.getValue(""), _dimensionUnits.getUnit()),
2164+ Inkscape::Util::Quantity(_dimensionHeight.getValue(""), _dimensionUnits.getUnit()));
2165+}
2166
2167 } // namespace Widget
2168 } // namespace UI
2169
2170=== modified file 'src/ui/widget/page-sizer.h'
2171--- src/ui/widget/page-sizer.h 2013-08-04 22:01:18 +0000
2172+++ src/ui/widget/page-sizer.h 2013-09-20 17:05:49 +0000
2173@@ -161,7 +161,7 @@
2174 * Set the page size to the given dimensions. If 'changeList' is
2175 * true, then reset the paper size list to the closest match
2176 */
2177- void setDim (double w, double h, bool changeList=true);
2178+ void setDim (Inkscape::Util::Quantity w, Inkscape::Util::Quantity h, bool changeList=true);
2179
2180 /**
2181 * Updates the scalar widgets for the fit margins. (Just changes the value
2182@@ -179,7 +179,7 @@
2183 /**
2184 * Find the closest standard paper size in the table, to the
2185 */
2186- Gtk::ListStore::iterator find_paper_size (double w, double h) const;
2187+ Gtk::ListStore::iterator find_paper_size (Inkscape::Util::Quantity w, Inkscape::Util::Quantity h) const;
2188
2189 void fire_fit_canvas_to_selection_or_drawing();
2190
2191@@ -252,13 +252,17 @@
2192
2193 //callback
2194 void on_value_changed();
2195+ void on_units_changed();
2196 sigc::connection _changedw_connection;
2197 sigc::connection _changedh_connection;
2198+ sigc::connection _changedu_connection;
2199
2200 Registry *_widgetRegistry;
2201
2202 //### state - whether we are currently landscape or portrait
2203 bool _landscape;
2204+
2205+ Glib::ustring _unit;
2206
2207 };
2208
2209
2210=== modified file 'src/ui/widget/spinbutton.cpp'
2211--- src/ui/widget/spinbutton.cpp 2012-07-05 21:39:08 +0000
2212+++ src/ui/widget/spinbutton.cpp 2013-09-20 17:05:49 +0000
2213@@ -14,6 +14,7 @@
2214 #include "spinbutton.h"
2215
2216 #include "unit-menu.h"
2217+#include "unit-tracker.h"
2218 #include "util/expression-evaluator.h"
2219 #include "event-context.h"
2220
2221@@ -32,16 +33,23 @@
2222 int SpinButton::on_input(double* newvalue)
2223 {
2224 try {
2225- Inkscape::Util::GimpEevlQuantity result;
2226- if (_unit_menu) {
2227- Unit unit = _unit_menu->getUnit();
2228- result = Inkscape::Util::gimp_eevl_evaluate (get_text().c_str(), &unit);
2229+ Inkscape::Util::EvaluatorQuantity result;
2230+ if (_unit_menu || _unit_tracker) {
2231+ Unit unit;
2232+ if (_unit_menu) {
2233+ unit = _unit_menu->getUnit();
2234+ } else {
2235+ unit = _unit_tracker->getActiveUnit();
2236+ }
2237+ Inkscape::Util::ExpressionEvaluator eval = Inkscape::Util::ExpressionEvaluator(get_text().c_str(), &unit);
2238+ result = eval.evaluate();
2239 // check if output dimension corresponds to input unit
2240 if (result.dimension != (unit.isAbsolute() ? 1 : 0) ) {
2241 throw Inkscape::Util::EvaluatorException("Input dimensions do not match with parameter dimensions.","");
2242 }
2243 } else {
2244- result = Inkscape::Util::gimp_eevl_evaluate (get_text().c_str(), NULL);
2245+ Inkscape::Util::ExpressionEvaluator eval = Inkscape::Util::ExpressionEvaluator(get_text().c_str(), NULL);
2246+ result = eval.evaluate();
2247 }
2248
2249 *newvalue = result.value;
2250
2251=== modified file 'src/ui/widget/spinbutton.h'
2252--- src/ui/widget/spinbutton.h 2013-06-07 03:18:19 +0000
2253+++ src/ui/widget/spinbutton.h 2013-09-20 17:05:49 +0000
2254@@ -25,6 +25,7 @@
2255 namespace Widget {
2256
2257 class UnitMenu;
2258+class UnitTracker;
2259
2260 /**
2261 * SpinButton widget, that allows entry of simple math expressions (also units, when linked with UnitMenu),
2262@@ -50,14 +51,18 @@
2263 _unit_menu(NULL)
2264 {
2265 connect_signals();
2266+ _unit_tracker = NULL;
2267 };
2268
2269 virtual ~SpinButton() {};
2270
2271 void setUnitMenu(UnitMenu* unit_menu) { _unit_menu = unit_menu; };
2272+
2273+ void addUnitTracker(UnitTracker* ut) { _unit_tracker = ut; };
2274
2275 protected:
2276 UnitMenu *_unit_menu; /// Linked unit menu for unit conversion in entered expressions.
2277+ UnitTracker *_unit_tracker; // Linked unit tracker for unit conversion in entered expressions.
2278
2279 void connect_signals();
2280
2281
2282=== modified file 'src/util/expression-evaluator.cpp'
2283--- src/util/expression-evaluator.cpp 2013-08-04 22:01:18 +0000
2284+++ src/util/expression-evaluator.cpp 2013-09-20 17:05:49 +0000
2285@@ -6,6 +6,7 @@
2286 * Copyright (C) 2008 Martin Nordholts <martinn@svn.gnome.org>
2287 * Modified for Inkscape by Johan Engelen
2288 * Copyright (C) 2011 Johan Engelen
2289+ * Copyright (C) 2013 Matthew Petroff
2290 *
2291 * This library is free software: you can redistribute it and/or
2292 * modify it under the terms of the GNU Lesser General Public
2293@@ -27,6 +28,7 @@
2294 #include "util/expression-evaluator.h"
2295 #include "util/units.h"
2296
2297+#include <math.h>
2298 #include <string.h>
2299
2300 using Inkscape::Util::unit_table;
2301@@ -34,495 +36,353 @@
2302 namespace Inkscape {
2303 namespace Util {
2304
2305-enum
2306-{
2307- GIMP_EEVL_TOKEN_NUM = 30000,
2308- GIMP_EEVL_TOKEN_IDENTIFIER = 30001,
2309-
2310- GIMP_EEVL_TOKEN_ANY = 40000,
2311-
2312- GIMP_EEVL_TOKEN_END = 50000
2313-};
2314-
2315-typedef int GimpEevlTokenType;
2316-
2317-
2318-typedef struct
2319-{
2320- GimpEevlTokenType type;
2321-
2322- union
2323- {
2324- gdouble fl;
2325-
2326- struct
2327- {
2328- const gchar *c;
2329- gint size;
2330- };
2331-
2332- } value;
2333-
2334-} GimpEevlToken;
2335-
2336-typedef struct
2337-{
2338- const gchar *string;
2339- GimpEevlUnitResolverProc unit_resolver_proc;
2340- Unit *unit;
2341-
2342- GimpEevlToken current_token;
2343- const gchar *start_of_current_token;
2344-} GimpEevl;
2345-
2346-/** Unit Resolver...
2347- */
2348-static bool unitresolverproc (const gchar* identifier, GimpEevlQuantity *result, Unit* unit)
2349-{
2350- if (!unit) {
2351- result->value = 1;
2352- result->dimension = 1;
2353- return true;
2354- }else if (!identifier) {
2355- result->value = 1;
2356- result->dimension = unit->isAbsolute() ? 1 : 0;
2357- return true;
2358- } else if (unit_table.hasUnit(identifier)) {
2359- Unit identifier_unit = unit_table.getUnit(identifier);
2360-
2361- // Catch the case of zero or negative unit factors (error!)
2362- if (identifier_unit.factor < 0.0000001) {
2363- return false;
2364- }
2365-
2366- result->value = unit->factor / identifier_unit.factor;
2367- result->dimension = identifier_unit.isAbsolute() ? 1 : 0;
2368- return true;
2369- } else {
2370- return false;
2371- }
2372-}
2373-
2374-static void gimp_eevl_init (GimpEevl *eva,
2375- const gchar *string,
2376- GimpEevlUnitResolverProc unit_resolver_proc,
2377- Unit *unit);
2378-static GimpEevlQuantity gimp_eevl_complete (GimpEevl *eva);
2379-static GimpEevlQuantity gimp_eevl_expression (GimpEevl *eva);
2380-static GimpEevlQuantity gimp_eevl_term (GimpEevl *eva);
2381-static GimpEevlQuantity gimp_eevl_signed_factor (GimpEevl *eva);
2382-static GimpEevlQuantity gimp_eevl_factor (GimpEevl *eva);
2383-static gboolean gimp_eevl_accept (GimpEevl *eva,
2384- GimpEevlTokenType token_type,
2385- GimpEevlToken *consumed_token);
2386-static void gimp_eevl_lex (GimpEevl *eva);
2387-static void gimp_eevl_lex_accept_count (GimpEevl *eva,
2388- gint count,
2389- GimpEevlTokenType token_type);
2390-static void gimp_eevl_lex_accept_to (GimpEevl *eva,
2391- gchar *to,
2392- GimpEevlTokenType token_type);
2393-static void gimp_eevl_move_past_whitespace (GimpEevl *eva);
2394-static gboolean gimp_eevl_unit_identifier_start (gunichar c);
2395-static gboolean gimp_eevl_unit_identifier_continue (gunichar c);
2396-static gint gimp_eevl_unit_identifier_size (const gchar *s,
2397- gint start);
2398-static void gimp_eevl_expect (GimpEevl *eva,
2399- GimpEevlTokenType token_type,
2400- GimpEevlToken *value);
2401-static void gimp_eevl_error (GimpEevl *eva,
2402- const char *msg);
2403-
2404+EvaluatorQuantity::EvaluatorQuantity(double value, unsigned int dimension) :
2405+ value(value),
2406+ dimension(dimension)
2407+{
2408+}
2409+
2410+EvaluatorToken::EvaluatorToken()
2411+{
2412+ type = 0;
2413+ value.fl = 0;
2414+}
2415+
2416+ExpressionEvaluator::ExpressionEvaluator(const char *string, Unit *unit) :
2417+ string(string),
2418+ unit(unit)
2419+{
2420+ current_token.type = TOKEN_END;
2421+
2422+ // Preload symbol
2423+ parseNextToken();
2424+}
2425
2426 /**
2427 * Evaluates the given arithmetic expression, along with an optional dimension
2428 * analysis, and basic unit conversions.
2429 *
2430- * @param string The NULL-terminated string to be evaluated.
2431- * @param unit_resolver_proc Unit resolver callback.
2432- *
2433 * All units conversions factors are relative to some implicit
2434- * base-unit (which in GIMP is inches). This is also the unit of the
2435- * returned value.
2436+ * base-unit. This is also the unit of the returned value.
2437 *
2438- * Returns: A #GimpEevlQuantity with a value given in the base unit along with
2439- * the order of the dimension (i.e. if the base unit is inches, a dimension
2440- * order of two menas in^2).
2441+ * Returns: An EvaluatorQuantity with a value given in the base unit along with
2442+ * the order of the dimension (e.g. if the base unit is inches, a dimension
2443+ * order of two means in^2).
2444 *
2445 * @return Result of evaluation.
2446 * @throws Inkscape::Util::EvaluatorException There was a parse error.
2447 **/
2448-GimpEevlQuantity
2449-gimp_eevl_evaluate (const gchar* string, Unit* unit)
2450+EvaluatorQuantity ExpressionEvaluator::evaluate()
2451 {
2452- if (! g_utf8_validate (string, -1, NULL)) {
2453+ if (!g_utf8_validate(string, -1, NULL)) {
2454 throw EvaluatorException("Invalid UTF8 string", NULL);
2455 }
2456-
2457- GimpEevl eva;
2458- gimp_eevl_init (&eva, string, unitresolverproc, unit);
2459-
2460- return gimp_eevl_complete(&eva);
2461-}
2462-
2463-static void
2464-gimp_eevl_init (GimpEevl *eva,
2465- const gchar *string,
2466- GimpEevlUnitResolverProc unit_resolver_proc,
2467- Unit *unit)
2468-{
2469- eva->string = string;
2470- eva->unit_resolver_proc = unit_resolver_proc;
2471- eva->unit = unit;
2472-
2473- eva->current_token.type = GIMP_EEVL_TOKEN_END;
2474-
2475- /* Preload symbol... */
2476- gimp_eevl_lex (eva);
2477-}
2478-
2479-static GimpEevlQuantity
2480-gimp_eevl_complete (GimpEevl *eva)
2481-{
2482- GimpEevlQuantity result = {0, 0};
2483- GimpEevlQuantity default_unit_factor;
2484-
2485- /* Empty expression evaluates to 0 */
2486- if (gimp_eevl_accept (eva, GIMP_EEVL_TOKEN_END, NULL))
2487- return result;
2488-
2489- result = gimp_eevl_expression (eva);
2490-
2491- /* There should be nothing left to parse by now */
2492- gimp_eevl_expect (eva, GIMP_EEVL_TOKEN_END, 0);
2493-
2494- eva->unit_resolver_proc (NULL, &default_unit_factor, eva->unit);
2495-
2496- /* Entire expression is dimensionless, apply default unit if
2497- * applicable
2498- */
2499- if (result.dimension == 0 && default_unit_factor.dimension != 0)
2500- {
2501- result.value /= default_unit_factor.value;
2502- result.dimension = default_unit_factor.dimension;
2503- }
2504- return result;
2505-}
2506-
2507-static GimpEevlQuantity
2508-gimp_eevl_expression (GimpEevl *eva)
2509-{
2510- gboolean subtract;
2511- GimpEevlQuantity evaluated_terms;
2512-
2513- evaluated_terms = gimp_eevl_term (eva);
2514-
2515- /* continue evaluating terms, chained with + or -. */
2516- for (subtract = FALSE;
2517- gimp_eevl_accept (eva, '+', NULL) ||
2518- (subtract = gimp_eevl_accept (eva, '-', NULL));
2519- subtract = FALSE)
2520- {
2521- GimpEevlQuantity new_term = gimp_eevl_term (eva);
2522-
2523- /* If dimensions missmatch, attempt default unit assignent */
2524- if (new_term.dimension != evaluated_terms.dimension)
2525- {
2526- GimpEevlQuantity default_unit_factor;
2527-
2528- eva->unit_resolver_proc (NULL,
2529- &default_unit_factor,
2530- eva->unit);
2531-
2532- if (new_term.dimension == 0 &&
2533- evaluated_terms.dimension == default_unit_factor.dimension)
2534- {
2535- new_term.value /= default_unit_factor.value;
2536- new_term.dimension = default_unit_factor.dimension;
2537- }
2538- else if (evaluated_terms.dimension == 0 &&
2539- new_term.dimension == default_unit_factor.dimension)
2540- {
2541- evaluated_terms.value /= default_unit_factor.value;
2542- evaluated_terms.dimension = default_unit_factor.dimension;
2543- }
2544- else
2545- {
2546- gimp_eevl_error (eva, "Dimension missmatch during addition");
2547- }
2548- }
2549-
2550- evaluated_terms.value += (subtract ? -new_term.value : new_term.value);
2551- }
2552-
2553- return evaluated_terms;
2554-}
2555-
2556-static GimpEevlQuantity
2557-gimp_eevl_term (GimpEevl *eva)
2558-{
2559- gboolean division;
2560- GimpEevlQuantity evaluated_signed_factors;
2561-
2562- evaluated_signed_factors = gimp_eevl_signed_factor (eva);
2563-
2564- for (division = FALSE;
2565- gimp_eevl_accept (eva, '*', NULL) ||
2566- (division = gimp_eevl_accept (eva, '/', NULL));
2567- division = FALSE)
2568- {
2569- GimpEevlQuantity new_signed_factor = gimp_eevl_signed_factor (eva);
2570-
2571- if (division)
2572- {
2573- evaluated_signed_factors.value /= new_signed_factor.value;
2574- evaluated_signed_factors.dimension -= new_signed_factor.dimension;
2575-
2576- }
2577- else
2578- {
2579- evaluated_signed_factors.value *= new_signed_factor.value;
2580- evaluated_signed_factors.dimension += new_signed_factor.dimension;
2581- }
2582- }
2583-
2584- return evaluated_signed_factors;
2585-}
2586-
2587-static GimpEevlQuantity
2588-gimp_eevl_signed_factor (GimpEevl *eva)
2589-{
2590- GimpEevlQuantity result;
2591- gboolean negate = FALSE;
2592-
2593- if (! gimp_eevl_accept (eva, '+', NULL))
2594- negate = gimp_eevl_accept (eva, '-', NULL);
2595-
2596- result = gimp_eevl_factor (eva);
2597-
2598- if (negate) result.value = -result.value;
2599-
2600- return result;
2601-}
2602-
2603-static GimpEevlQuantity
2604-gimp_eevl_factor (GimpEevl *eva)
2605-{
2606- GimpEevlQuantity evaluated_factor = { 0, 0 };
2607- GimpEevlToken consumed_token;
2608-
2609- if (gimp_eevl_accept (eva,
2610- GIMP_EEVL_TOKEN_NUM,
2611- &consumed_token))
2612- {
2613- evaluated_factor.value = consumed_token.value.fl;
2614- }
2615- else if (gimp_eevl_accept (eva, '(', NULL))
2616- {
2617- evaluated_factor = gimp_eevl_expression (eva);
2618- gimp_eevl_expect (eva, ')', 0);
2619- }
2620- else
2621- {
2622- gimp_eevl_error (eva, "Expected number or '('");
2623- }
2624-
2625- if (eva->current_token.type == GIMP_EEVL_TOKEN_IDENTIFIER)
2626- {
2627- gchar *identifier;
2628- GimpEevlQuantity result;
2629-
2630- gimp_eevl_accept (eva,
2631- GIMP_EEVL_TOKEN_ANY,
2632- &consumed_token);
2633-
2634- identifier = g_newa (gchar, consumed_token.value.size + 1);
2635-
2636- strncpy (identifier, consumed_token.value.c, consumed_token.value.size);
2637- identifier[consumed_token.value.size] = '\0';
2638-
2639- if (eva->unit_resolver_proc (identifier,
2640- &result,
2641- eva->unit))
2642- {
2643- evaluated_factor.value /= result.value;
2644- evaluated_factor.dimension += result.dimension;
2645- }
2646- else
2647- {
2648- gimp_eevl_error (eva, "Unit was not resolved");
2649- }
2650- }
2651-
2652- return evaluated_factor;
2653-}
2654-
2655-static gboolean
2656-gimp_eevl_accept (GimpEevl *eva,
2657- GimpEevlTokenType token_type,
2658- GimpEevlToken *consumed_token)
2659-{
2660- gboolean existed = FALSE;
2661-
2662- if (token_type == eva->current_token.type ||
2663- token_type == GIMP_EEVL_TOKEN_ANY)
2664- {
2665- existed = TRUE;
2666-
2667- if (consumed_token)
2668- *consumed_token = eva->current_token;
2669-
2670- /* Parse next token */
2671- gimp_eevl_lex (eva);
2672- }
2673-
2674- return existed;
2675-}
2676-
2677-static void
2678-gimp_eevl_lex (GimpEevl *eva)
2679-{
2680- const gchar *s;
2681-
2682- gimp_eevl_move_past_whitespace (eva);
2683- s = eva->string;
2684- eva->start_of_current_token = s;
2685-
2686- if (! s || s[0] == '\0')
2687- {
2688- /* We're all done */
2689- eva->current_token.type = GIMP_EEVL_TOKEN_END;
2690- }
2691- else if (s[0] == '+' || s[0] == '-')
2692- {
2693- /* Snatch these before the g_strtod() does, othewise they might
2694- * be used in a numeric conversion.
2695- */
2696- gimp_eevl_lex_accept_count (eva, 1, s[0]);
2697- }
2698- else
2699-
2700- {
2701- /* Attempt to parse a numeric value */
2702- gchar *endptr = NULL;
2703- gdouble value = g_strtod (s, &endptr);
2704-
2705- if (endptr && endptr != s)
2706- {
2707- /* A numeric could be parsed, use it */
2708- eva->current_token.value.fl = value;
2709-
2710- gimp_eevl_lex_accept_to (eva, endptr, GIMP_EEVL_TOKEN_NUM);
2711- }
2712- else if (gimp_eevl_unit_identifier_start (s[0]))
2713- {
2714- /* Unit identifier */
2715- eva->current_token.value.c = s;
2716- eva->current_token.value.size = gimp_eevl_unit_identifier_size (s, 0);
2717-
2718- gimp_eevl_lex_accept_count (eva,
2719- eva->current_token.value.size,
2720- GIMP_EEVL_TOKEN_IDENTIFIER);
2721- }
2722- else
2723- {
2724- /* Everything else is a single character token */
2725- gimp_eevl_lex_accept_count (eva, 1, s[0]);
2726- }
2727- }
2728-}
2729-
2730-static void
2731-gimp_eevl_lex_accept_count (GimpEevl *eva,
2732- gint count,
2733- GimpEevlTokenType token_type)
2734-{
2735- eva->current_token.type = token_type;
2736- eva->string += count;
2737-}
2738-
2739-static void
2740-gimp_eevl_lex_accept_to (GimpEevl *eva,
2741- gchar *to,
2742- GimpEevlTokenType token_type)
2743-{
2744- eva->current_token.type = token_type;
2745- eva->string = to;
2746-}
2747-
2748-static void
2749-gimp_eevl_move_past_whitespace (GimpEevl *eva)
2750-{
2751- if (! eva->string)
2752- return;
2753-
2754- while (g_ascii_isspace (*eva->string))
2755- eva->string++;
2756-}
2757-
2758-static gboolean
2759-gimp_eevl_unit_identifier_start (gunichar c)
2760-{
2761- return (g_unichar_isalpha (c) ||
2762- c == (gunichar) '%' ||
2763- c == (gunichar) '\'');
2764-}
2765-
2766-static gboolean
2767-gimp_eevl_unit_identifier_continue (gunichar c)
2768-{
2769- return (gimp_eevl_unit_identifier_start (c) ||
2770- g_unichar_isdigit (c));
2771+
2772+ EvaluatorQuantity result = EvaluatorQuantity();
2773+ EvaluatorQuantity default_unit_factor;
2774+
2775+ // Empty expression evaluates to 0
2776+ if (acceptToken(TOKEN_END, NULL)) {
2777+ return result;
2778+ }
2779+
2780+ result = evaluateExpression();
2781+
2782+ // There should be nothing left to parse by now
2783+ isExpected(TOKEN_END, 0);
2784+
2785+ resolveUnit(NULL, &default_unit_factor, unit);
2786+
2787+ // Entire expression is dimensionless, apply default unit if applicable
2788+ if ( result.dimension == 0 && default_unit_factor.dimension != 0 ) {
2789+ result.value /= default_unit_factor.value;
2790+ result.dimension = default_unit_factor.dimension;
2791+ }
2792+ return result;
2793+}
2794+
2795+EvaluatorQuantity ExpressionEvaluator::evaluateExpression()
2796+{
2797+ bool subtract;
2798+ EvaluatorQuantity evaluated_terms;
2799+
2800+ evaluated_terms = evaluateTerm();
2801+
2802+ // Continue evaluating terms, chained with + or -.
2803+ for (subtract = FALSE;
2804+ acceptToken('+', NULL) || (subtract = acceptToken('-', NULL));
2805+ subtract = FALSE)
2806+ {
2807+ EvaluatorQuantity new_term = evaluateTerm();
2808+
2809+ // If dimensions mismatch, attempt default unit assignent
2810+ if ( new_term.dimension != evaluated_terms.dimension ) {
2811+ EvaluatorQuantity default_unit_factor;
2812+
2813+ resolveUnit(NULL, &default_unit_factor, unit);
2814+
2815+ if ( new_term.dimension == 0
2816+ && evaluated_terms.dimension == default_unit_factor.dimension )
2817+ {
2818+ new_term.value /= default_unit_factor.value;
2819+ new_term.dimension = default_unit_factor.dimension;
2820+ } else if ( evaluated_terms.dimension == 0
2821+ && new_term.dimension == default_unit_factor.dimension )
2822+ {
2823+ evaluated_terms.value /= default_unit_factor.value;
2824+ evaluated_terms.dimension = default_unit_factor.dimension;
2825+ } else {
2826+ throwError("Dimension mismatch during addition");
2827+ }
2828+ }
2829+
2830+ evaluated_terms.value += (subtract ? -new_term.value : new_term.value);
2831+ }
2832+
2833+ return evaluated_terms;
2834+}
2835+
2836+EvaluatorQuantity ExpressionEvaluator::evaluateTerm()
2837+{
2838+ bool division;
2839+ EvaluatorQuantity evaluated_exp_terms = evaluateExpTerm();
2840+
2841+ for ( division = false;
2842+ acceptToken('*', NULL) || (division = acceptToken('/', NULL));
2843+ division = false )
2844+ {
2845+ EvaluatorQuantity new_exp_term = evaluateExpTerm();
2846+
2847+ if (division) {
2848+ evaluated_exp_terms.value /= new_exp_term.value;
2849+ evaluated_exp_terms.dimension -= new_exp_term.dimension;
2850+ } else {
2851+ evaluated_exp_terms.value *= new_exp_term.value;
2852+ evaluated_exp_terms.dimension += new_exp_term.dimension;
2853+ }
2854+ }
2855+
2856+ return evaluated_exp_terms;
2857+}
2858+
2859+EvaluatorQuantity ExpressionEvaluator::evaluateExpTerm()
2860+{
2861+ EvaluatorQuantity evaluated_signed_factors = evaluateSignedFactor();
2862+
2863+ while(acceptToken('^', NULL)) {
2864+ EvaluatorQuantity new_signed_factor = evaluateSignedFactor();
2865+
2866+ if (new_signed_factor.dimension == 0) {
2867+ evaluated_signed_factors.value = pow(evaluated_signed_factors.value,
2868+ new_signed_factor.value);
2869+ evaluated_signed_factors.dimension *= new_signed_factor.value;
2870+ } else {
2871+ throwError("Unit in exponent");
2872+ }
2873+ }
2874+
2875+ return evaluated_signed_factors;
2876+}
2877+
2878+EvaluatorQuantity ExpressionEvaluator::evaluateSignedFactor()
2879+{
2880+ EvaluatorQuantity result;
2881+ bool negate = FALSE;
2882+
2883+ if (!acceptToken('+', NULL)) {
2884+ negate = acceptToken ('-', NULL);
2885+ }
2886+
2887+ result = evaluateFactor();
2888+
2889+ if (negate) {
2890+ result.value = -result.value;
2891+ }
2892+
2893+ return result;
2894+}
2895+
2896+EvaluatorQuantity ExpressionEvaluator::evaluateFactor()
2897+{
2898+ EvaluatorQuantity evaluated_factor = EvaluatorQuantity();
2899+ EvaluatorToken consumed_token = EvaluatorToken();
2900+
2901+ if (acceptToken(TOKEN_NUM, &consumed_token)) {
2902+ evaluated_factor.value = consumed_token.value.fl;
2903+ } else if (acceptToken('(', NULL)) {
2904+ evaluated_factor = evaluateExpression();
2905+ isExpected(')', 0);
2906+ } else {
2907+ throwError("Expected number or '('");
2908+ }
2909+
2910+ if ( current_token.type == TOKEN_IDENTIFIER ) {
2911+ char *identifier;
2912+ EvaluatorQuantity result;
2913+
2914+ acceptToken(TOKEN_ANY, &consumed_token);
2915+
2916+ identifier = g_newa(char, consumed_token.value.size + 1);
2917+
2918+ strncpy(identifier, consumed_token.value.c, consumed_token.value.size);
2919+ identifier[consumed_token.value.size] = '\0';
2920+
2921+ if (resolveUnit(identifier, &result, unit)) {
2922+ evaluated_factor.value /= result.value;
2923+ evaluated_factor.dimension += result.dimension;
2924+ } else {
2925+ throwError("Unit was not resolved");
2926+ }
2927+ }
2928+
2929+ return evaluated_factor;
2930+}
2931+
2932+bool ExpressionEvaluator::acceptToken(TokenType token_type,
2933+ EvaluatorToken *consumed_token)
2934+{
2935+ bool existed = FALSE;
2936+
2937+ if ( token_type == current_token.type || token_type == TOKEN_ANY ) {
2938+ existed = TRUE;
2939+
2940+ if (consumed_token) {
2941+ *consumed_token = current_token;
2942+ }
2943+
2944+ // Parse next token
2945+ parseNextToken();
2946+ }
2947+
2948+ return existed;
2949+}
2950+
2951+void ExpressionEvaluator::parseNextToken()
2952+{
2953+ const char *s;
2954+
2955+ movePastWhiteSpace();
2956+ s = string;
2957+ start_of_current_token = s;
2958+
2959+ if ( !s || s[0] == '\0' ) {
2960+ // We're all done
2961+ current_token.type = TOKEN_END;
2962+ } else if ( s[0] == '+' || s[0] == '-' ) {
2963+ // Snatch these before the g_strtod() does, othewise they might
2964+ // be used in a numeric conversion.
2965+ acceptTokenCount(1, s[0]);
2966+ } else {
2967+ // Attempt to parse a numeric value
2968+ char *endptr = NULL;
2969+ gdouble value = g_strtod(s, &endptr);
2970+
2971+ if ( endptr && endptr != s ) {
2972+ // A numeric could be parsed, use it
2973+ current_token.value.fl = value;
2974+
2975+ current_token.type = TOKEN_NUM;
2976+ string = endptr;
2977+ } else if (isUnitIdentifierStart(s[0])) {
2978+ // Unit identifier
2979+ current_token.value.c = s;
2980+ current_token.value.size = getIdentifierSize(s, 0);
2981+
2982+ acceptTokenCount(current_token.value.size, TOKEN_IDENTIFIER);
2983+ } else {
2984+ // Everything else is a single character token
2985+ acceptTokenCount(1, s[0]);
2986+ }
2987+ }
2988+}
2989+
2990+void ExpressionEvaluator::acceptTokenCount (int count, TokenType token_type)
2991+{
2992+ current_token.type = token_type;
2993+ string += count;
2994+}
2995+
2996+void ExpressionEvaluator::isExpected(TokenType token_type,
2997+ EvaluatorToken *value)
2998+{
2999+ if (!acceptToken(token_type, value)) {
3000+ throwError("Unexpected token");
3001+ }
3002+}
3003+
3004+void ExpressionEvaluator::movePastWhiteSpace()
3005+{
3006+ if (!string) {
3007+ return;
3008+ }
3009+
3010+ while (g_ascii_isspace(*string)) {
3011+ string++;
3012+ }
3013+}
3014+
3015+bool ExpressionEvaluator::isUnitIdentifierStart(gunichar c)
3016+{
3017+ return (g_unichar_isalpha (c)
3018+ || c == (gunichar) '%'
3019+ || c == (gunichar) '\'');
3020 }
3021
3022 /**
3023- * gimp_eevl_unit_identifier_size:
3024+ * getIdentifierSize:
3025 * @s:
3026 * @start:
3027 *
3028 * Returns: Size of identifier in bytes (not including NULL
3029 * terminator).
3030 **/
3031-static gint
3032-gimp_eevl_unit_identifier_size (const gchar *string,
3033- gint start_offset)
3034+int ExpressionEvaluator::getIdentifierSize(const char *string, int start_offset)
3035 {
3036- const gchar *start = g_utf8_offset_to_pointer (string, start_offset);
3037- const gchar *s = start;
3038- gunichar c = g_utf8_get_char (s);
3039- gint length = 0;
3040-
3041- if (gimp_eevl_unit_identifier_start (c))
3042- {
3043- s = g_utf8_next_char (s);
3044- c = g_utf8_get_char (s);
3045- length++;
3046-
3047- while (gimp_eevl_unit_identifier_continue (c))
3048- {
3049- s = g_utf8_next_char (s);
3050- c = g_utf8_get_char (s);
3051- length++;
3052+ const char *start = g_utf8_offset_to_pointer(string, start_offset);
3053+ const char *s = start;
3054+ gunichar c = g_utf8_get_char(s);
3055+ int length = 0;
3056+
3057+ if (isUnitIdentifierStart(c)) {
3058+ s = g_utf8_next_char (s);
3059+ c = g_utf8_get_char (s);
3060+ length++;
3061+
3062+ while ( isUnitIdentifierStart (c) || g_unichar_isdigit (c) ) {
3063+ s = g_utf8_next_char(s);
3064+ c = g_utf8_get_char(s);
3065+ length++;
3066 }
3067 }
3068-
3069- return g_utf8_offset_to_pointer (start, length) - start;
3070-}
3071-
3072-static void
3073-gimp_eevl_expect (GimpEevl *eva,
3074- GimpEevlTokenType token_type,
3075- GimpEevlToken *value)
3076-{
3077- if (! gimp_eevl_accept (eva, token_type, value))
3078- gimp_eevl_error (eva, "Unexpected token");
3079-}
3080-
3081-static void
3082-gimp_eevl_error (GimpEevl *eva,
3083- const char *msg)
3084-{
3085- throw EvaluatorException(msg, eva->start_of_current_token);
3086+
3087+ return g_utf8_offset_to_pointer(start, length) - start;
3088+}
3089+
3090+bool ExpressionEvaluator::resolveUnit (const char* identifier,
3091+ EvaluatorQuantity *result,
3092+ Unit* unit)
3093+{
3094+ if (!unit) {
3095+ result->value = 1;
3096+ result->dimension = 1;
3097+ return true;
3098+ }else if (!identifier) {
3099+ result->value = 1;
3100+ result->dimension = unit->isAbsolute() ? 1 : 0;
3101+ return true;
3102+ } else if (unit_table.hasUnit(identifier)) {
3103+ Unit identifier_unit = unit_table.getUnit(identifier);
3104+ result->value = Quantity::convert(1, *unit, identifier_unit);
3105+ result->dimension = identifier_unit.isAbsolute() ? 1 : 0;
3106+ return true;
3107+ } else {
3108+ return false;
3109+ }
3110+}
3111+
3112+void ExpressionEvaluator::throwError(const char *msg)
3113+{
3114+ throw EvaluatorException(msg, start_of_current_token);
3115 }
3116
3117 } // namespace Util
3118
3119=== modified file 'src/util/expression-evaluator.h'
3120--- src/util/expression-evaluator.h 2011-10-27 04:55:51 +0000
3121+++ src/util/expression-evaluator.h 2013-09-20 17:05:49 +0000
3122@@ -6,6 +6,7 @@
3123 * Copyright (C) 2008-2009 Martin Nordholts <martinn@svn.gnome.org>
3124 * Modified for Inkscape by Johan Engelen
3125 * Copyright (C) 2011 Johan Engelen
3126+ * Copyright (C) 2013 Matthew Petroff
3127 *
3128 * This library is free software: you can redistribute it and/or
3129 * modify it under the terms of the GNU Lesser General Public
3130@@ -22,8 +23,8 @@
3131 * <http://www.gnu.org/licenses/>.
3132 */
3133
3134-#ifndef SEEN_GIMP_EEVL_H
3135-#define SEEN_GIMP_EEVL_H
3136+#ifndef INKSCAPE_UTIL_EXPRESSION_EVALUATOR_H
3137+#define INKSCAPE_UTIL_EXPRESSION_EVALUATOR_H
3138
3139 #include "util/units.h"
3140
3141@@ -33,7 +34,7 @@
3142
3143 /**
3144 * @file
3145- * Introducing eevl eva, the evaluator. A straightforward recursive
3146+ * Expression evaluator: A straightforward recursive
3147 * descent parser, no fuss, no new dependencies. The lexer is hand
3148 * coded, tedious, not extremely fast but works. It evaluates the
3149 * expression as it goes along, and does not create a parse tree or
3150@@ -43,8 +44,8 @@
3151 *
3152 * It relies on external unit resolving through a callback and does
3153 * elementary dimensionality constraint check (e.g. "2 mm + 3 px * 4
3154- * in" is an error, as L + L^2 is a missmatch). It uses g_strtod() for numeric
3155- * conversions and it's non-destructive in terms of the paramters, and
3156+ * in" is an error, as L + L^2 is a mismatch). It uses g_strtod() for numeric
3157+ * conversions and it's non-destructive in terms of the parameters, and
3158 * it's reentrant.
3159 *
3160 * EBNF:
3161@@ -52,7 +53,9 @@
3162 * expression ::= term { ('+' | '-') term }* |
3163 * <empty string> ;
3164 *
3165- * term ::= signed factor { ( '*' | '/' ) signed factor }* ;
3166+ * term ::= exponent { ( '*' | '/' ) exponent }* ;
3167+ *
3168+ * exponent ::= signed factor { '^' signed factor }* ;
3169 *
3170 * signed factor ::= ( '+' | '-' )? factor ;
3171 *
3172@@ -79,37 +82,104 @@
3173 class Unit;
3174
3175 /**
3176-* GimpEevlQuantity:
3177-* @value: In reference units.
3178-* @dimension: in has a dimension of 1, in^2 has a dimension of 2 etc
3179-*/
3180-typedef struct
3181+ * EvaluatorQuantity:
3182+ * @param value In reference units.
3183+ * @param dimension mm has a dimension of 1, mm^2 has a dimension of 2, etc.
3184+ */
3185+class EvaluatorQuantity
3186 {
3187+public:
3188+ EvaluatorQuantity(double value = 0, unsigned int dimension = 0);
3189+
3190 double value;
3191- gint dimension;
3192-} GimpEevlQuantity;
3193-
3194-typedef bool (* GimpEevlUnitResolverProc) (const gchar *identifier,
3195- GimpEevlQuantity *result,
3196- Unit* unit);
3197-
3198-GimpEevlQuantity gimp_eevl_evaluate (const gchar* string, Unit* unit = NULL);
3199+ unsigned int dimension;
3200+};
3201+
3202+/**
3203+ * TokenType
3204+ */
3205+enum {
3206+ TOKEN_NUM = 30000,
3207+ TOKEN_IDENTIFIER = 30001,
3208+ TOKEN_ANY = 40000,
3209+ TOKEN_END = 50000
3210+};
3211+typedef int TokenType;
3212+
3213+/**
3214+ * EvaluatorToken
3215+ */
3216+class EvaluatorToken
3217+{
3218+public:
3219+ EvaluatorToken();
3220+
3221+ TokenType type;
3222+
3223+ union {
3224+ double fl;
3225+ struct {
3226+ const char *c;
3227+ int size;
3228+ };
3229+ } value;
3230+};
3231+
3232+/**
3233+ * ExpressionEvaluator
3234+ * @param string NULL terminated input string to evaluate
3235+ * @param unit Unit output should be in
3236+ */
3237+class ExpressionEvaluator
3238+{
3239+public:
3240+ ExpressionEvaluator(const char *string, Unit *unit = NULL);
3241+
3242+ EvaluatorQuantity evaluate();
3243+
3244+private:
3245+ const char *string;
3246+ Unit *unit;
3247+
3248+ EvaluatorToken current_token;
3249+ const char *start_of_current_token;
3250+
3251+ EvaluatorQuantity evaluateExpression();
3252+ EvaluatorQuantity evaluateTerm();
3253+ EvaluatorQuantity evaluateExpTerm();
3254+ EvaluatorQuantity evaluateSignedFactor();
3255+ EvaluatorQuantity evaluateFactor();
3256+
3257+ bool acceptToken(TokenType token_type, EvaluatorToken *consumed_token);
3258+ void parseNextToken();
3259+ void acceptTokenCount(int count, TokenType token_type);
3260+ void isExpected(TokenType token_type, EvaluatorToken *value);
3261+
3262+ void movePastWhiteSpace();
3263+
3264+ static bool isUnitIdentifierStart(gunichar c);
3265+ static int getIdentifierSize(const char *s, int start);
3266+
3267+ static bool resolveUnit(const char *identifier, EvaluatorQuantity *result, Unit *unit);
3268+
3269+ void throwError(const char *msg);
3270+};
3271
3272 /**
3273 * Special exception class for the expression evaluator.
3274 */
3275 class EvaluatorException : public std::exception {
3276 public:
3277- EvaluatorException(const char * message, const char *at_position) {
3278+ EvaluatorException(const char *message, const char *at_position) {
3279 std::ostringstream os;
3280- const char* token = at_position ? at_position : "<End of input>";
3281+ const char *token = at_position ? at_position : "<End of input>";
3282 os << "Expression evaluator error: " << message << " at '" << token << "'";
3283 msgstr = os.str();
3284 }
3285
3286 virtual ~EvaluatorException() throw() {} // necessary to destroy the string object!!!
3287
3288- virtual const char* what() const throw () {
3289+ virtual const char *what() const throw () {
3290 return msgstr.c_str();
3291 }
3292 protected:
3293@@ -119,4 +189,4 @@
3294 }
3295 }
3296
3297-#endif // SEEN_GIMP_EEVL_H
3298+#endif // INKSCAPE_UTIL_EXPRESSION_EVALUATOR_H
3299
3300=== modified file 'src/util/units.cpp'
3301--- src/util/units.cpp 2013-09-01 17:34:44 +0000
3302+++ src/util/units.cpp 2013-09-20 17:05:49 +0000
3303@@ -114,6 +114,7 @@
3304 abbr(abbr),
3305 description(description)
3306 {
3307+ g_return_if_fail(factor <= 0);
3308 }
3309
3310 void Unit::clear()
3311@@ -166,25 +167,25 @@
3312 int Unit::svgUnit() const
3313 {
3314 if (!abbr.compare("px"))
3315- return 1;
3316+ return SVGLength::PX;
3317 if (!abbr.compare("pt"))
3318- return 2;
3319+ return SVGLength::PT;
3320 if (!abbr.compare("pc"))
3321- return 3;
3322+ return SVGLength::PC;
3323 if (!abbr.compare("mm"))
3324- return 4;
3325+ return SVGLength::MM;
3326 if (!abbr.compare("cm"))
3327- return 5;
3328+ return SVGLength::CM;
3329 if (!abbr.compare("in"))
3330- return 6;
3331+ return SVGLength::INCH;
3332 if (!abbr.compare("ft"))
3333- return 7;
3334+ return SVGLength::FOOT;
3335 if (!abbr.compare("em"))
3336- return 8;
3337+ return SVGLength::EM;
3338 if (!abbr.compare("ex"))
3339- return 9;
3340+ return SVGLength::EX;
3341 if (!abbr.compare("%"))
3342- return 10;
3343+ return SVGLength::PERCENT;
3344 return 0;
3345 }
3346
3347@@ -220,6 +221,36 @@
3348 return Unit();
3349 }
3350 }
3351+Unit UnitTable::getUnit(SVGLength::Unit const u) const
3352+{
3353+ Glib::ustring u_str;
3354+ switch(u) {
3355+ case SVGLength::PX:
3356+ u_str = "px"; break;
3357+ case SVGLength::PT:
3358+ u_str = "pt"; break;
3359+ case SVGLength::PC:
3360+ u_str = "pc"; break;
3361+ case SVGLength::MM:
3362+ u_str = "mm"; break;
3363+ case SVGLength::CM:
3364+ u_str = "cm"; break;
3365+ case SVGLength::INCH:
3366+ u_str = "in"; break;
3367+ case SVGLength::FOOT:
3368+ u_str = "ft"; break;
3369+ case SVGLength::EM:
3370+ u_str = "em"; break;
3371+ case SVGLength::EX:
3372+ u_str = "ex"; break;
3373+ case SVGLength::PERCENT:
3374+ u_str = "%"; break;
3375+ default:
3376+ u_str = "";
3377+ }
3378+
3379+ return getUnit(u_str);
3380+}
3381
3382 Quantity UnitTable::getQuantity(Glib::ustring const& q) const
3383 {
3384@@ -421,6 +452,27 @@
3385 return convert(from_dist, unit_table.getUnit(from), unit_table.getUnit(to));
3386 }
3387
3388+bool operator< (const Quantity &ql, const Quantity &qr)
3389+{
3390+ if (ql.unit->type != qr.unit->type) {
3391+ g_warning("Incompatible units");
3392+ return false;
3393+ }
3394+ return ql.quantity < qr.value(*ql.unit);
3395+}
3396+bool operator> (const Quantity &ql, const Quantity &qr)
3397+{
3398+ if (ql.unit->type != qr.unit->type) {
3399+ g_warning("Incompatible units");
3400+ return false;
3401+ }
3402+ return ql.quantity > qr.value(*ql.unit);
3403+}
3404+bool operator!= (const Quantity &q1, const Quantity &q2)
3405+{
3406+ return (*q1.unit != *q2.unit) || (q1.quantity != q2.quantity);
3407+}
3408+
3409 } // namespace Util
3410 } // namespace Inkscape
3411
3412
3413=== modified file 'src/util/units.h'
3414--- src/util/units.h 2013-08-04 22:01:18 +0000
3415+++ src/util/units.h 2013-09-20 17:05:49 +0000
3416@@ -1,5 +1,6 @@
3417 /*
3418 * Inkscape Units
3419+ * These classes are used for defining different unit systems.
3420 *
3421 * Authors:
3422 * Matthew Petroff <matthew@mpetroff.net>
3423@@ -9,25 +10,12 @@
3424 * Released under GNU GPL, read the file 'COPYING' for more information
3425 */
3426
3427-/*
3428-This is a rough draft of a global 'units' thingee, to allow dialogs and
3429-the ruler to share info about unit systems... Dunno if this is the
3430-right kind of object though, so we may have to redo this or shift things
3431-around later when it becomes clearer what we need.
3432-
3433-This object is used for defining different unit systems.
3434-
3435-This is intended to eventually replace inkscape/helper/units.*.
3436-
3437-Need to review the Units support that's in Gtkmm already...
3438-
3439-*/
3440-
3441 #ifndef INKSCAPE_UTIL_UNITS_H
3442 #define INKSCAPE_UTIL_UNITS_H
3443
3444 #include <map>
3445 #include <glibmm/ustring.h>
3446+#include "svg/svg-length.h"
3447
3448 namespace Inkscape {
3449 namespace Util {
3450@@ -112,6 +100,11 @@
3451 static double convert(const double from_dist, const Glib::ustring from, const Unit &to);
3452 static double convert(const double from_dist, const Unit &from, const Glib::ustring to);
3453 static double convert(const double from_dist, const Glib::ustring from, const Glib::ustring to);
3454+
3455+ /** Comparison operators. */
3456+ friend bool operator< (const Quantity &ql, const Quantity &qr);
3457+ friend bool operator> (const Quantity &ql, const Quantity &qr);
3458+ friend bool operator!= (const Quantity &q1, const Quantity &q2);
3459 };
3460
3461 class UnitTable {
3462@@ -132,6 +125,9 @@
3463 /** Retrieve a given unit based on its string identifier */
3464 Unit getUnit(Glib::ustring const &name) const;
3465
3466+ /** Retrieve a given unit based on its SVGLength unit */
3467+ Unit getUnit(SVGLength::Unit const u) const;
3468+
3469 /** Retrieve a quantity based on its string identifier */
3470 Quantity getQuantity(Glib::ustring const &q) const;
3471
3472
3473=== modified file 'src/widgets/calligraphy-toolbar.cpp'
3474--- src/widgets/calligraphy-toolbar.cpp 2013-07-19 18:19:03 +0000
3475+++ src/widgets/calligraphy-toolbar.cpp 2013-09-20 17:05:49 +0000
3476@@ -450,7 +450,7 @@
3477 GTK_WIDGET(desktop->canvas), holder, TRUE, "altx-calligraphy",
3478 1, 100, 1.0, 10.0,
3479 labels, values, G_N_ELEMENTS(labels),
3480- sp_ddc_width_value_changed, 1, 0 );
3481+ sp_ddc_width_value_changed, NULL /*unit tracker*/, 1, 0 );
3482 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
3483 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3484 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3485@@ -467,7 +467,7 @@
3486 GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
3487 -100, 100, 1, 10.0,
3488 labels, values, G_N_ELEMENTS(labels),
3489- sp_ddc_velthin_value_changed, 1, 0);
3490+ sp_ddc_velthin_value_changed, NULL /*unit tracker*/, 1, 0);
3491 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3492 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3493 }
3494@@ -483,7 +483,7 @@
3495 GTK_WIDGET(desktop->canvas), holder, TRUE, "calligraphy-angle",
3496 -90.0, 90.0, 1.0, 10.0,
3497 labels, values, G_N_ELEMENTS(labels),
3498- sp_ddc_angle_value_changed, 1, 0 );
3499+ sp_ddc_angle_value_changed, NULL /*unit tracker*/, 1, 0 );
3500 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3501 g_object_set_data( holder, "angle_action", eact );
3502 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3503@@ -501,7 +501,7 @@
3504 GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
3505 0.0, 100, 1.0, 10.0,
3506 labels, values, G_N_ELEMENTS(labels),
3507- sp_ddc_flatness_value_changed, 1, 0);
3508+ sp_ddc_flatness_value_changed, NULL /*unit tracker*/, 1, 0);
3509 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3510 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3511 }
3512@@ -518,7 +518,7 @@
3513 GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
3514 0.0, 5.0, 0.01, 0.1,
3515 labels, values, G_N_ELEMENTS(labels),
3516- sp_ddc_cap_rounding_value_changed, 0.01, 2 );
3517+ sp_ddc_cap_rounding_value_changed, NULL /*unit tracker*/, 0.01, 2 );
3518 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3519 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3520 }
3521@@ -534,7 +534,7 @@
3522 GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
3523 0.0, 100, 1, 10.0,
3524 labels, values, G_N_ELEMENTS(labels),
3525- sp_ddc_tremor_value_changed, 1, 0);
3526+ sp_ddc_tremor_value_changed, NULL /*unit tracker*/, 1, 0);
3527
3528 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
3529 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3530@@ -552,7 +552,7 @@
3531 GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
3532 0.0, 100, 1, 10.0,
3533 labels, values, G_N_ELEMENTS(labels),
3534- sp_ddc_wiggle_value_changed, 1, 0);
3535+ sp_ddc_wiggle_value_changed, NULL /*unit tracker*/, 1, 0);
3536 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
3537 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3538 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3539@@ -569,7 +569,7 @@
3540 GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
3541 0.0, 100, 1, 10.0,
3542 labels, values, G_N_ELEMENTS(labels),
3543- sp_ddc_mass_value_changed, 1, 0);
3544+ sp_ddc_mass_value_changed, NULL /*unit tracker*/, 1, 0);
3545 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
3546 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3547 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3548
3549=== modified file 'src/widgets/connector-toolbar.cpp'
3550--- src/widgets/connector-toolbar.cpp 2013-07-19 18:19:03 +0000
3551+++ src/widgets/connector-toolbar.cpp 2013-09-20 17:05:49 +0000
3552@@ -364,7 +364,7 @@
3553 GTK_WIDGET(desktop->canvas), holder, TRUE, "inkscape:connector-curvature",
3554 0, 100, 1.0, 10.0,
3555 0, 0, 0,
3556- connector_curvature_changed, 1, 0 );
3557+ connector_curvature_changed, NULL /*unit tracker*/, 1, 0 );
3558 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3559
3560 // Spacing spinbox
3561@@ -375,7 +375,7 @@
3562 GTK_WIDGET(desktop->canvas), holder, TRUE, "inkscape:connector-spacing",
3563 0, 100, 1.0, 10.0,
3564 0, 0, 0,
3565- connector_spacing_changed, 1, 0 );
3566+ connector_spacing_changed, NULL /*unit tracker*/, 1, 0 );
3567 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3568
3569 // Graph (connector network) layout
3570@@ -397,7 +397,7 @@
3571 GTK_WIDGET(desktop->canvas), holder, TRUE, "inkscape:connector-length",
3572 10, 1000, 10.0, 100.0,
3573 0, 0, 0,
3574- connector_length_changed, 1, 0 );
3575+ connector_length_changed, NULL /*unit tracker*/, 1, 0 );
3576 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3577
3578
3579
3580=== modified file 'src/widgets/desktop-widget.cpp'
3581--- src/widgets/desktop-widget.cpp 2013-08-30 21:35:42 +0000
3582+++ src/widgets/desktop-widget.cpp 2013-09-20 17:05:49 +0000
3583@@ -2135,8 +2135,8 @@
3584
3585 /* The desktop region we always show unconditionally */
3586 SPDocument *doc = dtw->desktop->doc();
3587- Geom::Rect darea ( Geom::Point(-doc->getWidth(), -doc->getHeight()),
3588- Geom::Point(2 * doc->getWidth(), 2 * doc->getHeight()) );
3589+ Geom::Rect darea ( Geom::Point(-doc->getWidth().value("px"), -doc->getHeight().value("px")),
3590+ Geom::Point(2 * doc->getWidth().value("px"), 2 * doc->getHeight().value("px")) );
3591
3592 Geom::OptRect deskarea;
3593 if (Inkscape::Preferences::get()->getInt("/tools/bounding_box") == 0) {
3594
3595=== modified file 'src/widgets/eraser-toolbar.cpp'
3596--- src/widgets/eraser-toolbar.cpp 2013-07-30 01:54:37 +0000
3597+++ src/widgets/eraser-toolbar.cpp 2013-09-20 17:05:49 +0000
3598@@ -148,7 +148,7 @@
3599 GTK_WIDGET(desktop->canvas), holder, TRUE, "altx-eraser",
3600 1, 100, 1.0, 10.0,
3601 labels, values, G_N_ELEMENTS(labels),
3602- sp_erc_width_value_changed, 1, 0);
3603+ sp_erc_width_value_changed, NULL /*unit tracker*/, 1, 0);
3604 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
3605 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3606 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3607
3608=== modified file 'src/widgets/gradient-toolbar.cpp'
3609--- src/widgets/gradient-toolbar.cpp 2013-08-30 21:35:42 +0000
3610+++ src/widgets/gradient-toolbar.cpp 2013-09-20 17:05:49 +0000
3611@@ -1175,8 +1175,9 @@
3612 GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
3613 0.0, 1.0, 0.01, 0.1,
3614 0, 0, 0,
3615- gr_stop_offset_adjustment_changed
3616- , 0.01, 2, 1.0);
3617+ gr_stop_offset_adjustment_changed,
3618+ NULL /*unit tracker*/,
3619+ 0.01, 2, 1.0);
3620
3621 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3622 g_object_set_data( holder, "offset_action", eact );
3623
3624=== modified file 'src/widgets/icon.cpp'
3625--- src/widgets/icon.cpp 2013-06-12 15:14:48 +0000
3626+++ src/widgets/icon.cpp 2013-09-20 17:05:49 +0000
3627@@ -42,6 +42,7 @@
3628 #include "display/drawing.h"
3629 #include "io/sys.h"
3630 #include "sp-root.h"
3631+#include "util/units.h"
3632
3633 #include "icon.h"
3634
3635@@ -1137,7 +1138,7 @@
3636 if ( object->parent == NULL )
3637 {
3638 dbox = Geom::Rect(Geom::Point(0, 0),
3639- Geom::Point(doc->getWidth(), doc->getHeight()));
3640+ Geom::Point(doc->getWidth().value("px"), doc->getHeight().value("px")));
3641 }
3642
3643 /* This is in document coordinates, i.e. pixels */
3644
3645=== modified file 'src/widgets/mesh-toolbar.cpp'
3646--- src/widgets/mesh-toolbar.cpp 2013-07-19 18:19:03 +0000
3647+++ src/widgets/mesh-toolbar.cpp 2013-09-20 17:05:49 +0000
3648@@ -265,7 +265,7 @@
3649 GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
3650 1, 20, 1, 1,
3651 labels, values, G_N_ELEMENTS(labels),
3652- ms_row_changed,
3653+ ms_row_changed, NULL /*unit tracker*/,
3654 1.0, 0 );
3655 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3656 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3657@@ -281,7 +281,7 @@
3658 GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
3659 1, 20, 1, 1,
3660 labels, values, G_N_ELEMENTS(labels),
3661- ms_col_changed,
3662+ ms_col_changed, NULL /*unit tracker*/,
3663 1.0, 0 );
3664 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3665 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3666
3667=== modified file 'src/widgets/node-toolbar.cpp'
3668--- src/widgets/node-toolbar.cpp 2013-08-04 22:01:18 +0000
3669+++ src/widgets/node-toolbar.cpp 2013-09-20 17:05:49 +0000
3670@@ -595,7 +595,7 @@
3671 GTK_WIDGET(desktop->canvas), holder, TRUE, "altx-nodes",
3672 -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
3673 labels, values, G_N_ELEMENTS(labels),
3674- sp_node_path_x_value_changed );
3675+ sp_node_path_x_value_changed, tracker );
3676 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
3677 g_object_set_data( holder, "nodes_x_action", eact );
3678 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
3679@@ -613,7 +613,7 @@
3680 GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
3681 -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
3682 labels, values, G_N_ELEMENTS(labels),
3683- sp_node_path_y_value_changed );
3684+ sp_node_path_y_value_changed, tracker );
3685 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
3686 g_object_set_data( holder, "nodes_y_action", eact );
3687 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
3688
3689=== modified file 'src/widgets/paintbucket-toolbar.cpp'
3690--- src/widgets/paintbucket-toolbar.cpp 2013-08-30 21:35:42 +0000
3691+++ src/widgets/paintbucket-toolbar.cpp 2013-09-20 17:05:49 +0000
3692@@ -169,7 +169,7 @@
3693 "/tools/paintbucket/threshold", 5, GTK_WIDGET(desktop->canvas), holder, TRUE,
3694 "inkscape:paintbucket-threshold", 0, 100.0, 1.0, 10.0,
3695 0, 0, 0,
3696- paintbucket_threshold_changed, 1, 0 );
3697+ paintbucket_threshold_changed, NULL /*unit tracker*/, 1, 0 );
3698
3699 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
3700 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3701@@ -197,7 +197,7 @@
3702 "/tools/paintbucket/offset", 0, GTK_WIDGET(desktop->canvas), holder, TRUE,
3703 "inkscape:paintbucket-offset", -1e4, 1e4, 0.1, 0.5,
3704 0, 0, 0,
3705- paintbucket_offset_changed, 1, 2);
3706+ paintbucket_offset_changed, tracker, 1, 2);
3707 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
3708
3709 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3710
3711=== modified file 'src/widgets/pencil-toolbar.cpp'
3712--- src/widgets/pencil-toolbar.cpp 2013-07-19 18:19:03 +0000
3713+++ src/widgets/pencil-toolbar.cpp 2013-09-20 17:05:49 +0000
3714@@ -307,6 +307,7 @@
3715 1, 100.0, 0.5, 1.0,
3716 labels, values, G_N_ELEMENTS(labels),
3717 sp_pencil_tb_tolerance_value_changed,
3718+ NULL /*unit tracker*/,
3719 1, 2);
3720 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
3721 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3722
3723=== modified file 'src/widgets/rect-toolbar.cpp'
3724--- src/widgets/rect-toolbar.cpp 2013-08-30 21:35:42 +0000
3725+++ src/widgets/rect-toolbar.cpp 2013-09-20 17:05:49 +0000
3726@@ -114,7 +114,7 @@
3727 for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
3728 if (SP_IS_RECT(items->data)) {
3729 if (gtk_adjustment_get_value(adj) != 0) {
3730- (SP_RECT(items->data)->*setter)(Quantity::convert(gtk_adjustment_get_value(adj), unit, "px"));
3731+ (SP_RECT(items->data)->*setter)(Quantity::convert(gtk_adjustment_get_value(adj), unit, *sp_desktop_namedview(desktop)->doc_units));
3732 } else {
3733 SP_OBJECT(items->data)->getRepr()->setAttribute(value_name, NULL);
3734 }
3735@@ -186,6 +186,7 @@
3736
3737 UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
3738 Unit const unit = tracker->getActiveUnit();
3739+ Unit const doc_unit = *sp_desktop_namedview(SP_ACTIVE_DESKTOP)->doc_units;
3740
3741 gpointer item = g_object_get_data( tbl, "item" );
3742 if (item && SP_IS_RECT(item)) {
3743@@ -193,28 +194,28 @@
3744 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "rx" ) );
3745
3746 gdouble rx = SP_RECT(item)->getVisibleRx();
3747- gtk_adjustment_set_value(adj, Quantity::convert(rx, "px", unit));
3748+ gtk_adjustment_set_value(adj, Quantity::convert(rx, doc_unit, unit));
3749 }
3750
3751 {
3752 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "ry" ) );
3753
3754 gdouble ry = SP_RECT(item)->getVisibleRy();
3755- gtk_adjustment_set_value(adj, Quantity::convert(ry, "px", unit));
3756+ gtk_adjustment_set_value(adj, Quantity::convert(ry, doc_unit, unit));
3757 }
3758
3759 {
3760 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "width" ) );
3761
3762 gdouble width = SP_RECT(item)->getVisibleWidth();
3763- gtk_adjustment_set_value(adj, Quantity::convert(width, "px", unit));
3764+ gtk_adjustment_set_value(adj, Quantity::convert(width, doc_unit, unit));
3765 }
3766
3767 {
3768 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "height" ) );
3769
3770 gdouble height = SP_RECT(item)->getVisibleHeight();
3771- gtk_adjustment_set_value(adj, Quantity::convert(height, "px", unit));
3772+ gtk_adjustment_set_value(adj, Quantity::convert(height, doc_unit, unit));
3773 }
3774 }
3775
3776@@ -322,7 +323,7 @@
3777 GTK_WIDGET(desktop->canvas), holder, TRUE, "altx-rect",
3778 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
3779 labels, values, G_N_ELEMENTS(labels),
3780- sp_rtb_width_value_changed );
3781+ sp_rtb_width_value_changed, tracker);
3782 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
3783 g_object_set_data( holder, "width_action", eact );
3784 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
3785@@ -339,7 +340,7 @@
3786 GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
3787 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
3788 labels, values, G_N_ELEMENTS(labels),
3789- sp_rtb_height_value_changed );
3790+ sp_rtb_height_value_changed, tracker);
3791 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
3792 g_object_set_data( holder, "height_action", eact );
3793 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
3794@@ -356,7 +357,7 @@
3795 GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
3796 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
3797 labels, values, G_N_ELEMENTS(labels),
3798- sp_rtb_rx_value_changed);
3799+ sp_rtb_rx_value_changed, tracker);
3800 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
3801 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3802 }
3803@@ -371,7 +372,7 @@
3804 GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
3805 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
3806 labels, values, G_N_ELEMENTS(labels),
3807- sp_rtb_ry_value_changed);
3808+ sp_rtb_ry_value_changed, tracker);
3809 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
3810 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3811 }
3812
3813=== modified file 'src/widgets/select-toolbar.cpp'
3814--- src/widgets/select-toolbar.cpp 2013-08-04 22:01:18 +0000
3815+++ src/widgets/select-toolbar.cpp 2013-09-20 17:05:49 +0000
3816@@ -273,7 +273,7 @@
3817 g_object_set_data(G_OBJECT(spw), "update", GINT_TO_POINTER(FALSE));
3818 }
3819
3820-static GtkWidget* createCustomSlider( GtkAdjustment *adjustment, gdouble climbRate, guint digits )
3821+static GtkWidget* createCustomSlider( GtkAdjustment *adjustment, gdouble climbRate, guint digits, Inkscape::UI::Widget::UnitTracker *unit_tracker )
3822 {
3823 #if WITH_GTKMM_3_0
3824 Glib::RefPtr<Gtk::Adjustment> adj = Glib::wrap(adjustment, true);
3825@@ -281,6 +281,7 @@
3826 #else
3827 Inkscape::UI::Widget::SpinButton *inkSpinner = new Inkscape::UI::Widget::SpinButton(*Glib::wrap(adjustment, true), climbRate, digits);
3828 #endif
3829+ inkSpinner->addUnitTracker(unit_tracker);
3830 inkSpinner = Gtk::manage( inkSpinner );
3831 GtkWidget *widget = GTK_WIDGET( inkSpinner->gobj() );
3832 return widget;
3833@@ -313,7 +314,7 @@
3834 g_object_set_data( G_OBJECT(spw), data, adj );
3835 }
3836
3837- EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, Q_(label), tooltip, 0, SPIN_STEP, 3 );
3838+ EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, Q_(label), tooltip, 0, SPIN_STEP, 3, tracker );
3839 if ( shortLabel ) {
3840 g_object_set( act, "short_label", Q_(shortLabel), NULL );
3841 }
3842
3843=== modified file 'src/widgets/spiral-toolbar.cpp'
3844--- src/widgets/spiral-toolbar.cpp 2013-07-19 18:19:03 +0000
3845+++ src/widgets/spiral-toolbar.cpp 2013-09-20 17:05:49 +0000
3846@@ -262,7 +262,7 @@
3847 GTK_WIDGET(desktop->canvas), holder, TRUE, "altx-spiral",
3848 0.01, 1024.0, 0.1, 1.0,
3849 labels, values, G_N_ELEMENTS(labels),
3850- sp_spl_tb_revolution_value_changed, 1, 2);
3851+ sp_spl_tb_revolution_value_changed, NULL /*unit tracker*/, 1, 2);
3852 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3853 }
3854
3855
3856=== modified file 'src/widgets/spray-toolbar.cpp'
3857--- src/widgets/spray-toolbar.cpp 2013-07-19 18:19:03 +0000
3858+++ src/widgets/spray-toolbar.cpp 2013-09-20 17:05:49 +0000
3859@@ -130,7 +130,7 @@
3860 GTK_WIDGET(desktop->canvas), holder, TRUE, "altx-spray",
3861 1, 100, 1.0, 10.0,
3862 labels, values, G_N_ELEMENTS(labels),
3863- sp_spray_width_value_changed, 1, 0 );
3864+ sp_spray_width_value_changed, NULL /*unit tracker*/, 1, 0 );
3865 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
3866 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3867 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3868@@ -146,7 +146,7 @@
3869 GTK_WIDGET(desktop->canvas), holder, TRUE, "spray-mean",
3870 0, 100, 1.0, 10.0,
3871 labels, values, G_N_ELEMENTS(labels),
3872- sp_spray_mean_value_changed, 1, 0 );
3873+ sp_spray_mean_value_changed, NULL /*unit tracker*/, 1, 0 );
3874 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
3875 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3876 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3877@@ -162,7 +162,7 @@
3878 GTK_WIDGET(desktop->canvas), holder, TRUE, "spray-standard_deviation",
3879 1, 100, 1.0, 10.0,
3880 labels, values, G_N_ELEMENTS(labels),
3881- sp_spray_standard_deviation_value_changed, 1, 0 );
3882+ sp_spray_standard_deviation_value_changed, NULL /*unit tracker*/, 1, 0 );
3883 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
3884 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3885 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3886@@ -223,7 +223,7 @@
3887 GTK_WIDGET(desktop->canvas), holder, TRUE, "spray-population",
3888 1, 100, 1.0, 10.0,
3889 labels, values, G_N_ELEMENTS(labels),
3890- sp_spray_population_value_changed, 1, 0 );
3891+ sp_spray_population_value_changed, NULL /*unit tracker*/, 1, 0 );
3892 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
3893 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3894 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3895@@ -254,7 +254,7 @@
3896 GTK_WIDGET(desktop->canvas), holder, TRUE, "spray-rotation",
3897 0, 100, 1.0, 10.0,
3898 labels, values, G_N_ELEMENTS(labels),
3899- sp_spray_rotation_value_changed, 1, 0 );
3900+ sp_spray_rotation_value_changed, NULL /*unit tracker*/, 1, 0 );
3901 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
3902 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3903 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3904@@ -272,7 +272,7 @@
3905 GTK_WIDGET(desktop->canvas), holder, TRUE, "spray-scale",
3906 0, 100, 1.0, 10.0,
3907 labels, values, G_N_ELEMENTS(labels),
3908- sp_spray_scale_value_changed, 1, 0 );
3909+ sp_spray_scale_value_changed, NULL /*unit tracker*/, 1, 0 );
3910 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
3911 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3912 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3913
3914=== modified file 'src/widgets/star-toolbar.cpp'
3915--- src/widgets/star-toolbar.cpp 2013-07-19 18:19:03 +0000
3916+++ src/widgets/star-toolbar.cpp 2013-09-20 17:05:49 +0000
3917@@ -504,7 +504,7 @@
3918 GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
3919 3, 1024, 1, 5,
3920 labels, values, G_N_ELEMENTS(labels),
3921- sp_stb_magnitude_value_changed,
3922+ sp_stb_magnitude_value_changed, NULL /*unit tracker*/,
3923 1.0, 0 );
3924 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3925 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3926@@ -559,7 +559,7 @@
3927 GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
3928 -10.0, 10.0, 0.001, 0.01,
3929 labels, values, G_N_ELEMENTS(labels),
3930- sp_stb_randomized_value_changed, 0.1, 3 );
3931+ sp_stb_randomized_value_changed, NULL /*unit tracker*/, 0.1, 3 );
3932 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3933 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3934 }
3935
3936=== modified file 'src/widgets/text-toolbar.cpp'
3937--- src/widgets/text-toolbar.cpp 2013-07-30 02:51:28 +0000
3938+++ src/widgets/text-toolbar.cpp 2013-09-20 17:05:49 +0000
3939@@ -1459,6 +1459,7 @@
3940 0.0, 10.0, 0.01, 0.10, /* lower, upper, step (arrow up/down), page up/down */
3941 labels, values, G_N_ELEMENTS(labels), /* drop down menu */
3942 sp_text_lineheight_value_changed, /* callback */
3943+ NULL, /* unit tracker */
3944 0.1, /* step (used?) */
3945 2, /* digits to show */
3946 1.0 /* factor (multiplies default) */
3947@@ -1489,6 +1490,7 @@
3948 -100.0, 100.0, 0.01, 0.10, /* lower, upper, step (arrow up/down), page up/down */
3949 labels, values, G_N_ELEMENTS(labels), /* drop down menu */
3950 sp_text_wordspacing_value_changed, /* callback */
3951+ NULL, /* unit tracker */
3952 0.1, /* step (used?) */
3953 2, /* digits to show */
3954 1.0 /* factor (multiplies default) */
3955@@ -1519,6 +1521,7 @@
3956 -100.0, 100.0, 0.01, 0.10, /* lower, upper, step (arrow up/down), page up/down */
3957 labels, values, G_N_ELEMENTS(labels), /* drop down menu */
3958 sp_text_letterspacing_value_changed, /* callback */
3959+ NULL, /* unit tracker */
3960 0.1, /* step (used?) */
3961 2, /* digits to show */
3962 1.0 /* factor (multiplies default) */
3963@@ -1549,6 +1552,7 @@
3964 -100.0, 100.0, 0.01, 0.1, /* lower, upper, step (arrow up/down), page up/down */
3965 labels, values, G_N_ELEMENTS(labels), /* drop down menu */
3966 sp_text_dx_value_changed, /* callback */
3967+ NULL, /* unit tracker */
3968 0.1, /* step (used?) */
3969 2, /* digits to show */
3970 1.0 /* factor (multiplies default) */
3971@@ -1579,6 +1583,7 @@
3972 -100.0, 100.0, 0.01, 0.1, /* lower, upper, step (arrow up/down), page up/down */
3973 labels, values, G_N_ELEMENTS(labels), /* drop down menu */
3974 sp_text_dy_value_changed, /* callback */
3975+ NULL, /* unit tracker */
3976 0.1, /* step (used?) */
3977 2, /* digits to show */
3978 1.0 /* factor (multiplies default) */
3979@@ -1609,6 +1614,7 @@
3980 -180.0, 180.0, 0.1, 1.0, /* lower, upper, step (arrow up/down), page up/down */
3981 labels, values, G_N_ELEMENTS(labels), /* drop down menu */
3982 sp_text_rotation_value_changed, /* callback */
3983+ NULL, /* unit tracker */
3984 0.1, /* step (used?) */
3985 2, /* digits to show */
3986 1.0 /* factor (multiplies default) */
3987
3988=== modified file 'src/widgets/toolbox.cpp'
3989--- src/widgets/toolbox.cpp 2013-08-30 21:35:42 +0000
3990+++ src/widgets/toolbox.cpp 2013-09-20 17:05:49 +0000
3991@@ -1012,7 +1012,7 @@
3992 return toolboxNewCommon( tb, BAR_SNAP, GTK_POS_LEFT );
3993 }
3994
3995-static GtkWidget* createCustomSlider( GtkAdjustment *adjustment, gdouble climbRate, guint digits )
3996+static GtkWidget* createCustomSlider( GtkAdjustment *adjustment, gdouble climbRate, guint digits, Inkscape::UI::Widget::UnitTracker *unit_tracker)
3997 {
3998 #if WITH_GTKMM_3_0
3999 Glib::RefPtr<Gtk::Adjustment> adj = Glib::wrap(adjustment, true);
4000@@ -1020,6 +1020,7 @@
4001 #else
4002 Inkscape::UI::Widget::SpinButton *inkSpinner = new Inkscape::UI::Widget::SpinButton(*Glib::wrap(adjustment, true), climbRate, digits);
4003 #endif
4004+ inkSpinner->addUnitTracker(unit_tracker);
4005 inkSpinner = Gtk::manage( inkSpinner );
4006 GtkWidget *widget = GTK_WIDGET( inkSpinner->gobj() );
4007 return widget;
4008@@ -1034,6 +1035,7 @@
4009 gdouble lower, gdouble upper, gdouble step, gdouble page,
4010 gchar const** descrLabels, gdouble const* descrValues, guint descrCount,
4011 void (*callback)(GtkAdjustment *, GObject *),
4012+ Inkscape::UI::Widget::UnitTracker *unit_tracker,
4013 gdouble climb/* = 0.1*/, guint digits/* = 3*/, double factor/* = 1.0*/ )
4014 {
4015 static bool init = false;
4016@@ -1048,7 +1050,7 @@
4017
4018 g_signal_connect( G_OBJECT(adj), "value-changed", G_CALLBACK(callback), dataKludge );
4019
4020- EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, label, tooltip, 0, climb, digits );
4021+ EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, label, tooltip, 0, climb, digits, unit_tracker );
4022 if ( shortLabel ) {
4023 g_object_set( act, "short_label", shortLabel, NULL );
4024 }
4025
4026=== modified file 'src/widgets/toolbox.h'
4027--- src/widgets/toolbox.h 2013-08-30 21:35:42 +0000
4028+++ src/widgets/toolbox.h 2013-09-20 17:05:49 +0000
4029@@ -28,6 +28,10 @@
4030 namespace Inkscape {
4031 namespace UI {
4032
4033+namespace Widget {
4034+ class UnitTracker;
4035+}
4036+
4037 /**
4038 * Main toolbox source.
4039 */
4040@@ -123,6 +127,7 @@
4041 gdouble lower, gdouble upper, gdouble step, gdouble page,
4042 gchar const** descrLabels, gdouble const* descrValues, guint descrCount,
4043 void (*callback)(GtkAdjustment *, GObject *),
4044+ Inkscape::UI::Widget::UnitTracker *unit_tracker = NULL,
4045 gdouble climb = 0.1, guint digits = 3, double factor = 1.0 );
4046
4047 #endif /* !SEEN_TOOLBOX_H */
4048
4049=== modified file 'src/widgets/tweak-toolbar.cpp'
4050--- src/widgets/tweak-toolbar.cpp 2013-07-19 18:19:03 +0000
4051+++ src/widgets/tweak-toolbar.cpp 2013-09-20 17:05:49 +0000
4052@@ -144,7 +144,7 @@
4053 GTK_WIDGET(desktop->canvas), holder, TRUE, "altx-tweak",
4054 1, 100, 1.0, 10.0,
4055 labels, values, G_N_ELEMENTS(labels),
4056- sp_tweak_width_value_changed, 0.01, 0, 100 );
4057+ sp_tweak_width_value_changed, NULL /*unit tracker*/, 0.01, 0, 100 );
4058 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
4059 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4060 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4061@@ -161,7 +161,7 @@
4062 GTK_WIDGET(desktop->canvas), holder, TRUE, "tweak-force",
4063 1, 100, 1.0, 10.0,
4064 labels, values, G_N_ELEMENTS(labels),
4065- sp_tweak_force_value_changed, 0.01, 0, 100 );
4066+ sp_tweak_force_value_changed, NULL /*unit tracker*/, 0.01, 0, 100 );
4067 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
4068 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4069 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4070@@ -370,7 +370,7 @@
4071 GTK_WIDGET(desktop->canvas), holder, TRUE, "tweak-fidelity",
4072 1, 100, 1.0, 10.0,
4073 labels, values, G_N_ELEMENTS(labels),
4074- sp_tweak_fidelity_value_changed, 0.01, 0, 100 );
4075+ sp_tweak_fidelity_value_changed, NULL /*unit tracker*/, 0.01, 0, 100 );
4076 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4077 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4078 if (mode == TWEAK_MODE_COLORPAINT || mode == TWEAK_MODE_COLORJITTER) {