Merge lp:~inkscape.dev/inkscape/doc_rotate into lp:~inkscape.dev/inkscape/trunk
- doc_rotate
- Merge into trunk
Proposed by
Jabiertxof
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | 15444 | ||||
Proposed branch: | lp:~inkscape.dev/inkscape/doc_rotate | ||||
Merge into: | lp:~inkscape.dev/inkscape/trunk | ||||
Diff against target: |
2821 lines (+1359/-546) 31 files modified
share/extensions/hpgl_output.py (+15/-0) share/extensions/synfig_output.py (+9/-0) src/attributes.cpp (+1/-0) src/attributes.h (+1/-0) src/desktop-events.cpp (+4/-0) src/display/canvas-temporary-item-list.h (+1/-0) src/display/sp-canvas.cpp (+292/-3) src/display/sp-canvas.h (+4/-1) src/document-undo.cpp (+37/-34) src/document.cpp (+6/-0) src/extension/internal/cairo-png-out.cpp (+2/-2) src/extension/internal/cairo-ps-out.cpp (+5/-2) src/extension/internal/cairo-renderer-pdf-out.cpp (+3/-1) src/extension/internal/emf-inout.cpp (+3/-2) src/extension/internal/javafx-out.cpp (+7/-2) src/extension/internal/latex-pstricks-out.cpp (+2/-0) src/extension/internal/odf.cpp (+8/-1) src/extension/internal/pov-out.cpp (+10/-3) src/extension/internal/wmf-inout.cpp (+5/-2) src/file.cpp (+4/-2) src/print.cpp (+2/-0) src/sp-namedview.cpp (+97/-1) src/sp-namedview.h (+8/-3) src/ui/dialog/export.cpp (+8/-1) src/ui/tools/tool-base.cpp (+562/-466) src/ui/tools/tool-base.h (+1/-0) src/viewbox.cpp (+49/-13) src/viewbox.h (+7/-0) src/widgets/desktop-widget.cpp (+202/-6) src/widgets/desktop-widget.h (+3/-1) src/widgets/widget-sizes.h (+1/-0) |
||||
To merge this branch: | bzr merge lp:~inkscape.dev/inkscape/doc_rotate | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Martin Owens | Approve | ||
Inkscape Developers | Pending | ||
Review via email: mp+310123@code.launchpad.net |
Commit message
Description of the change
Add rotate canvas feature to Inkscape.
It add the option to rotate in 2 ways:
1. from botton left widget
2. with control+middle button or spacebar
To post a comment you must log in.
- 15175. By Jabiertxof
-
Fix a bug that allow to enter rotate mode with right click
- 15176. By Jabiertxof
-
Update to trunk
- 15177. By Jabiertxof
-
Fix some bugs pointed by vlada
- 15178. By Jabiertxof
-
Update to trunk
- 15179. By Jabiertxof
-
Fix some bugs
- 15180. By Jabiertxof <jtx@jtx>
-
fixing to new trunk
- 15181. By Jabiertxof <jtx@jtx>
-
Update to trunk
- 15182. By Jabiertxof
-
Put namespace as constant
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'share/extensions/hpgl_output.py' |
2 | --- share/extensions/hpgl_output.py 2016-05-26 09:28:23 +0000 |
3 | +++ share/extensions/hpgl_output.py 2017-01-24 17:53:20 +0000 |
4 | @@ -20,6 +20,7 @@ |
5 | |
6 | # standard library |
7 | import sys |
8 | +from inkex import NSS |
9 | # local libraries |
10 | import hpgl_encoder |
11 | import inkex |
12 | @@ -44,10 +45,18 @@ |
13 | self.OptionParser.add_option('--precut', action='store', type='inkbool', dest='precut', default='TRUE', help='Use precut') |
14 | self.OptionParser.add_option('--flat', action='store', type='float', dest='flat', default=1.2, help='Curve flatness') |
15 | self.OptionParser.add_option('--autoAlign', action='store', type='inkbool', dest='autoAlign', default='TRUE', help='Auto align') |
16 | + self.DOCROTATE = "{http://www.inkscape.org/namespaces/inkscape}document_rotation" |
17 | |
18 | def effect(self): |
19 | self.options.debug = False |
20 | # get hpgl data |
21 | + svg = self.document.getroot() |
22 | + xpathStr = '//sodipodi:namedview' |
23 | + nv = svg.xpath(xpathStr, namespaces=NSS) |
24 | + document_rotate = "0" |
25 | + if nv != []: |
26 | + document_rotate = nv[0].get(self.DOCROTATE) |
27 | + nv[0].set(self.DOCROTATE,"0") |
28 | myHpglEncoder = hpgl_encoder.hpglEncoder(self) |
29 | try: |
30 | self.hpgl, debugObject = myHpglEncoder.getHpgl() |
31 | @@ -56,9 +65,13 @@ |
32 | # issue error if no paths found |
33 | inkex.errormsg(_("No paths where found. Please convert all objects you want to save into paths.")) |
34 | self.hpgl = '' |
35 | + if nv != [] and document_rotate: |
36 | + nv[0].set("inkscape:document_rotation",document_rotate) |
37 | return |
38 | else: |
39 | type, value, traceback = sys.exc_info() |
40 | + if nv != [] and document_rotate: |
41 | + nv[0].set("inkscape:document_rotation",document_rotate) |
42 | raise ValueError, ("", type, value), traceback |
43 | # convert raw HPGL to HPGL |
44 | hpglInit = 'IN' |
45 | @@ -67,6 +80,8 @@ |
46 | if self.options.speed > 0: |
47 | hpglInit += ';VS%d' % self.options.speed |
48 | self.hpgl = hpglInit + self.hpgl + ';SP0;PU0,0;IN; ' |
49 | + if nv != [] and document_rotate: |
50 | + nv[0].set("inkscape:document_rotation",document_rotate) |
51 | |
52 | def output(self): |
53 | # print to file |
54 | |
55 | === modified file 'share/extensions/synfig_output.py' |
56 | --- share/extensions/synfig_output.py 2011-11-25 19:00:24 +0000 |
57 | +++ share/extensions/synfig_output.py 2017-01-24 17:53:20 +0000 |
58 | @@ -1046,6 +1046,11 @@ |
59 | ###### Main Class ######################################### |
60 | class SynfigExport(SynfigPrep): |
61 | def __init__(self): |
62 | + svg = self.document.getroot() |
63 | + xpathStr = '//http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd}:namedview' |
64 | + res = svg.xpath(xpathStr, namespaces=inkex.NSS) |
65 | + self.document_rotate = res[0].get("inkscape:document_rotation") |
66 | + res[0].set("inkscape:document_rotation","0") |
67 | SynfigPrep.__init__(self) |
68 | |
69 | def effect(self): |
70 | @@ -1073,6 +1078,10 @@ |
71 | root_canvas.append(layer) |
72 | |
73 | d.get_root_tree().write(sys.stdout) |
74 | + svg = self.document.getroot() |
75 | + xpathStr = '//http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd}:namedview' |
76 | + res = svg.xpath(xpathStr, namespaces=inkex.NSS) |
77 | + res[0].set("inkscape:document_rotation",self.document_rotate) |
78 | |
79 | def convert_node(self, node, d): |
80 | """Convert an SVG node to a list of Synfig layers""" |
81 | |
82 | === modified file 'src/attributes.cpp' |
83 | --- src/attributes.cpp 2016-10-19 11:11:05 +0000 |
84 | +++ src/attributes.cpp 2017-01-24 17:53:20 +0000 |
85 | @@ -89,6 +89,7 @@ |
86 | {SP_ATTR_INKSCAPE_ZOOM, "inkscape:zoom"}, |
87 | {SP_ATTR_INKSCAPE_CX, "inkscape:cx"}, |
88 | {SP_ATTR_INKSCAPE_CY, "inkscape:cy"}, |
89 | + {SP_ATTR_INKSCAPE_DOCUMENT_ROTATION, "inkscape:document-rotation"}, |
90 | {SP_ATTR_INKSCAPE_WINDOW_WIDTH, "inkscape:window-width"}, |
91 | {SP_ATTR_INKSCAPE_WINDOW_HEIGHT, "inkscape:window-height"}, |
92 | {SP_ATTR_INKSCAPE_WINDOW_X, "inkscape:window-x"}, |
93 | |
94 | === modified file 'src/attributes.h' |
95 | --- src/attributes.h 2016-10-19 11:11:05 +0000 |
96 | +++ src/attributes.h 2017-01-24 17:53:20 +0000 |
97 | @@ -97,6 +97,7 @@ |
98 | SP_ATTR_INKSCAPE_ZOOM, |
99 | SP_ATTR_INKSCAPE_CX, |
100 | SP_ATTR_INKSCAPE_CY, |
101 | + SP_ATTR_INKSCAPE_DOCUMENT_ROTATION, |
102 | SP_ATTR_INKSCAPE_WINDOW_WIDTH, |
103 | SP_ATTR_INKSCAPE_WINDOW_HEIGHT, |
104 | SP_ATTR_INKSCAPE_WINDOW_X, |
105 | |
106 | === modified file 'src/desktop-events.cpp' |
107 | --- src/desktop-events.cpp 2016-08-08 23:57:01 +0000 |
108 | +++ src/desktop-events.cpp 2017-01-24 17:53:20 +0000 |
109 | @@ -155,6 +155,10 @@ |
110 | } |
111 | } |
112 | |
113 | + SPNamedView *namedview = desktop->namedview; |
114 | + if (namedview && namedview->document_rotation) { |
115 | + normal *= Geom::Rotate(Geom::rad_from_deg(namedview->document_rotation * -1)); |
116 | + } |
117 | guide = sp_guideline_new(desktop->guides, NULL, event_dt, normal); |
118 | sp_guideline_set_color(SP_GUIDELINE(guide), desktop->namedview->guidehicolor); |
119 | |
120 | |
121 | === modified file 'src/display/canvas-temporary-item-list.h' |
122 | --- src/display/canvas-temporary-item-list.h 2014-10-08 02:22:03 +0000 |
123 | +++ src/display/canvas-temporary-item-list.h 2017-01-24 17:53:20 +0000 |
124 | @@ -14,6 +14,7 @@ |
125 | |
126 | struct SPCanvasItem; |
127 | class SPDesktop; |
128 | +class SPViewBox; |
129 | |
130 | namespace Inkscape { |
131 | namespace Display { |
132 | |
133 | === modified file 'src/display/sp-canvas.cpp' |
134 | --- src/display/sp-canvas.cpp 2016-12-25 19:26:50 +0000 |
135 | +++ src/display/sp-canvas.cpp 2017-01-24 17:53:20 +0000 |
136 | @@ -29,18 +29,24 @@ |
137 | #include "helper/sp-marshal.h" |
138 | #include <2geom/rect.h> |
139 | #include <2geom/affine.h> |
140 | -#include "display/cairo-utils.h" |
141 | #include "display/sp-canvas.h" |
142 | #include "display/sp-canvas-group.h" |
143 | +#include "display/rendermode.h" |
144 | +#include "display/cairo-utils.h" |
145 | +#include "display/cairo-templates.h" |
146 | +#include "display/drawing-context.h" |
147 | +#include "display/drawing-item.h" |
148 | +#include "display/nr-filter-colormatrix.h" |
149 | +#include "display/canvas-arena.h" |
150 | #include "preferences.h" |
151 | #include "inkscape.h" |
152 | #include "sodipodi-ctrlrect.h" |
153 | #include "cms-system.h" |
154 | -#include "display/rendermode.h" |
155 | -#include "display/cairo-utils.h" |
156 | #include "debug/gdk-event-latency-tracker.h" |
157 | #include "desktop.h" |
158 | #include "color.h" |
159 | +#include <iomanip> |
160 | +#include <glibmm/i18n.h> |
161 | |
162 | using Inkscape::Debug::GdkEventLatencyTracker; |
163 | |
164 | @@ -1888,6 +1894,19 @@ |
165 | return SP_CANVAS_GROUP(_root); |
166 | } |
167 | |
168 | +gdouble grayscale_value_matrix[20] = { |
169 | + 0.21, 0.72, 0.072, 0, 0, |
170 | + 0.21, 0.72, 0.072, 0, 0, |
171 | + 0.21, 0.72, 0.072, 0, 0, |
172 | + 0 , 0 , 0 , 1, 0 |
173 | + }; |
174 | +cairo_surface_t *surface_rotated; |
175 | +cairo_surface_t *surface_origin; |
176 | +cairo_surface_t *surface_measure; |
177 | +double start_angle = 0; |
178 | +bool started = false; |
179 | +bool rotated = false; |
180 | + |
181 | void SPCanvas::scrollTo(double cx, double cy, unsigned int clear, bool is_scrolling) |
182 | { |
183 | GtkAllocation allocation; |
184 | @@ -1910,9 +1929,14 @@ |
185 | cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); |
186 | // Paint the background |
187 | cairo_translate(cr, -ix, -iy); |
188 | + if (rotated) { |
189 | + cairo_translate(cr, dx, dy); |
190 | + rotated = false; |
191 | + } |
192 | cairo_set_source(cr, _background); |
193 | cairo_paint(cr); |
194 | // Copy the old backing store contents |
195 | + |
196 | cairo_set_source_surface(cr, _backing_store, _x0, _y0); |
197 | cairo_rectangle(cr, _x0, _y0, allocation.width, allocation.height); |
198 | cairo_clip(cr); |
199 | @@ -1949,6 +1973,271 @@ |
200 | addIdle(); |
201 | } |
202 | |
203 | +void SPCanvas::startRotateTo(double angle) |
204 | +{ |
205 | + if (!_backing_store || started) { |
206 | + return; |
207 | + } |
208 | + start_angle = angle; |
209 | + started = true; |
210 | + GtkAllocation allocation; |
211 | + gtk_widget_get_allocation(&_widget, &allocation); |
212 | + int half_w = allocation.width/2; |
213 | + int half_h = allocation.height/2; |
214 | + int half_min = std::min(half_w,half_h); |
215 | + |
216 | + cairo_surface_t *new_backing_store = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height); |
217 | + cairo_t *cr = cairo_create(new_backing_store); |
218 | + cairo_arc(cr, half_w, half_h, half_min-15, 0, 2*M_PI); |
219 | + cairo_fill(cr); |
220 | + cairo_set_operator(cr, CAIRO_OPERATOR_IN); |
221 | + cairo_set_source_surface(cr, _backing_store, 0, 0); |
222 | + cairo_paint(cr); |
223 | + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); |
224 | + cairo_arc(cr, half_w, half_h, half_min-16, 0, 2*M_PI); |
225 | + cairo_set_source_rgba (cr, 1, 1, 1, 0.5); |
226 | + cairo_stroke(cr); |
227 | + cairo_destroy(cr); |
228 | + surface_rotated = new_backing_store; |
229 | + |
230 | + cairo_surface_t *new_backing_store_measure = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height); |
231 | + cr = cairo_create(new_backing_store_measure); |
232 | + cairo_arc(cr, half_w, half_h, half_min-15, 0, 2*M_PI); |
233 | + cairo_set_source_rgba (cr, 1, 1, 1, 0.2); |
234 | + cairo_fill(cr); |
235 | + cairo_translate(cr, half_w, half_h); |
236 | + cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); |
237 | + cairo_set_font_size(cr, 10.0); |
238 | + for (gint x = 0; x < 360 ; x++){ |
239 | + gint ang = 360 - x ;//+ 90; |
240 | + if (ang > 180) { |
241 | + ang -= 360; |
242 | + } |
243 | + double rot = (-180.0 + x)*(M_PI/180.); |
244 | + double dist = half_min-9; |
245 | + gint inverse = 1; |
246 | + if((x) < 91 || (x) > 270) { |
247 | + inverse = -1; |
248 | + } |
249 | + if(x%10 == 0) { |
250 | + cairo_rotate(cr, -rot); |
251 | + cairo_text_extents_t extents; |
252 | + std::string s = std::to_string(ang) + "º"; |
253 | + cairo_text_extents(cr, s.c_str(), &extents); |
254 | + //std::cout << extents.width/2 << "extents.x_bearing\n"; |
255 | + cairo_translate(cr, (extents.width/2) * inverse * -1, (dist + ((extents.height/2)* inverse))); |
256 | + if((x) < 91 || (x) > 270) { |
257 | + cairo_rotate(cr, 180*(M_PI/180.0)); |
258 | + } |
259 | + cairo_text_path(cr, s.c_str()); |
260 | + if((x) < 91 || (x) > 270) { |
261 | + cairo_rotate(cr, -180*(M_PI/180.0)); |
262 | + } |
263 | + cairo_translate(cr, (extents.width/2) * inverse , (dist + ((extents.height/2)* inverse)) * -1); |
264 | + cairo_set_source_rgba (cr, 1, 1, 1, 1); |
265 | + cairo_fill(cr); |
266 | + cairo_rotate(cr, rot); |
267 | + } |
268 | + cairo_rotate(cr, x*(M_PI/180.)); |
269 | + if(x%5 == 0) { |
270 | + cairo_move_to(cr, 0, half_min-30); |
271 | + cairo_line_to(cr, 0, half_min-17); |
272 | + } else { |
273 | + cairo_move_to(cr, 0, half_min-20); |
274 | + cairo_line_to(cr, 0, half_min-15); |
275 | + } |
276 | + cairo_line_to(cr, 0, half_min-15); |
277 | + cairo_set_source_rgba (cr, 0, 0, 0, 0.4); |
278 | + cairo_set_line_width (cr,1); |
279 | + cairo_stroke(cr); |
280 | + cairo_rotate(cr, -x*(M_PI/180.)); |
281 | + } |
282 | + cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); |
283 | + cairo_translate(cr, -half_w, -half_h); |
284 | + cairo_arc(cr, half_w, half_h, half_min-30, 0, 2*M_PI); |
285 | + cairo_set_source_rgba (cr, 1, 1, 1, 1); |
286 | + cairo_fill(cr); |
287 | + cairo_translate(cr, half_w, half_h); |
288 | + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); |
289 | + cairo_rotate(cr, start_angle*(M_PI/180.)); |
290 | + cairo_move_to(cr, 0, 0); |
291 | + cairo_line_to(cr, 0, (half_min-17) * -1); |
292 | + cairo_set_source_rgba (cr, 1, 1, 1, 0.25); |
293 | + cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); |
294 | + cairo_set_line_width (cr,5); |
295 | + cairo_stroke(cr); |
296 | + cairo_move_to(cr, 0, 0); |
297 | + cairo_line_to(cr, 0, (half_min-17) * -1); |
298 | + cairo_set_source_rgba (cr, 1, 0, 0, 0.9); |
299 | + cairo_set_line_width (cr,1); |
300 | + cairo_stroke(cr); |
301 | + cairo_rotate(cr, -start_angle*(M_PI/180.)); |
302 | + cairo_destroy(cr); |
303 | + surface_measure = new_backing_store_measure; |
304 | + |
305 | + cairo_surface_t *new_backing_store_grey = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height); |
306 | + cr = cairo_create(new_backing_store_grey); |
307 | + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); |
308 | + cairo_set_source_surface(cr, _backing_store, 0, 0); |
309 | + cairo_paint(cr); |
310 | + Inkscape::Filters::FilterColorMatrix::ColorMatrixMatrix _grayscale_colormatrix = std::vector<gdouble> (grayscale_value_matrix, grayscale_value_matrix + 20); |
311 | + cairo_surface_t *out = ink_cairo_surface_create_identical(new_backing_store_grey); |
312 | + ink_cairo_surface_filter(new_backing_store_grey, out, _grayscale_colormatrix); |
313 | + cairo_set_source_surface(cr, out, 0, 0); |
314 | + cairo_surface_destroy(out); |
315 | + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); |
316 | + cairo_paint(cr); |
317 | + cairo_destroy(cr); |
318 | + surface_origin = new_backing_store_grey; |
319 | +} |
320 | + |
321 | +bool SPCanvas::endRotateTo() |
322 | +{ |
323 | + if (!_backing_store || !started) { |
324 | + return false; |
325 | + } |
326 | + started = false; |
327 | + surface_rotated = NULL; |
328 | + surface_origin = NULL; |
329 | + gtk_widget_queue_draw(GTK_WIDGET(this)); |
330 | + dirtyAll(); |
331 | + addIdle(); |
332 | + rotated = true; |
333 | + return true; |
334 | +} |
335 | + |
336 | +void SPCanvas::clearRotateTo() |
337 | +{ |
338 | + if (!started) { |
339 | + return; |
340 | + } |
341 | + gtk_widget_queue_draw(GTK_WIDGET(this)); |
342 | + dirtyAll(); |
343 | + addIdle(); |
344 | +} |
345 | + |
346 | +void SPCanvas::rotateTo(double angle) |
347 | +{ |
348 | + if (!_backing_store || !started) { |
349 | + return; |
350 | + } |
351 | + GtkAllocation allocation; |
352 | + gtk_widget_get_allocation(&_widget, &allocation); |
353 | + int half_w = allocation.width/2; |
354 | + int half_h = allocation.height/2; |
355 | + int half_min = std::min(half_w,half_h); |
356 | + cairo_surface_t *new_backing_store = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height); |
357 | + cairo_t *cr = cairo_create(new_backing_store); |
358 | + cairo_set_source_surface(cr, surface_origin, 0, 0); |
359 | + cairo_paint(cr); |
360 | + cairo_set_source_rgba (cr, 0, 0, 0, 0.5); |
361 | + cairo_paint(cr); |
362 | + cairo_pattern_t *source_pattern; |
363 | + cairo_matrix_t matrix; |
364 | + source_pattern = cairo_pattern_create_for_surface (surface_rotated); |
365 | + cairo_matrix_init_identity (&matrix); |
366 | + cairo_matrix_translate (&matrix, allocation.width/2.0, allocation.height/2.0); |
367 | + cairo_matrix_rotate (&matrix, Geom::rad_from_deg(angle - start_angle) * -1); |
368 | + cairo_matrix_translate (&matrix, -allocation.width/2.0, -allocation.height/2.0); |
369 | + cairo_pattern_set_matrix (source_pattern, &matrix); |
370 | + cairo_set_source(cr, source_pattern); |
371 | + cairo_paint(cr); |
372 | + cairo_set_source_surface(cr, surface_measure, 0, 0); |
373 | + cairo_paint(cr); |
374 | + cairo_translate(cr, half_w, half_h); |
375 | + cairo_rotate(cr, angle*(M_PI/180.)); |
376 | + cairo_move_to(cr, 0, 0); |
377 | + cairo_line_to(cr, 0, (half_min-17) * -1); |
378 | + cairo_set_source_rgba (cr, 1, 1, 1, 0.25); |
379 | + cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); |
380 | + cairo_set_line_width (cr,5); |
381 | + cairo_stroke(cr); |
382 | + cairo_move_to(cr, 0, 0); |
383 | + cairo_line_to(cr, 0, (half_min-17) * -1); |
384 | + cairo_set_source_rgba (cr, 1, 1, 1, 0.9); |
385 | + cairo_set_line_width (cr,1); |
386 | + cairo_stroke(cr); |
387 | + cairo_move_to(cr, 0, 0); |
388 | + cairo_line_to(cr, 0, (half_min-17) * -1); |
389 | + cairo_set_source_rgba (cr, 1, 0, 0, 0.9); |
390 | + const double dashed[] = {6.0, 3.0}; |
391 | + int len = sizeof(dashed) / sizeof(dashed[0]); |
392 | + cairo_set_dash(cr, dashed, len, 1); |
393 | + cairo_stroke(cr); |
394 | + cairo_translate(cr, -half_w, -half_h); |
395 | + cairo_set_source_rgba (cr, 1, 1, 1, 0.25); |
396 | + cairo_arc(cr, half_w, half_h, 7, 0, 2*M_PI); |
397 | + cairo_fill(cr); |
398 | + cairo_set_source_rgba (cr, 1, 0, 0, 0.7); |
399 | + cairo_arc(cr, half_w, half_h, 5, 0, 2*M_PI); |
400 | + cairo_fill(cr); |
401 | + cairo_translate(cr, half_w, half_h); |
402 | + cairo_rotate(cr, -angle*(M_PI/180.)); |
403 | + cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); |
404 | + cairo_set_font_size(cr, 15.0); |
405 | + cairo_text_extents_t extents; |
406 | + std::ostringstream s; |
407 | + s << _("Original angle ") << std::fixed << std::setprecision(2) << start_angle << "º"; |
408 | + cairo_text_extents(cr, s.str().c_str(), &extents); |
409 | + cairo_translate(cr, half_w - extents.width -15 ,-half_h + 25); |
410 | + cairo_set_source_rgba (cr, 1, 1, 1, 1); |
411 | + cairo_text_path(cr, s.str().c_str()); |
412 | + cairo_fill(cr); |
413 | + cairo_translate(cr, (half_w - extents.width -15) *-1 ,(-half_h + 25) *-1); |
414 | + s.str(""); |
415 | + s << _("New angle ") << std::fixed << std::setprecision(2) << angle << "º"; |
416 | + cairo_text_extents(cr, s.str().c_str(), &extents); |
417 | + cairo_translate(cr, half_w - extents.width -15 ,-half_h + 45); |
418 | + cairo_text_path(cr, s.str().c_str()); |
419 | + cairo_fill(cr); |
420 | + cairo_translate(cr, (half_w - extents.width -15) *-1 ,(-half_h + 45) *-1); |
421 | + s.str(""); |
422 | + s << _("Gap ") << std::fixed << std::setprecision(2) << std::abs(start_angle-angle) << "º"; |
423 | + cairo_text_extents(cr, s.str().c_str(), &extents); |
424 | + cairo_translate(cr, half_w - extents.width -15 ,-half_h + 65); |
425 | + cairo_text_path(cr, s.str().c_str()); |
426 | + cairo_fill(cr); |
427 | + cairo_translate(cr, (half_w - extents.width -15) *-1 ,(-half_h + 65) *-1); |
428 | + cairo_translate(cr, -half_w + 10 ,-half_h + 25); |
429 | + s.str(""); |
430 | + cairo_set_font_size(cr, 12.0); |
431 | + s << _("Normal mode, 1º round step"); |
432 | + cairo_text_path(cr, s.str().c_str()); |
433 | + cairo_fill(cr); |
434 | + cairo_translate(cr, (-half_w +10) * -1 ,(-half_h + 25) * -1); |
435 | + cairo_translate(cr, -half_w + 10 ,-half_h + 40); |
436 | + s.str(""); |
437 | + s << _("+ALT, Fractional degrees"); |
438 | + cairo_text_path(cr, s.str().c_str()); |
439 | + cairo_fill(cr); |
440 | + cairo_translate(cr, (-half_w + 10) * -1 ,(-half_h + 40) * -1); |
441 | + cairo_translate(cr, -half_w + 10 ,-half_h + 55); |
442 | + s.str(""); |
443 | + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); |
444 | + s << _("+CTRL, ") << 180.0/prefs->getInt("/options/rotationsnapsperpi/value", 12) << _("º round step"); |
445 | + cairo_text_path(cr, s.str().c_str()); |
446 | + cairo_fill(cr); |
447 | + cairo_translate(cr, (-half_w + 10) * -1 ,(-half_h + 55) * -1); |
448 | + cairo_translate(cr, -half_w + 10 ,-half_h + 70); |
449 | + s.str(""); |
450 | + s << _("+SHIFT, Reset"); |
451 | + cairo_text_path(cr, s.str().c_str()); |
452 | + cairo_fill(cr); |
453 | + cairo_translate(cr, (-half_w + 10) * -1 ,(-half_h + 70) * -1); |
454 | + cairo_translate(cr, -half_w + 10 ,-half_h + 85); |
455 | + s.str(""); |
456 | + s << _("+CTRL+SHIFT, 0º"); |
457 | + cairo_text_path(cr, s.str().c_str()); |
458 | + cairo_fill(cr); |
459 | + //cairo_translate(cr, (-half_w + 10) * -1 ,(-half_h + 60) * -1); |
460 | + cairo_destroy(cr); |
461 | + cairo_surface_destroy(_backing_store); |
462 | + _backing_store = new_backing_store; |
463 | + cairo_pattern_destroy (source_pattern); |
464 | + gtk_widget_queue_draw(GTK_WIDGET(this)); |
465 | + addIdle(); |
466 | +} |
467 | + |
468 | void SPCanvas::updateNow() |
469 | { |
470 | if (_need_update) { |
471 | |
472 | === modified file 'src/display/sp-canvas.h' |
473 | --- src/display/sp-canvas.h 2016-08-12 04:11:03 +0000 |
474 | +++ src/display/sp-canvas.h 2017-01-24 17:53:20 +0000 |
475 | @@ -72,7 +72,10 @@ |
476 | struct SPCanvas { |
477 | /// Scrolls canvas to specific position (cx and cy are measured in screen pixels). |
478 | void scrollTo(double cx, double cy, unsigned int clear, bool is_scrolling = false); |
479 | - |
480 | + void startRotateTo(double angle); |
481 | + void rotateTo(double angle); |
482 | + bool endRotateTo(); |
483 | + void clearRotateTo(); |
484 | /// Synchronously updates the canvas if necessary. |
485 | void updateNow(); |
486 | |
487 | |
488 | === modified file 'src/document-undo.cpp' |
489 | --- src/document-undo.cpp 2017-01-24 00:02:46 +0000 |
490 | +++ src/document-undo.cpp 2017-01-24 17:53:20 +0000 |
491 | @@ -240,49 +240,52 @@ |
492 | |
493 | gboolean Inkscape::DocumentUndo::undo(SPDocument *doc) |
494 | { |
495 | - using Inkscape::Debug::EventTracker; |
496 | - using Inkscape::Debug::SimpleEvent; |
497 | - |
498 | - gboolean ret; |
499 | - |
500 | - EventTracker<SimpleEvent<Inkscape::Debug::Event::DOCUMENT> > tracker("undo"); |
501 | - |
502 | - g_assert (doc != NULL); |
503 | - g_assert (doc->priv != NULL); |
504 | - g_assert (doc->priv->sensitive); |
505 | - |
506 | - doc->priv->sensitive = FALSE; |
507 | + using Inkscape::Debug::EventTracker; |
508 | + using Inkscape::Debug::SimpleEvent; |
509 | + |
510 | + gboolean ret; |
511 | + |
512 | + EventTracker<SimpleEvent<Inkscape::Debug::Event::DOCUMENT> > tracker("undo"); |
513 | + |
514 | + g_assert (doc != NULL); |
515 | + g_assert (doc->priv != NULL); |
516 | + g_assert (doc->priv->sensitive); |
517 | + |
518 | + doc->priv->sensitive = FALSE; |
519 | doc->priv->seeking = true; |
520 | |
521 | - doc->actionkey.clear(); |
522 | - |
523 | - finish_incomplete_transaction(*doc); |
524 | - |
525 | - if (! doc->priv->undo.empty()) { |
526 | - Inkscape::Event *log = doc->priv->undo.back(); |
527 | - doc->priv->undo.pop_back(); |
528 | - sp_repr_undo_log (log->event); |
529 | - perform_document_update(*doc); |
530 | - |
531 | - doc->priv->redo.push_back(log); |
532 | + doc->actionkey.clear(); |
533 | + |
534 | + finish_incomplete_transaction(*doc); |
535 | + |
536 | + if (! doc->priv->undo.empty()) { |
537 | + Inkscape::Event *log = doc->priv->undo.back(); |
538 | + doc->priv->undo.pop_back(); |
539 | + sp_repr_undo_log (log->event); |
540 | + perform_document_update(*doc); |
541 | + |
542 | + doc->priv->redo.push_back(log); |
543 | |
544 | doc->setModifiedSinceSave(); |
545 | doc->priv->undoStackObservers.notifyUndoEvent(log); |
546 | |
547 | - ret = TRUE; |
548 | - } else { |
549 | - ret = FALSE; |
550 | - } |
551 | - |
552 | - sp_repr_begin_transaction (doc->rdoc); |
553 | - |
554 | - doc->priv->sensitive = TRUE; |
555 | + ret = TRUE; |
556 | + } else { |
557 | + ret = FALSE; |
558 | + } |
559 | + |
560 | + sp_repr_begin_transaction (doc->rdoc); |
561 | + |
562 | + doc->priv->sensitive = TRUE; |
563 | doc->priv->seeking = false; |
564 | |
565 | - if (ret) |
566 | - INKSCAPE.external_change(); |
567 | + if (ret) INKSCAPE.external_change(); |
568 | |
569 | - return ret; |
570 | + SPObject *updated = doc->getRoot(); |
571 | + if (updated) { |
572 | + updated->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); |
573 | + } |
574 | + return ret; |
575 | } |
576 | |
577 | gboolean Inkscape::DocumentUndo::redo(SPDocument *doc) |
578 | |
579 | === modified file 'src/document.cpp' |
580 | --- src/document.cpp 2016-11-28 22:07:00 +0000 |
581 | +++ src/document.cpp 2017-01-24 17:53:20 +0000 |
582 | @@ -386,6 +386,7 @@ |
583 | if (!bordercolor.empty()) { |
584 | rnew->setAttribute("bordercolor", bordercolor.data()); |
585 | } |
586 | + sp_repr_set_svg_double(rnew, "inkscape:document-rotation", 0.); |
587 | sp_repr_set_svg_double(rnew, "borderopacity", |
588 | prefs->getDouble("/template/base/borderopacity", 1.0)); |
589 | sp_repr_set_svg_double(rnew, "objecttolerance", |
590 | @@ -407,6 +408,11 @@ |
591 | rroot->addChild(rnew, NULL); |
592 | // clean up |
593 | Inkscape::GC::release(rnew); |
594 | + } else { |
595 | + Inkscape::XML::Node *nv_repr = sp_item_group_get_child_by_name(document->root, NULL, "sodipodi:namedview")->getRepr(); |
596 | + if (!nv_repr->attribute("inkscape:document-rotation")) { |
597 | + sp_repr_set_svg_double(nv_repr, "inkscape:document-rotation", 0.); |
598 | + } |
599 | } |
600 | |
601 | // Defs |
602 | |
603 | === modified file 'src/extension/internal/cairo-png-out.cpp' |
604 | --- src/extension/internal/cairo-png-out.cpp 2014-03-27 01:33:44 +0000 |
605 | +++ src/extension/internal/cairo-png-out.cpp 2017-01-24 17:53:20 +0000 |
606 | @@ -53,11 +53,10 @@ |
607 | { |
608 | CairoRenderer *renderer; |
609 | CairoRenderContext *ctx; |
610 | - |
611 | + doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p; |
612 | doc->ensureUpToDate(); |
613 | |
614 | /* Start */ |
615 | - |
616 | SPItem *base = doc->getRoot(); |
617 | Inkscape::Drawing drawing; |
618 | unsigned dkey = SPItem::display_key_new(1); |
619 | @@ -77,6 +76,7 @@ |
620 | renderer->destroyContext(ctx); |
621 | |
622 | base->invoke_hide(dkey); |
623 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
624 | /* end */ |
625 | delete renderer; |
626 | |
627 | |
628 | === modified file 'src/extension/internal/cairo-ps-out.cpp' |
629 | --- src/extension/internal/cairo-ps-out.cpp 2016-06-11 17:25:23 +0000 |
630 | +++ src/extension/internal/cairo-ps-out.cpp 2017-01-24 17:53:20 +0000 |
631 | @@ -68,6 +68,7 @@ |
632 | ps_print_document_to_file(SPDocument *doc, gchar const *filename, unsigned int level, bool texttopath, bool omittext, |
633 | bool filtertobitmap, int resolution, const gchar * const exportId, bool exportDrawing, bool exportCanvas, float bleedmargin_px, bool eps = false) |
634 | { |
635 | + doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p; |
636 | doc->ensureUpToDate(); |
637 | |
638 | SPItem *base = NULL; |
639 | @@ -84,9 +85,10 @@ |
640 | pageBoundingBox = !exportDrawing; |
641 | } |
642 | |
643 | - if (!base) |
644 | + if (!base) { |
645 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
646 | return false; |
647 | - |
648 | + } |
649 | Inkscape::Drawing drawing; |
650 | unsigned dkey = SPItem::display_key_new(1); |
651 | base->invoke_show(drawing, dkey, SP_ITEM_SHOW_DISPLAY); |
652 | @@ -115,6 +117,7 @@ |
653 | |
654 | renderer->destroyContext(ctx); |
655 | delete renderer; |
656 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
657 | |
658 | return ret; |
659 | } |
660 | |
661 | === modified file 'src/extension/internal/cairo-renderer-pdf-out.cpp' |
662 | --- src/extension/internal/cairo-renderer-pdf-out.cpp 2016-06-11 17:25:23 +0000 |
663 | +++ src/extension/internal/cairo-renderer-pdf-out.cpp 2017-01-24 17:53:20 +0000 |
664 | @@ -61,6 +61,7 @@ |
665 | bool texttopath, bool omittext, bool filtertobitmap, int resolution, |
666 | const gchar * const exportId, bool exportDrawing, bool exportCanvas, float bleedmargin_px) |
667 | { |
668 | + doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p; |
669 | doc->ensureUpToDate(); |
670 | |
671 | /* Start */ |
672 | @@ -80,6 +81,7 @@ |
673 | } |
674 | |
675 | if (!base) { |
676 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
677 | return false; |
678 | } |
679 | |
680 | @@ -112,7 +114,7 @@ |
681 | |
682 | renderer->destroyContext(ctx); |
683 | delete renderer; |
684 | - |
685 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
686 | return ret; |
687 | } |
688 | |
689 | |
690 | === modified file 'src/extension/internal/emf-inout.cpp' |
691 | --- src/extension/internal/emf-inout.cpp 2016-06-11 17:25:23 +0000 |
692 | +++ src/extension/internal/emf-inout.cpp 2017-01-24 17:53:20 +0000 |
693 | @@ -94,7 +94,7 @@ |
694 | const gchar *oldconst; |
695 | gchar *oldoutput; |
696 | unsigned int ret; |
697 | - |
698 | + doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p; |
699 | doc->ensureUpToDate(); |
700 | |
701 | mod = Inkscape::Extension::get_print(PRINT_EMF); |
702 | @@ -114,6 +114,7 @@ |
703 | /* Print document */ |
704 | ret = mod->begin(doc); |
705 | if (ret) { |
706 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
707 | g_free(oldoutput); |
708 | throw Inkscape::Extension::Output::save_failed(); |
709 | } |
710 | @@ -127,7 +128,7 @@ |
711 | |
712 | mod->set_param_string("destination", oldoutput); |
713 | g_free(oldoutput); |
714 | - |
715 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
716 | return; |
717 | } |
718 | |
719 | |
720 | === modified file 'src/extension/internal/javafx-out.cpp' |
721 | --- src/extension/internal/javafx-out.cpp 2016-07-14 11:17:21 +0000 |
722 | +++ src/extension/internal/javafx-out.cpp 2017-01-24 17:53:20 +0000 |
723 | @@ -843,7 +843,8 @@ |
724 | bool JavaFXOutput::saveDocument(SPDocument *doc, gchar const *filename_utf8) |
725 | { |
726 | reset(); |
727 | - |
728 | + doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p; |
729 | + doc->ensureUpToDate(); |
730 | |
731 | name = Glib::path_get_basename(filename_utf8); |
732 | int pos = name.find('.'); |
733 | @@ -856,12 +857,14 @@ |
734 | //# Lets do the curves first, to get the stats |
735 | |
736 | if (!doTree(doc)) { |
737 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
738 | return false; |
739 | } |
740 | String curveBuf = outbuf; |
741 | outbuf.clear(); |
742 | |
743 | if (!doHeader()) { |
744 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
745 | return false; |
746 | } |
747 | |
748 | @@ -875,6 +878,7 @@ |
749 | doBody(doc, doc->getRoot()); |
750 | |
751 | if (!doTail()) { |
752 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
753 | return false; |
754 | } |
755 | |
756 | @@ -884,6 +888,7 @@ |
757 | FILE *f = Inkscape::IO::fopen_utf8name(filename_utf8, "w"); |
758 | if (!f) |
759 | { |
760 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
761 | err("Could open JavaFX file '%s' for writing", filename_utf8); |
762 | return false; |
763 | } |
764 | @@ -894,7 +899,7 @@ |
765 | } |
766 | |
767 | fclose(f); |
768 | - |
769 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
770 | return true; |
771 | } |
772 | |
773 | |
774 | === modified file 'src/extension/internal/latex-pstricks-out.cpp' |
775 | --- src/extension/internal/latex-pstricks-out.cpp 2012-04-18 07:02:24 +0000 |
776 | +++ src/extension/internal/latex-pstricks-out.cpp 2017-01-24 17:53:20 +0000 |
777 | @@ -49,6 +49,7 @@ |
778 | void LatexOutput::save(Inkscape::Extension::Output * /*mod2*/, SPDocument *doc, gchar const *filename) |
779 | { |
780 | SPPrintContext context; |
781 | + doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p; |
782 | doc->ensureUpToDate(); |
783 | |
784 | Inkscape::Extension::Print *mod = Inkscape::Extension::get_print(SP_MODULE_KEY_PRINT_LATEX); |
785 | @@ -76,6 +77,7 @@ |
786 | |
787 | mod->set_param_string("destination", oldoutput); |
788 | g_free(oldoutput); |
789 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
790 | } |
791 | |
792 | #include "clear-n_.h" |
793 | |
794 | === modified file 'src/extension/internal/odf.cpp' |
795 | --- src/extension/internal/odf.cpp 2016-08-17 07:39:43 +0000 |
796 | +++ src/extension/internal/odf.cpp 2017-01-24 17:53:20 +0000 |
797 | @@ -72,6 +72,7 @@ |
798 | #include "sp-path.h" |
799 | #include "sp-text.h" |
800 | #include "sp-flowtext.h" |
801 | +#include "sp-root.h" |
802 | #include "svg/svg.h" |
803 | #include "text-editing.h" |
804 | #include "util/units.h" |
805 | @@ -2095,7 +2096,8 @@ |
806 | void OdfOutput::save(Inkscape::Extension::Output */*mod*/, SPDocument *doc, gchar const *filename) |
807 | { |
808 | reset(); |
809 | - |
810 | + doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p; |
811 | + doc->ensureUpToDate(); |
812 | documentUri = Inkscape::URI(filename); |
813 | |
814 | ZipFile zf; |
815 | @@ -2104,25 +2106,30 @@ |
816 | if (!writeManifest(zf)) |
817 | { |
818 | g_warning("Failed to write manifest"); |
819 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
820 | return; |
821 | } |
822 | |
823 | if (!writeContent(zf, doc->rroot)) |
824 | { |
825 | g_warning("Failed to write content"); |
826 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
827 | return; |
828 | } |
829 | |
830 | if (!writeMeta(zf)) |
831 | { |
832 | g_warning("Failed to write metafile"); |
833 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
834 | return; |
835 | } |
836 | |
837 | if (!zf.writeFile(filename)) |
838 | { |
839 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
840 | return; |
841 | } |
842 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
843 | } |
844 | |
845 | |
846 | |
847 | === modified file 'src/extension/internal/pov-out.cpp' |
848 | --- src/extension/internal/pov-out.cpp 2016-07-14 11:17:21 +0000 |
849 | +++ src/extension/internal/pov-out.cpp 2017-01-24 17:53:20 +0000 |
850 | @@ -616,11 +616,13 @@ |
851 | void PovOutput::saveDocument(SPDocument *doc, gchar const *filename_utf8) |
852 | { |
853 | reset(); |
854 | - |
855 | + doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p; |
856 | + doc->ensureUpToDate(); |
857 | //###### SAVE IN POV FORMAT TO BUFFER |
858 | //# Lets do the curves first, to get the stats |
859 | if (!doTree(doc)) |
860 | { |
861 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
862 | err("Could not output curves for %s", filename_utf8); |
863 | return; |
864 | } |
865 | @@ -630,6 +632,7 @@ |
866 | |
867 | if (!doHeader()) |
868 | { |
869 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
870 | err("Could not write header for %s", filename_utf8); |
871 | return; |
872 | } |
873 | @@ -638,6 +641,7 @@ |
874 | |
875 | if (!doTail()) |
876 | { |
877 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
878 | err("Could not write footer for %s", filename_utf8); |
879 | return; |
880 | } |
881 | @@ -648,9 +652,11 @@ |
882 | //###### WRITE TO FILE |
883 | Inkscape::IO::dump_fopen_call(filename_utf8, "L"); |
884 | FILE *f = Inkscape::IO::fopen_utf8name(filename_utf8, "w"); |
885 | - if (!f) |
886 | + if (!f){ |
887 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
888 | return; |
889 | - |
890 | + } |
891 | + |
892 | for (String::iterator iter = outbuf.begin() ; iter!=outbuf.end(); ++iter) |
893 | { |
894 | int ch = *iter; |
895 | @@ -658,6 +664,7 @@ |
896 | } |
897 | |
898 | fclose(f); |
899 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
900 | } |
901 | |
902 | |
903 | |
904 | === modified file 'src/extension/internal/wmf-inout.cpp' |
905 | --- src/extension/internal/wmf-inout.cpp 2016-06-11 17:25:23 +0000 |
906 | +++ src/extension/internal/wmf-inout.cpp 2017-01-24 17:53:20 +0000 |
907 | @@ -95,7 +95,7 @@ |
908 | SPPrintContext context; |
909 | const gchar *oldconst; |
910 | gchar *oldoutput; |
911 | - |
912 | + doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p; |
913 | doc->ensureUpToDate(); |
914 | |
915 | mod = Inkscape::Extension::get_print(PRINT_WMF); |
916 | @@ -115,6 +115,7 @@ |
917 | /* Print document */ |
918 | if (mod->begin(doc)) { |
919 | g_free(oldoutput); |
920 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
921 | throw Inkscape::Extension::Output::save_failed(); |
922 | } |
923 | mod->base->invoke_print(&context); |
924 | @@ -127,7 +128,7 @@ |
925 | |
926 | mod->set_param_string("destination", oldoutput); |
927 | g_free(oldoutput); |
928 | - |
929 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
930 | return; |
931 | } |
932 | |
933 | @@ -135,6 +136,8 @@ |
934 | void |
935 | Wmf::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filename) |
936 | { |
937 | + doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p; |
938 | + doc->ensureUpToDate(); |
939 | Inkscape::Extension::Extension * ext; |
940 | |
941 | ext = Inkscape::Extension::db.get(PRINT_WMF); |
942 | |
943 | === modified file 'src/file.cpp' |
944 | --- src/file.cpp 2017-01-24 00:39:06 +0000 |
945 | +++ src/file.cpp 2017-01-24 17:53:20 +0000 |
946 | @@ -293,10 +293,12 @@ |
947 | bool replace_empty) |
948 | { |
949 | SPDesktop *desktop = SP_ACTIVE_DESKTOP; |
950 | + Inkscape::Display::TemporaryItem *page_border_rotated = NULL; |
951 | if (desktop) { |
952 | desktop->setWaitingCursor(); |
953 | + page_border_rotated = sp_document_namedview(desktop->getDocument(), NULL)->page_border_rotated; |
954 | } |
955 | - |
956 | + |
957 | SPDocument *doc = NULL; |
958 | bool cancelled = false; |
959 | try { |
960 | @@ -315,7 +317,6 @@ |
961 | } |
962 | |
963 | if (doc) { |
964 | - |
965 | SPDocument *existing = desktop ? desktop->getDocument() : NULL; |
966 | |
967 | if (existing && existing->virgin && replace_empty) { |
968 | @@ -323,6 +324,7 @@ |
969 | doc->ensureUpToDate(); // TODO this will trigger broken link warnings, etc. |
970 | desktop->change_document(doc); |
971 | doc->emitResizedSignal(doc->getWidth().value("px"), doc->getHeight().value("px")); |
972 | + desktop->remove_temporary_canvasitem(page_border_rotated); |
973 | } else { |
974 | // create a whole new desktop and window |
975 | SPViewWidget *dtw = sp_desktop_widget_new(sp_document_namedview(doc, NULL)); // TODO this will trigger broken link warnings, etc. |
976 | |
977 | === modified file 'src/print.cpp' |
978 | --- src/print.cpp 2012-02-27 23:49:20 +0000 |
979 | +++ src/print.cpp 2017-01-24 17:53:20 +0000 |
980 | @@ -79,6 +79,7 @@ |
981 | void |
982 | sp_print_document(Gtk::Window& parentWindow, SPDocument *doc) |
983 | { |
984 | + doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p; |
985 | doc->ensureUpToDate(); |
986 | |
987 | // Build arena |
988 | @@ -88,6 +89,7 @@ |
989 | Inkscape::UI::Dialog::Print printop(doc,base); |
990 | Gtk::PrintOperationResult res = printop.run(Gtk::PRINT_OPERATION_ACTION_PRINT_DIALOG, parentWindow); |
991 | (void)res; // TODO handle this |
992 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
993 | } |
994 | |
995 | void sp_print_document_to_file(SPDocument *doc, gchar const *filename) |
996 | |
997 | === modified file 'src/sp-namedview.cpp' |
998 | --- src/sp-namedview.cpp 2016-08-03 14:56:48 +0000 |
999 | +++ src/sp-namedview.cpp 2017-01-24 17:53:20 +0000 |
1000 | @@ -19,7 +19,12 @@ |
1001 | #include "event-log.h" |
1002 | #include <2geom/transforms.h> |
1003 | |
1004 | +#include "display/sp-canvas-group.h" |
1005 | +#include "display/canvas-bpath.h" |
1006 | +#include "display/canvas-temporary-item.h" |
1007 | +#include "display/canvas-temporary-item-list.h" |
1008 | #include "display/canvas-grid.h" |
1009 | +#include "display/curve.h" |
1010 | #include "util/units.h" |
1011 | #include "svg/svg-color.h" |
1012 | #include "xml/repr.h" |
1013 | @@ -29,12 +34,15 @@ |
1014 | #include "desktop-events.h" |
1015 | |
1016 | #include "sp-guide.h" |
1017 | +#include "sp-root.h" |
1018 | #include "sp-item-group.h" |
1019 | #include "sp-namedview.h" |
1020 | #include "preferences.h" |
1021 | #include "desktop.h" |
1022 | +#include "selection.h" |
1023 | +#include "object-set.h" |
1024 | +#include "inkscape.h" |
1025 | #include "conn-avoid-ref.h" // for defaultConnSpacing. |
1026 | -#include "sp-root.h" |
1027 | #include <gtkmm/window.h> |
1028 | |
1029 | using Inkscape::DocumentUndo; |
1030 | @@ -72,6 +80,7 @@ |
1031 | this->pagecolor = 0; |
1032 | this->cx = 0; |
1033 | this->pageshadow = 0; |
1034 | + this->document_rotation = 0; |
1035 | this->window_width = 0; |
1036 | this->window_height = 0; |
1037 | this->window_maximized = 0; |
1038 | @@ -92,9 +101,13 @@ |
1039 | this->default_layer_id = 0; |
1040 | |
1041 | this->connector_spacing = defaultConnSpacing; |
1042 | + this->page_border_rotated = NULL; |
1043 | } |
1044 | |
1045 | SPNamedView::~SPNamedView() { |
1046 | + if(!this->getViewList().empty()) { // >0 Desktops |
1047 | + this->getViewList()[0]->remove_temporary_canvasitem(this->page_border_rotated); |
1048 | + } |
1049 | } |
1050 | |
1051 | static void sp_namedview_generate_old_grid(SPNamedView * /*nv*/, SPDocument *document, Inkscape::XML::Node *repr) { |
1052 | @@ -212,6 +225,7 @@ |
1053 | this->readAttr( "inkscape:zoom" ); |
1054 | this->readAttr( "inkscape:cx" ); |
1055 | this->readAttr( "inkscape:cy" ); |
1056 | + this->readAttr( "inkscape:document-rotation" ); |
1057 | this->readAttr( "inkscape:window-width" ); |
1058 | this->readAttr( "inkscape:window-height" ); |
1059 | this->readAttr( "inkscape:window-x" ); |
1060 | @@ -409,6 +423,11 @@ |
1061 | this->cy = value ? g_ascii_strtod(value, NULL) : HUGE_VAL; // HUGE_VAL means not set |
1062 | this->requestModified(SP_OBJECT_MODIFIED_FLAG); |
1063 | break; |
1064 | + case SP_ATTR_INKSCAPE_DOCUMENT_ROTATION: |
1065 | + this->document_rotation = value ? g_ascii_strtod(value, NULL) : 0; |
1066 | + sp_namedview_set_document_rotation(this); |
1067 | + this->requestModified(SP_OBJECT_MODIFIED_FLAG); |
1068 | + break; |
1069 | case SP_ATTR_INKSCAPE_WINDOW_WIDTH: |
1070 | this->window_width = value? atoi(value) : -1; // -1 means not set |
1071 | this->requestModified(SP_OBJECT_MODIFIED_FLAG); |
1072 | @@ -939,6 +958,81 @@ |
1073 | } |
1074 | } |
1075 | |
1076 | +void sp_namedview_doc_rotate_guides(SPNamedView *nv) |
1077 | +{ |
1078 | + bool saved = DocumentUndo::getUndoSensitive(nv->document); |
1079 | + DocumentUndo::setUndoSensitive(nv->document, false); |
1080 | + SPRoot * root = nv->document->getRoot(); |
1081 | + Geom::Point page_center = root->viewBox.midpoint() * root->vbt; |
1082 | + Geom::Affine rot = Geom::identity(); |
1083 | + rot *= Geom::Translate(page_center).inverse(); |
1084 | + rot *= Geom::Rotate(Geom::rad_from_deg((nv->document_rotation - root->get_rotation()) * -1)); |
1085 | + rot *= Geom::Translate(page_center); |
1086 | + for(std::vector<SPGuide *>::iterator it=nv->guides.begin();it!=nv->guides.end();++it ) { |
1087 | + Geom::Point const on_line = (*it)->getPoint() * rot ; |
1088 | + (*it)->moveto(on_line, true); |
1089 | + Geom::Affine rot_normal_affine = Geom::Rotate(Geom::rad_from_deg((nv->document_rotation - root->get_rotation()) * -1)); |
1090 | + Geom::Point const rot_normal = (*it)->getNormal() * rot_normal_affine; |
1091 | + (*it)->set_normal(rot_normal, true); |
1092 | + } |
1093 | + DocumentUndo::setUndoSensitive(nv->document, saved); |
1094 | + nv->document->setModifiedSinceSave(); |
1095 | +} |
1096 | + |
1097 | +void sp_namedview_set_document_rotation(SPNamedView *nv) |
1098 | +{ |
1099 | + if ( nv->document->getRoot()->get_rotation() == nv->document_rotation) return; |
1100 | + if(!nv->getViewList().empty()) { // >0 Desktops |
1101 | + SPDesktop *desktop = nv->getViewList()[0]; |
1102 | + desktop->remove_temporary_canvasitem(nv->page_border_rotated); |
1103 | + SPRoot * root = nv->document->getRoot(); |
1104 | + SPCurve *c = new SPCurve(); |
1105 | + c->moveto(root->viewBox.min()); |
1106 | + c->lineto(Geom::Point(root->viewBox.max()[Geom::X],root->viewBox.min()[Geom::Y])); |
1107 | + c->lineto(Geom::Point(root->viewBox.max()[Geom::X],root->viewBox.max()[Geom::Y])); |
1108 | + c->lineto(Geom::Point(root->viewBox.min()[Geom::X],root->viewBox.max()[Geom::Y])); |
1109 | + c->closepath(); |
1110 | + Geom::Point page_center = root->viewBox.midpoint(); |
1111 | + Geom::PathVector const box = c->get_pathvector(); |
1112 | + Geom::Affine rot = Geom::identity(); |
1113 | + rot *= Geom::Translate(page_center).inverse(); |
1114 | + rot *= Geom::Rotate(Geom::rad_from_deg(nv->document_rotation * -1)); |
1115 | + rot *= Geom::Translate(page_center); |
1116 | + if (nv->document_rotation) { |
1117 | + SPCanvasItem *canvas_border = sp_canvas_bpath_new(desktop->getTempGroup(), c, true); |
1118 | + sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(canvas_border), 0xFF00009A, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); |
1119 | + sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(canvas_border), 0, SP_WIND_RULE_NONZERO); |
1120 | + sp_canvas_item_affine_absolute(canvas_border, rot * root->vbt); |
1121 | + nv->page_border_rotated = desktop->add_temporary_canvasitem(canvas_border, 0); |
1122 | + } |
1123 | + sp_namedview_doc_rotate_guides(nv); |
1124 | + nv->document->getRoot()->set_rotation(nv->document_rotation); |
1125 | + c->unref(); |
1126 | + } |
1127 | + if (nv->document_rotation) { |
1128 | + nv->showborder = FALSE; |
1129 | + } else { |
1130 | + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); |
1131 | + nv->showborder = prefs->getBool("/template/base/showborder", 1.0); |
1132 | + } |
1133 | + |
1134 | + SPDesktop * desktop = SP_ACTIVE_DESKTOP; |
1135 | + if (desktop) { |
1136 | +//TODO: Remove knots of shapes on selected items |
1137 | +// Inkscape::Selection * sel = desktop->getSelection(); |
1138 | +// std::vector<SPItem*> il(sel->items().begin(), sel->items().end()); |
1139 | +// for (std::vector<SPItem*>::const_iterator l = il.begin(); l != il.end(); l++){ |
1140 | +// SPItem *item = *l; |
1141 | +// sel->remove(item->getRepr()); |
1142 | +// sel->add(item->getRepr()); |
1143 | +// } |
1144 | + SPObject *updated = desktop->getDocument()->getRoot(); |
1145 | + if (updated) { |
1146 | + updated->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); |
1147 | + } |
1148 | + } |
1149 | +} |
1150 | + |
1151 | static void sp_namedview_show_single_guide(SPGuide* guide, bool show) |
1152 | { |
1153 | if (show) { |
1154 | @@ -953,6 +1047,8 @@ |
1155 | guide->set_locked(locked, true); |
1156 | } |
1157 | |
1158 | + |
1159 | + |
1160 | void sp_namedview_toggle_guides(SPDocument *doc, Inkscape::XML::Node *repr) |
1161 | { |
1162 | unsigned int v; |
1163 | |
1164 | === modified file 'src/sp-namedview.h' |
1165 | --- src/sp-namedview.h 2016-06-08 08:35:36 +0000 |
1166 | +++ src/sp-namedview.h 2017-01-24 17:53:20 +0000 |
1167 | @@ -21,6 +21,7 @@ |
1168 | #include "snap.h" |
1169 | #include "document.h" |
1170 | #include "util/units.h" |
1171 | +#include "display/sp-canvas.h" |
1172 | #include <vector> |
1173 | |
1174 | namespace Inkscape { |
1175 | @@ -28,6 +29,9 @@ |
1176 | namespace Util { |
1177 | class Unit; |
1178 | } |
1179 | + namespace Display { |
1180 | + class TemporaryItem; |
1181 | + } |
1182 | } |
1183 | |
1184 | typedef unsigned int guint32; |
1185 | @@ -38,7 +42,7 @@ |
1186 | SP_BORDER_LAYER_TOP |
1187 | }; |
1188 | |
1189 | -class SPNamedView : public SPObjectGroup { |
1190 | +class SPNamedView : public SPObjectGroup{ |
1191 | public: |
1192 | SPNamedView(); |
1193 | virtual ~SPNamedView(); |
1194 | @@ -54,6 +58,7 @@ |
1195 | double zoom; |
1196 | double cx; |
1197 | double cy; |
1198 | + double document_rotation; |
1199 | int window_width; |
1200 | int window_height; |
1201 | int window_x; |
1202 | @@ -66,7 +71,7 @@ |
1203 | |
1204 | Inkscape::Util::Unit const *display_units; // Units used for the UI (*not* the same as units of SVG coordinates) |
1205 | Inkscape::Util::Unit const *page_size_units; // Only used in "Custom size" part of Document Properties dialog |
1206 | - |
1207 | + Inkscape::Display::TemporaryItem *page_border_rotated; |
1208 | GQuark default_layer_id; |
1209 | |
1210 | double connector_spacing; |
1211 | @@ -121,7 +126,7 @@ |
1212 | void sp_namedview_window_from_document(SPDesktop *desktop); |
1213 | void sp_namedview_document_from_window(SPDesktop *desktop); |
1214 | void sp_namedview_update_layers_from_document (SPDesktop *desktop); |
1215 | - |
1216 | +void sp_namedview_set_document_rotation(SPNamedView *nv); |
1217 | void sp_namedview_toggle_guides(SPDocument *doc, Inkscape::XML::Node *repr); |
1218 | void sp_namedview_guides_toggle_lock(SPDocument *doc, Inkscape::XML::Node *repr); |
1219 | void sp_namedview_show_grids(SPNamedView *namedview, bool show, bool dirty_document); |
1220 | |
1221 | === modified file 'src/ui/dialog/export.cpp' |
1222 | --- src/ui/dialog/export.cpp 2017-01-04 23:08:02 +0000 |
1223 | +++ src/ui/dialog/export.cpp 2017-01-24 17:53:20 +0000 |
1224 | @@ -978,7 +978,9 @@ |
1225 | |
1226 | SPNamedView *nv = desktop->getNamedView(); |
1227 | SPDocument *doc = desktop->getDocument(); |
1228 | - |
1229 | + Geom::Affine rot = doc->getRoot()->c2p; |
1230 | + doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p; |
1231 | + doc->ensureUpToDate(); |
1232 | bool exportSuccessful = false; |
1233 | |
1234 | bool hide = hide_export.get_active (); |
1235 | @@ -1003,6 +1005,7 @@ |
1236 | |
1237 | if (num < 1) { |
1238 | desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("No items selected.")); |
1239 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
1240 | return; |
1241 | } |
1242 | |
1243 | @@ -1094,6 +1097,7 @@ |
1244 | if (filename.empty()) { |
1245 | desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("You have to enter a filename.")); |
1246 | sp_ui_error_dialog(_("You have to enter a filename")); |
1247 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
1248 | return; |
1249 | } |
1250 | |
1251 | @@ -1110,6 +1114,7 @@ |
1252 | if (!((x1 > x0) && (y1 > y0) && (width > 0) && (height > 0))) { |
1253 | desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("The chosen area to be exported is invalid.")); |
1254 | sp_ui_error_dialog(_("The chosen area to be exported is invalid")); |
1255 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
1256 | return; |
1257 | } |
1258 | |
1259 | @@ -1132,6 +1137,7 @@ |
1260 | |
1261 | g_free(safeDir); |
1262 | g_free(error); |
1263 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
1264 | return; |
1265 | } |
1266 | |
1267 | @@ -1281,6 +1287,7 @@ |
1268 | } |
1269 | } |
1270 | } |
1271 | + doc->getRoot()->c2p *= doc->getRoot()->rotation; |
1272 | } // end of sp_export_export_clicked() |
1273 | |
1274 | /// Called when Browse button is clicked |
1275 | |
1276 | === modified file 'src/ui/tools/tool-base.cpp' |
1277 | --- src/ui/tools/tool-base.cpp 2016-08-09 09:33:34 +0000 |
1278 | +++ src/ui/tools/tool-base.cpp 2017-01-24 17:53:20 +0000 |
1279 | @@ -94,6 +94,7 @@ |
1280 | , _grdrag(NULL) |
1281 | , shape_editor(NULL) |
1282 | , space_panning(false) |
1283 | + , rotating_mode(false) |
1284 | , _delayed_snap_event(NULL) |
1285 | , _dse_callback_in_process(false) |
1286 | , desktop(NULL) |
1287 | @@ -327,99 +328,130 @@ |
1288 | static unsigned int panning = 0; |
1289 | static unsigned int panning_cursor = 0; |
1290 | static unsigned int zoom_rb = 0; |
1291 | + static double angle = 0; |
1292 | |
1293 | Inkscape::Preferences *prefs = Inkscape::Preferences::get(); |
1294 | |
1295 | /// @todo REmove redundant /value in preference keys |
1296 | tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); |
1297 | bool allow_panning = prefs->getBool("/options/spacebarpans/value"); |
1298 | + int rotation_snap = 180.0/prefs->getInt("/options/rotationsnapsperpi/value", 12); |
1299 | gint ret = FALSE; |
1300 | |
1301 | switch (event->type) { |
1302 | - case GDK_2BUTTON_PRESS: |
1303 | - if (panning) { |
1304 | - panning = 0; |
1305 | - sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); |
1306 | - ret = TRUE; |
1307 | - } else { |
1308 | - /* sp_desktop_dialog(); */ |
1309 | - } |
1310 | - break; |
1311 | - |
1312 | - case GDK_BUTTON_PRESS: |
1313 | - // save drag origin |
1314 | - xp = (gint) event->button.x; |
1315 | - yp = (gint) event->button.y; |
1316 | - within_tolerance = true; |
1317 | - |
1318 | - button_w = Geom::Point(event->button.x, event->button.y); |
1319 | - |
1320 | - switch (event->button.button) { |
1321 | - case 1: |
1322 | - if (this->space_panning) { |
1323 | - // When starting panning, make sure there are no snap events pending because these might disable the panning again |
1324 | - if (_uses_snap) { |
1325 | - sp_event_context_discard_delayed_snap_event(this); |
1326 | - } |
1327 | - panning = 1; |
1328 | - |
1329 | - sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), |
1330 | - GDK_KEY_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK |
1331 | - | GDK_POINTER_MOTION_MASK |
1332 | - | GDK_POINTER_MOTION_HINT_MASK, NULL, |
1333 | - event->button.time - 1); |
1334 | - |
1335 | - ret = TRUE; |
1336 | - } |
1337 | - break; |
1338 | - |
1339 | - case 2: |
1340 | - if (event->button.state & GDK_SHIFT_MASK) { |
1341 | - zoom_rb = 2; |
1342 | - } else { |
1343 | - // When starting panning, make sure there are no snap events pending because these might disable the panning again |
1344 | - if (_uses_snap) { |
1345 | - sp_event_context_discard_delayed_snap_event(this); |
1346 | - } |
1347 | - panning = 2; |
1348 | - |
1349 | - sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), |
1350 | - GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
1351 | - | GDK_POINTER_MOTION_HINT_MASK, NULL, |
1352 | - event->button.time - 1); |
1353 | - |
1354 | - } |
1355 | - |
1356 | - ret = TRUE; |
1357 | - break; |
1358 | - |
1359 | - case 3: |
1360 | - if ((event->button.state & GDK_SHIFT_MASK) || (event->button.state & GDK_CONTROL_MASK)) { |
1361 | - // When starting panning, make sure there are no snap events pending because these might disable the panning again |
1362 | - if (_uses_snap) { |
1363 | - sp_event_context_discard_delayed_snap_event(this); |
1364 | - } |
1365 | - panning = 3; |
1366 | - |
1367 | - sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), |
1368 | - GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
1369 | - | GDK_POINTER_MOTION_HINT_MASK, NULL, |
1370 | - event->button.time); |
1371 | - |
1372 | - ret = TRUE; |
1373 | - } else { |
1374 | - sp_event_root_menu_popup(desktop, NULL, event); |
1375 | - } |
1376 | - break; |
1377 | - |
1378 | - default: |
1379 | - break; |
1380 | - } |
1381 | - break; |
1382 | - |
1383 | - case GDK_MOTION_NOTIFY: |
1384 | - if (panning) { |
1385 | - if (panning == 4 && !xp && !yp ) { |
1386 | + case GDK_2BUTTON_PRESS: |
1387 | + if (panning) { |
1388 | + panning = 0; |
1389 | + sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); |
1390 | + ret = TRUE; |
1391 | + } else { |
1392 | + /* sp_desktop_dialog(); */ |
1393 | + } |
1394 | + break; |
1395 | + |
1396 | + case GDK_BUTTON_PRESS: |
1397 | + // save drag origin |
1398 | + xp = (gint) event->button.x; |
1399 | + yp = (gint) event->button.y; |
1400 | + within_tolerance = true; |
1401 | + |
1402 | + button_w = Geom::Point(event->button.x, event->button.y); |
1403 | + switch (event->button.button) { |
1404 | + case 1: |
1405 | + if (this->space_panning) { |
1406 | + // When starting panning, make sure there are no snap events pending because these might disable the panning again |
1407 | + if (_uses_snap) { |
1408 | + sp_event_context_discard_delayed_snap_event(this); |
1409 | + } |
1410 | + panning = 1; |
1411 | + |
1412 | + sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), |
1413 | + GDK_KEY_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK |
1414 | + | GDK_POINTER_MOTION_MASK |
1415 | + | GDK_POINTER_MOTION_HINT_MASK, NULL, |
1416 | + event->button.time - 1); |
1417 | + |
1418 | + ret = TRUE; |
1419 | + } |
1420 | + desktop->canvas->clearRotateTo(); |
1421 | + this->rotating_mode = false; |
1422 | + break; |
1423 | + |
1424 | + case 2: |
1425 | + if (event->button.state & GDK_CONTROL_MASK) { |
1426 | + sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); |
1427 | + desktop->canvas->startRotateTo(desktop->namedview->document_rotation); |
1428 | + this->rotating_mode = true; |
1429 | + this->message_context->set(Inkscape::INFORMATION_MESSAGE, |
1430 | + _("<b>MMB + mouse move</b> to rotate canvas, use modifiers on screen to change snaps")); |
1431 | + } else { |
1432 | + if (event->button.state & GDK_SHIFT_MASK) { |
1433 | + zoom_rb = 2; |
1434 | + } else { |
1435 | + // When starting panning, make sure there are no snap events pending because these might disable the panning again |
1436 | + if (_uses_snap) { |
1437 | + sp_event_context_discard_delayed_snap_event(this); |
1438 | + } |
1439 | + panning = 2; |
1440 | + |
1441 | + sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), |
1442 | + GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
1443 | + | GDK_POINTER_MOTION_HINT_MASK, NULL, |
1444 | + event->button.time - 1); |
1445 | + } |
1446 | + ret = TRUE; |
1447 | + } |
1448 | + ret = TRUE; |
1449 | + break; |
1450 | + |
1451 | + case 3: |
1452 | + if ((event->button.state & GDK_SHIFT_MASK) || (event->button.state & GDK_CONTROL_MASK)) { |
1453 | + // When starting panning, make sure there are no snap events pending because these might disable the panning again |
1454 | + if (_uses_snap) { |
1455 | + sp_event_context_discard_delayed_snap_event(this); |
1456 | + } |
1457 | + panning = 3; |
1458 | + |
1459 | + sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), |
1460 | + GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
1461 | + | GDK_POINTER_MOTION_HINT_MASK, NULL, |
1462 | + event->button.time); |
1463 | + |
1464 | + ret = TRUE; |
1465 | + } else if( !this->space_panning) { |
1466 | + sp_event_root_menu_popup(desktop, NULL, event); |
1467 | + } |
1468 | + ret = TRUE; |
1469 | + desktop->canvas->clearRotateTo(); |
1470 | + this->rotating_mode = false; |
1471 | + break; |
1472 | + |
1473 | + default: |
1474 | + break; |
1475 | + } |
1476 | + break; |
1477 | + |
1478 | + case GDK_MOTION_NOTIFY: |
1479 | + if (this->rotating_mode) { |
1480 | + button_w = Geom::Point(event->motion.x, event->motion.y); |
1481 | + Geom::Point const motion_dt(desktop->doc2dt(desktop->w2d(button_w))); |
1482 | + Geom::Rect view = desktop->get_display_area(); |
1483 | + Geom::Point view_center = desktop->doc2dt(view.midpoint()); |
1484 | + Geom::Ray center_ray(motion_dt, view_center); |
1485 | + angle = Geom::deg_from_rad(center_ray.angle()) - 90; |
1486 | + if (event->motion.state & GDK_SHIFT_MASK && event->motion.state & GDK_CONTROL_MASK) { |
1487 | + angle = 0; |
1488 | + } else if(event->motion.state & GDK_CONTROL_MASK) { |
1489 | + angle = floor(angle/rotation_snap) * rotation_snap; |
1490 | + } else if (event->motion.state & GDK_SHIFT_MASK) { |
1491 | + angle = desktop->namedview->document_rotation; |
1492 | + } else if (event->motion.state & GDK_MOD1_MASK) { |
1493 | + //Decimal raw angle |
1494 | + } else { |
1495 | + angle = floor(angle); |
1496 | + } |
1497 | + desktop->canvas->rotateTo(angle); |
1498 | + } else if (panning == 4 && !xp && !yp ) { |
1499 | // <Space> + mouse panning started, save location and grab canvas |
1500 | xp = event->motion.x; |
1501 | yp = event->motion.y; |
1502 | @@ -431,401 +463,465 @@ |
1503 | | GDK_POINTER_MOTION_HINT_MASK, NULL, |
1504 | event->motion.time - 1); |
1505 | } |
1506 | - |
1507 | - if ((panning == 2 && !(event->motion.state & GDK_BUTTON2_MASK)) |
1508 | - || (panning == 1 && !(event->motion.state & GDK_BUTTON1_MASK)) |
1509 | - || (panning == 3 && !(event->motion.state & GDK_BUTTON3_MASK))) { |
1510 | - /* Gdk seems to lose button release for us sometimes :-( */ |
1511 | - panning = 0; |
1512 | - sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); |
1513 | - ret = TRUE; |
1514 | - } else { |
1515 | + if (panning && !this->rotating_mode) { |
1516 | + if ((panning == 2 && !(event->motion.state & GDK_BUTTON2_MASK)) |
1517 | + || (panning == 1 && !(event->motion.state & GDK_BUTTON1_MASK)) |
1518 | + || (panning == 3 && !(event->motion.state & GDK_BUTTON3_MASK))) { |
1519 | + /* Gdk seems to lose button release for us sometimes :-( */ |
1520 | + panning = 0; |
1521 | + sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); |
1522 | + ret = TRUE; |
1523 | + } else { |
1524 | + if (within_tolerance && (abs((gint) event->motion.x - xp) |
1525 | + < tolerance) && (abs((gint) event->motion.y - yp) |
1526 | + < tolerance)) { |
1527 | + // do not drag if we're within tolerance from origin |
1528 | + break; |
1529 | + } |
1530 | + |
1531 | + // Once the user has moved farther than tolerance from |
1532 | + // the original location (indicating they intend to move |
1533 | + // the object, not click), then always process the motion |
1534 | + // notify coordinates as given (no snapping back to origin) |
1535 | + within_tolerance = false; |
1536 | + |
1537 | + // gobble subsequent motion events to prevent "sticking" |
1538 | + // when scrolling is slow |
1539 | + gobble_motion_events(panning == 2 ? GDK_BUTTON2_MASK : (panning |
1540 | + == 1 ? GDK_BUTTON1_MASK : GDK_BUTTON3_MASK)); |
1541 | + |
1542 | + if (panning_cursor == 0) { |
1543 | + panning_cursor = 1; |
1544 | + this->sp_event_context_set_cursor(GDK_FLEUR); |
1545 | + } |
1546 | + |
1547 | + Geom::Point const motion_w(event->motion.x, event->motion.y); |
1548 | + Geom::Point const moved_w(motion_w - button_w); |
1549 | + this->desktop->scroll_world(moved_w, true); // we're still scrolling, do not redraw |
1550 | + ret = TRUE; |
1551 | + } |
1552 | + } else if (zoom_rb) { |
1553 | + Geom::Point const motion_w(event->motion.x, event->motion.y); |
1554 | + Geom::Point const motion_dt(desktop->w2d(motion_w)); |
1555 | + |
1556 | if (within_tolerance && (abs((gint) event->motion.x - xp) |
1557 | < tolerance) && (abs((gint) event->motion.y - yp) |
1558 | < tolerance)) { |
1559 | - // do not drag if we're within tolerance from origin |
1560 | - break; |
1561 | + break; // do not drag if we're within tolerance from origin |
1562 | } |
1563 | |
1564 | - // Once the user has moved farther than tolerance from |
1565 | - // the original location (indicating they intend to move |
1566 | - // the object, not click), then always process the motion |
1567 | - // notify coordinates as given (no snapping back to origin) |
1568 | + // Once the user has moved farther than tolerance from the original location |
1569 | + // (indicating they intend to move the object, not click), then always process the |
1570 | + // motion notify coordinates as given (no snapping back to origin) |
1571 | within_tolerance = false; |
1572 | |
1573 | - // gobble subsequent motion events to prevent "sticking" |
1574 | - // when scrolling is slow |
1575 | - gobble_motion_events(panning == 2 ? GDK_BUTTON2_MASK : (panning |
1576 | - == 1 ? GDK_BUTTON1_MASK : GDK_BUTTON3_MASK)); |
1577 | - |
1578 | - if (panning_cursor == 0) { |
1579 | - panning_cursor = 1; |
1580 | - this->sp_event_context_set_cursor(GDK_FLEUR); |
1581 | - } |
1582 | - |
1583 | - Geom::Point const motion_w(event->motion.x, event->motion.y); |
1584 | - Geom::Point const moved_w(motion_w - button_w); |
1585 | - this->desktop->scroll_world(moved_w, true); // we're still scrolling, do not redraw |
1586 | + if (Inkscape::Rubberband::get(desktop)->is_started()) { |
1587 | + Inkscape::Rubberband::get(desktop)->move(motion_dt); |
1588 | + } else { |
1589 | + Inkscape::Rubberband::get(desktop)->start(desktop, motion_dt); |
1590 | + } |
1591 | + |
1592 | + if (zoom_rb == 2) { |
1593 | + gobble_motion_events(GDK_BUTTON2_MASK); |
1594 | + } |
1595 | + } |
1596 | + break; |
1597 | + |
1598 | + case GDK_BUTTON_RELEASE: |
1599 | + if (this->rotating_mode && event->button.button == 2) { |
1600 | + desktop->canvas->clearRotateTo(); |
1601 | + this->rotating_mode = false; |
1602 | ret = TRUE; |
1603 | - } |
1604 | - } else if (zoom_rb) { |
1605 | - Geom::Point const motion_w(event->motion.x, event->motion.y); |
1606 | - Geom::Point const motion_dt(desktop->w2d(motion_w)); |
1607 | - |
1608 | - if (within_tolerance && (abs((gint) event->motion.x - xp) |
1609 | - < tolerance) && (abs((gint) event->motion.y - yp) |
1610 | - < tolerance)) { |
1611 | - break; // do not drag if we're within tolerance from origin |
1612 | - } |
1613 | - |
1614 | - // Once the user has moved farther than tolerance from the original location |
1615 | - // (indicating they intend to move the object, not click), then always process the |
1616 | - // motion notify coordinates as given (no snapping back to origin) |
1617 | - within_tolerance = false; |
1618 | - |
1619 | - if (Inkscape::Rubberband::get(desktop)->is_started()) { |
1620 | - Inkscape::Rubberband::get(desktop)->move(motion_dt); |
1621 | + if (desktop->canvas->endRotateTo()) { |
1622 | + sp_repr_set_svg_double(desktop->namedview->getRepr(), "inkscape:document-rotation", angle); |
1623 | + } |
1624 | } else { |
1625 | - Inkscape::Rubberband::get(desktop)->start(desktop, motion_dt); |
1626 | - } |
1627 | - |
1628 | - if (zoom_rb == 2) { |
1629 | - gobble_motion_events(GDK_BUTTON2_MASK); |
1630 | - } |
1631 | - } |
1632 | - break; |
1633 | - |
1634 | - case GDK_BUTTON_RELEASE: |
1635 | - xp = yp = 0; |
1636 | - |
1637 | - if (panning_cursor == 1) { |
1638 | - panning_cursor = 0; |
1639 | - GtkWidget *w = GTK_WIDGET(this->desktop->getCanvas()); |
1640 | - gdk_window_set_cursor(gtk_widget_get_window (w), this->cursor); |
1641 | - } |
1642 | - |
1643 | - if (within_tolerance && (panning || zoom_rb)) { |
1644 | - zoom_rb = 0; |
1645 | + xp = yp = 0; |
1646 | + if (panning_cursor == 1) { |
1647 | + panning_cursor = 0; |
1648 | + GtkWidget *w = GTK_WIDGET(this->desktop->getCanvas()); |
1649 | + gdk_window_set_cursor(gtk_widget_get_window (w), this->cursor); |
1650 | + } |
1651 | + |
1652 | + if (within_tolerance && (panning || zoom_rb)) { |
1653 | + zoom_rb = 0; |
1654 | + |
1655 | + if (panning) { |
1656 | + panning = 0; |
1657 | + sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), |
1658 | + event->button.time); |
1659 | + } |
1660 | + |
1661 | + Geom::Point const event_w(event->button.x, event->button.y); |
1662 | + Geom::Point const event_dt(desktop->w2d(event_w)); |
1663 | + |
1664 | + double const zoom_inc = prefs->getDoubleLimited( |
1665 | + "/options/zoomincrement/value", M_SQRT2, 1.01, 10); |
1666 | + |
1667 | + desktop->zoom_relative_keep_point(event_dt, (event->button.state |
1668 | + & GDK_SHIFT_MASK) ? 1 / zoom_inc : zoom_inc); |
1669 | + |
1670 | + desktop->updateNow(); |
1671 | + ret = TRUE; |
1672 | + } else if (panning == event->button.button) { |
1673 | + panning = 0; |
1674 | + sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), |
1675 | + event->button.time); |
1676 | + |
1677 | + // in slow complex drawings, some of the motion events are lost; |
1678 | + // to make up for this, we scroll it once again to the button-up event coordinates |
1679 | + // (i.e. canvas will always get scrolled all the way to the mouse release point, |
1680 | + // even if few intermediate steps were visible) |
1681 | + Geom::Point const motion_w(event->button.x, event->button.y); |
1682 | + Geom::Point const moved_w(motion_w - button_w); |
1683 | + |
1684 | + this->desktop->scroll_world(moved_w); |
1685 | + desktop->updateNow(); |
1686 | + ret = TRUE; |
1687 | + } else if (zoom_rb == event->button.button) { |
1688 | + zoom_rb = 0; |
1689 | + |
1690 | + Geom::OptRect const b = Inkscape::Rubberband::get(desktop)->getRectangle(); |
1691 | + Inkscape::Rubberband::get(desktop)->stop(); |
1692 | + |
1693 | + if (b && !within_tolerance) { |
1694 | + desktop->set_display_area(*b, 10); |
1695 | + } |
1696 | + |
1697 | + ret = TRUE; |
1698 | + } |
1699 | + if (this->rotating_mode && event->button.button != 3) { |
1700 | + desktop->canvas->clearRotateTo(); |
1701 | + this->rotating_mode = false; |
1702 | + ret = TRUE; |
1703 | + desktop->canvas->endRotateTo(); |
1704 | + } |
1705 | + } |
1706 | + break; |
1707 | + |
1708 | + case GDK_KEY_PRESS: { |
1709 | + double const acceleration = prefs->getDoubleLimited( |
1710 | + "/options/scrollingacceleration/value", 0, 0, 6); |
1711 | + int const key_scroll = prefs->getIntLimited("/options/keyscroll/value", |
1712 | + 10, 0, 1000); |
1713 | + |
1714 | + if (this->rotating_mode && |
1715 | + get_group0_keyval(&event->key) != GDK_KEY_space && |
1716 | + get_group0_keyval(&event->key) != GDK_KEY_Shift_L && |
1717 | + get_group0_keyval(&event->key) != GDK_KEY_Shift_R && |
1718 | + get_group0_keyval(&event->key) != GDK_KEY_Control_L && |
1719 | + get_group0_keyval(&event->key) != GDK_KEY_Control_R && |
1720 | + get_group0_keyval(&event->key) != GDK_KEY_Alt_L && |
1721 | + get_group0_keyval(&event->key) != GDK_KEY_Alt_R ) |
1722 | + { |
1723 | + desktop->canvas->clearRotateTo(); |
1724 | + this->rotating_mode = false; |
1725 | + ret = TRUE; |
1726 | + desktop->canvas->endRotateTo(); |
1727 | + break; |
1728 | + } |
1729 | + |
1730 | + switch (get_group0_keyval(&event->key)) { |
1731 | + // GDK insists on stealing these keys (F1 for no idea what, tab for cycling widgets |
1732 | + // in the editing window). So we resteal them back and run our regular shortcut |
1733 | + // invoker on them. |
1734 | + unsigned int shortcut; |
1735 | + case GDK_KEY_Tab: |
1736 | + case GDK_KEY_ISO_Left_Tab: |
1737 | + case GDK_KEY_F1: |
1738 | + shortcut = get_group0_keyval(&event->key); |
1739 | + |
1740 | + if (event->key.state & GDK_SHIFT_MASK) { |
1741 | + shortcut |= SP_SHORTCUT_SHIFT_MASK; |
1742 | + } |
1743 | + |
1744 | + if (event->key.state & GDK_CONTROL_MASK) { |
1745 | + shortcut |= SP_SHORTCUT_CONTROL_MASK; |
1746 | + } |
1747 | + |
1748 | + if (event->key.state & GDK_MOD1_MASK) { |
1749 | + shortcut |= SP_SHORTCUT_ALT_MASK; |
1750 | + } |
1751 | + |
1752 | + ret = sp_shortcut_invoke(shortcut, desktop); |
1753 | + break; |
1754 | + |
1755 | + case GDK_KEY_Q: |
1756 | + case GDK_KEY_q: |
1757 | + if (desktop->quick_zoomed()) { |
1758 | + ret = TRUE; |
1759 | + } |
1760 | + if (!MOD__SHIFT(event) && !MOD__CTRL(event) && !MOD__ALT(event)) { |
1761 | + desktop->zoom_quick(true); |
1762 | + ret = TRUE; |
1763 | + } |
1764 | + break; |
1765 | + |
1766 | + case GDK_KEY_W: |
1767 | + case GDK_KEY_w: |
1768 | + case GDK_KEY_F4: |
1769 | + /* Close view */ |
1770 | + if (MOD__CTRL_ONLY(event)) { |
1771 | + sp_ui_close_view(NULL); |
1772 | + ret = TRUE; |
1773 | + } |
1774 | + break; |
1775 | + |
1776 | + case GDK_KEY_Left: // Ctrl Left |
1777 | + case GDK_KEY_KP_Left: |
1778 | + case GDK_KEY_KP_4: |
1779 | + if (MOD__CTRL_ONLY(event)) { |
1780 | + int i = (int) floor(key_scroll * accelerate_scroll(event, |
1781 | + acceleration, desktop->getCanvas())); |
1782 | + |
1783 | + gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK); |
1784 | + this->desktop->scroll_world(i, 0); |
1785 | + ret = TRUE; |
1786 | + } |
1787 | + break; |
1788 | + |
1789 | + case GDK_KEY_Up: // Ctrl Up |
1790 | + case GDK_KEY_KP_Up: |
1791 | + case GDK_KEY_KP_8: |
1792 | + if (MOD__CTRL_ONLY(event)) { |
1793 | + int i = (int) floor(key_scroll * accelerate_scroll(event, |
1794 | + acceleration, desktop->getCanvas())); |
1795 | + |
1796 | + gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK); |
1797 | + this->desktop->scroll_world(0, i); |
1798 | + ret = TRUE; |
1799 | + } |
1800 | + break; |
1801 | + |
1802 | + case GDK_KEY_Right: // Ctrl Right |
1803 | + case GDK_KEY_KP_Right: |
1804 | + case GDK_KEY_KP_6: |
1805 | + if (MOD__CTRL_ONLY(event)) { |
1806 | + int i = (int) floor(key_scroll * accelerate_scroll(event, |
1807 | + acceleration, desktop->getCanvas())); |
1808 | + |
1809 | + gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK); |
1810 | + this->desktop->scroll_world(-i, 0); |
1811 | + ret = TRUE; |
1812 | + } |
1813 | + break; |
1814 | + |
1815 | + case GDK_KEY_Down: // Ctrl Down |
1816 | + case GDK_KEY_KP_Down: |
1817 | + case GDK_KEY_KP_2: |
1818 | + if (MOD__CTRL_ONLY(event)) { |
1819 | + int i = (int) floor(key_scroll * accelerate_scroll(event, |
1820 | + acceleration, desktop->getCanvas())); |
1821 | + |
1822 | + gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK); |
1823 | + this->desktop->scroll_world(0, -i); |
1824 | + ret = TRUE; |
1825 | + } |
1826 | + break; |
1827 | + |
1828 | + case GDK_KEY_Menu: |
1829 | + sp_event_root_menu_popup(desktop, NULL, event); |
1830 | + ret = TRUE; |
1831 | + break; |
1832 | + |
1833 | + case GDK_KEY_F10: |
1834 | + if (MOD__SHIFT_ONLY(event)) { |
1835 | + sp_event_root_menu_popup(desktop, NULL, event); |
1836 | + ret = TRUE; |
1837 | + } |
1838 | + break; |
1839 | + |
1840 | + case GDK_KEY_space: |
1841 | + if (event->key.state & GDK_CONTROL_MASK) { |
1842 | + sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); |
1843 | + desktop->canvas->startRotateTo(desktop->namedview->document_rotation); |
1844 | + this->rotating_mode = true; |
1845 | + this->message_context->set(Inkscape::INFORMATION_MESSAGE, |
1846 | + _("<b>Space+mouse move</b> to rotate canvas, use modifiers on screen to change snaps")); |
1847 | + } else { |
1848 | + within_tolerance = true; |
1849 | + xp = yp = 0; |
1850 | + if (!allow_panning) break; |
1851 | + panning = 4; |
1852 | + this->space_panning = true; |
1853 | + this->message_context->set(Inkscape::INFORMATION_MESSAGE, |
1854 | + _("<b>Space+mouse move</b> to pan canvas")); |
1855 | + } |
1856 | + ret = TRUE; |
1857 | + break; |
1858 | + |
1859 | + case GDK_KEY_z: |
1860 | + case GDK_KEY_Z: |
1861 | + if (MOD__ALT_ONLY(event)) { |
1862 | + desktop->zoom_grab_focus(); |
1863 | + ret = TRUE; |
1864 | + } |
1865 | + break; |
1866 | + |
1867 | + default: |
1868 | + break; |
1869 | + } |
1870 | + } |
1871 | + break; |
1872 | + |
1873 | + case GDK_KEY_RELEASE: |
1874 | + if (this->rotating_mode && |
1875 | + get_group0_keyval(&event->key) != GDK_KEY_space && |
1876 | + get_group0_keyval(&event->key) != GDK_KEY_Shift_L && |
1877 | + get_group0_keyval(&event->key) != GDK_KEY_Shift_R && |
1878 | + get_group0_keyval(&event->key) != GDK_KEY_Control_L && |
1879 | + get_group0_keyval(&event->key) != GDK_KEY_Control_R && |
1880 | + get_group0_keyval(&event->key) != GDK_KEY_Alt_L && |
1881 | + get_group0_keyval(&event->key) != GDK_KEY_Alt_R ) |
1882 | + { |
1883 | + desktop->canvas->clearRotateTo(); |
1884 | + this->rotating_mode = false; |
1885 | + ret = TRUE; |
1886 | + desktop->canvas->endRotateTo(); |
1887 | + break; |
1888 | + } |
1889 | + |
1890 | + // Stop panning on any key release |
1891 | + if (this->space_panning) { |
1892 | + this->space_panning = false; |
1893 | + this->message_context->clear(); |
1894 | + } |
1895 | |
1896 | if (panning) { |
1897 | panning = 0; |
1898 | + xp = yp = 0; |
1899 | + |
1900 | sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), |
1901 | - event->button.time); |
1902 | - } |
1903 | - |
1904 | - Geom::Point const event_w(event->button.x, event->button.y); |
1905 | - Geom::Point const event_dt(desktop->w2d(event_w)); |
1906 | - |
1907 | - double const zoom_inc = prefs->getDoubleLimited( |
1908 | - "/options/zoomincrement/value", M_SQRT2, 1.01, 10); |
1909 | - |
1910 | - desktop->zoom_relative_keep_point(event_dt, (event->button.state |
1911 | - & GDK_SHIFT_MASK) ? 1 / zoom_inc : zoom_inc); |
1912 | - |
1913 | - desktop->updateNow(); |
1914 | - ret = TRUE; |
1915 | - } else if (panning == event->button.button) { |
1916 | - panning = 0; |
1917 | - sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), |
1918 | - event->button.time); |
1919 | - |
1920 | - // in slow complex drawings, some of the motion events are lost; |
1921 | - // to make up for this, we scroll it once again to the button-up event coordinates |
1922 | - // (i.e. canvas will always get scrolled all the way to the mouse release point, |
1923 | - // even if few intermediate steps were visible) |
1924 | - Geom::Point const motion_w(event->button.x, event->button.y); |
1925 | - Geom::Point const moved_w(motion_w - button_w); |
1926 | - |
1927 | - this->desktop->scroll_world(moved_w); |
1928 | - desktop->updateNow(); |
1929 | - ret = TRUE; |
1930 | - } else if (zoom_rb == event->button.button) { |
1931 | - zoom_rb = 0; |
1932 | - |
1933 | - Geom::OptRect const b = Inkscape::Rubberband::get(desktop)->getRectangle(); |
1934 | - Inkscape::Rubberband::get(desktop)->stop(); |
1935 | - |
1936 | - if (b && !within_tolerance) { |
1937 | - desktop->set_display_area(*b, 10); |
1938 | - } |
1939 | - |
1940 | - ret = TRUE; |
1941 | - } |
1942 | - break; |
1943 | - |
1944 | - case GDK_KEY_PRESS: { |
1945 | - double const acceleration = prefs->getDoubleLimited( |
1946 | - "/options/scrollingacceleration/value", 0, 0, 6); |
1947 | - int const key_scroll = prefs->getIntLimited("/options/keyscroll/value", |
1948 | - 10, 0, 1000); |
1949 | - |
1950 | - switch (get_group0_keyval(&event->key)) { |
1951 | - // GDK insists on stealing these keys (F1 for no idea what, tab for cycling widgets |
1952 | - // in the editing window). So we resteal them back and run our regular shortcut |
1953 | - // invoker on them. |
1954 | - unsigned int shortcut; |
1955 | - case GDK_KEY_Tab: |
1956 | - case GDK_KEY_ISO_Left_Tab: |
1957 | - case GDK_KEY_F1: |
1958 | - shortcut = get_group0_keyval(&event->key); |
1959 | - |
1960 | - if (event->key.state & GDK_SHIFT_MASK) { |
1961 | - shortcut |= SP_SHORTCUT_SHIFT_MASK; |
1962 | - } |
1963 | - |
1964 | - if (event->key.state & GDK_CONTROL_MASK) { |
1965 | - shortcut |= SP_SHORTCUT_CONTROL_MASK; |
1966 | - } |
1967 | - |
1968 | - if (event->key.state & GDK_MOD1_MASK) { |
1969 | - shortcut |= SP_SHORTCUT_ALT_MASK; |
1970 | - } |
1971 | - |
1972 | - ret = sp_shortcut_invoke(shortcut, desktop); |
1973 | - break; |
1974 | - |
1975 | - case GDK_KEY_Q: |
1976 | - case GDK_KEY_q: |
1977 | - if (desktop->quick_zoomed()) { |
1978 | - ret = TRUE; |
1979 | - } |
1980 | - if (!MOD__SHIFT(event) && !MOD__CTRL(event) && !MOD__ALT(event)) { |
1981 | - desktop->zoom_quick(true); |
1982 | - ret = TRUE; |
1983 | - } |
1984 | - break; |
1985 | - |
1986 | - case GDK_KEY_W: |
1987 | - case GDK_KEY_w: |
1988 | - case GDK_KEY_F4: |
1989 | - /* Close view */ |
1990 | - if (MOD__CTRL_ONLY(event)) { |
1991 | - sp_ui_close_view(NULL); |
1992 | - ret = TRUE; |
1993 | - } |
1994 | - break; |
1995 | - |
1996 | - case GDK_KEY_Left: // Ctrl Left |
1997 | - case GDK_KEY_KP_Left: |
1998 | - case GDK_KEY_KP_4: |
1999 | - if (MOD__CTRL_ONLY(event)) { |
2000 | - int i = (int) floor(key_scroll * accelerate_scroll(event, |
2001 | - acceleration, desktop->getCanvas())); |
2002 | - |
2003 | - gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK); |
2004 | - this->desktop->scroll_world(i, 0); |
2005 | - ret = TRUE; |
2006 | - } |
2007 | - break; |
2008 | - |
2009 | - case GDK_KEY_Up: // Ctrl Up |
2010 | - case GDK_KEY_KP_Up: |
2011 | - case GDK_KEY_KP_8: |
2012 | - if (MOD__CTRL_ONLY(event)) { |
2013 | - int i = (int) floor(key_scroll * accelerate_scroll(event, |
2014 | - acceleration, desktop->getCanvas())); |
2015 | - |
2016 | - gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK); |
2017 | - this->desktop->scroll_world(0, i); |
2018 | - ret = TRUE; |
2019 | - } |
2020 | - break; |
2021 | - |
2022 | - case GDK_KEY_Right: // Ctrl Right |
2023 | - case GDK_KEY_KP_Right: |
2024 | - case GDK_KEY_KP_6: |
2025 | - if (MOD__CTRL_ONLY(event)) { |
2026 | - int i = (int) floor(key_scroll * accelerate_scroll(event, |
2027 | - acceleration, desktop->getCanvas())); |
2028 | - |
2029 | - gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK); |
2030 | - this->desktop->scroll_world(-i, 0); |
2031 | - ret = TRUE; |
2032 | - } |
2033 | - break; |
2034 | - |
2035 | - case GDK_KEY_Down: // Ctrl Down |
2036 | - case GDK_KEY_KP_Down: |
2037 | - case GDK_KEY_KP_2: |
2038 | - if (MOD__CTRL_ONLY(event)) { |
2039 | - int i = (int) floor(key_scroll * accelerate_scroll(event, |
2040 | - acceleration, desktop->getCanvas())); |
2041 | - |
2042 | - gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK); |
2043 | - this->desktop->scroll_world(0, -i); |
2044 | - ret = TRUE; |
2045 | - } |
2046 | - break; |
2047 | - |
2048 | - case GDK_KEY_Menu: |
2049 | - sp_event_root_menu_popup(desktop, NULL, event); |
2050 | - ret = TRUE; |
2051 | - break; |
2052 | - |
2053 | - case GDK_KEY_F10: |
2054 | - if (MOD__SHIFT_ONLY(event)) { |
2055 | - sp_event_root_menu_popup(desktop, NULL, event); |
2056 | - ret = TRUE; |
2057 | - } |
2058 | - break; |
2059 | - |
2060 | - case GDK_KEY_space: |
2061 | - within_tolerance = true; |
2062 | - xp = yp = 0; |
2063 | - if (!allow_panning) break; |
2064 | - panning = 4; |
2065 | - this->space_panning = true; |
2066 | - this->message_context->set(Inkscape::INFORMATION_MESSAGE, |
2067 | - _("<b>Space+mouse move</b> to pan canvas")); |
2068 | - |
2069 | - ret = TRUE; |
2070 | - break; |
2071 | - |
2072 | - case GDK_KEY_z: |
2073 | - case GDK_KEY_Z: |
2074 | - if (MOD__ALT_ONLY(event)) { |
2075 | - desktop->zoom_grab_focus(); |
2076 | - ret = TRUE; |
2077 | - } |
2078 | - break; |
2079 | - |
2080 | - default: |
2081 | - break; |
2082 | - } |
2083 | - } |
2084 | - break; |
2085 | - |
2086 | - case GDK_KEY_RELEASE: |
2087 | - // Stop panning on any key release |
2088 | - if (this->space_panning) { |
2089 | - this->space_panning = false; |
2090 | - this->message_context->clear(); |
2091 | - } |
2092 | - |
2093 | - if (panning) { |
2094 | - panning = 0; |
2095 | - xp = yp = 0; |
2096 | - |
2097 | - sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), |
2098 | - event->key.time); |
2099 | - |
2100 | - desktop->updateNow(); |
2101 | - } |
2102 | - |
2103 | - if (panning_cursor == 1) { |
2104 | - panning_cursor = 0; |
2105 | - GtkWidget *w = GTK_WIDGET(this->desktop->getCanvas()); |
2106 | - gdk_window_set_cursor(gtk_widget_get_window (w), this->cursor); |
2107 | - } |
2108 | - |
2109 | - switch (get_group0_keyval(&event->key)) { |
2110 | - case GDK_KEY_space: |
2111 | - if (within_tolerance) { |
2112 | - // Space was pressed, but not panned |
2113 | - sp_toggle_selector(desktop); |
2114 | - |
2115 | - // Be careful, sp_toggle_selector will delete ourselves. |
2116 | - // Thus, make sure we return immediately. |
2117 | - return true; |
2118 | - } |
2119 | - |
2120 | - break; |
2121 | - |
2122 | - case GDK_KEY_Q: |
2123 | - case GDK_KEY_q: |
2124 | - if (desktop->quick_zoomed()) { |
2125 | - desktop->zoom_quick(false); |
2126 | - ret = TRUE; |
2127 | - } |
2128 | - break; |
2129 | - |
2130 | - default: |
2131 | - break; |
2132 | - } |
2133 | - break; |
2134 | - |
2135 | - case GDK_SCROLL: { |
2136 | - bool ctrl = (event->scroll.state & GDK_CONTROL_MASK); |
2137 | - bool wheelzooms = prefs->getBool("/options/wheelzooms/value"); |
2138 | - |
2139 | - int const wheel_scroll = prefs->getIntLimited( |
2140 | - "/options/wheelscroll/value", 40, 0, 1000); |
2141 | - |
2142 | - // Size of smooth-scrolls (only used in GTK+ 3) |
2143 | - gdouble delta_x = 0; |
2144 | - gdouble delta_y = 0; |
2145 | - |
2146 | - /* shift + wheel, pan left--right */ |
2147 | - if (event->scroll.state & GDK_SHIFT_MASK) { |
2148 | - switch (event->scroll.direction) { |
2149 | - case GDK_SCROLL_UP: |
2150 | - desktop->scroll_world(wheel_scroll, 0); |
2151 | - break; |
2152 | - |
2153 | - case GDK_SCROLL_DOWN: |
2154 | - desktop->scroll_world(-wheel_scroll, 0); |
2155 | - break; |
2156 | - |
2157 | - default: |
2158 | - break; |
2159 | - } |
2160 | - |
2161 | - /* ctrl + wheel, zoom in--out */ |
2162 | - } else if ((ctrl && !wheelzooms) || (!ctrl && wheelzooms)) { |
2163 | - double rel_zoom; |
2164 | - double const zoom_inc = prefs->getDoubleLimited( |
2165 | - "/options/zoomincrement/value", M_SQRT2, 1.01, 10); |
2166 | - |
2167 | - switch (event->scroll.direction) { |
2168 | - case GDK_SCROLL_UP: |
2169 | - rel_zoom = zoom_inc; |
2170 | - break; |
2171 | - |
2172 | - case GDK_SCROLL_DOWN: |
2173 | - rel_zoom = 1 / zoom_inc; |
2174 | - break; |
2175 | - |
2176 | - default: |
2177 | - rel_zoom = 0.0; |
2178 | - break; |
2179 | - } |
2180 | - |
2181 | - if (rel_zoom != 0.0) { |
2182 | - Geom::Point const scroll_dt = desktop->point(); |
2183 | - desktop->zoom_relative_keep_point(scroll_dt, rel_zoom); |
2184 | - } |
2185 | - |
2186 | - /* no modifier, pan up--down (left--right on multiwheel mice?) */ |
2187 | - } else { |
2188 | - switch (event->scroll.direction) { |
2189 | - case GDK_SCROLL_UP: |
2190 | - desktop->scroll_world(0, wheel_scroll); |
2191 | - break; |
2192 | - |
2193 | - case GDK_SCROLL_DOWN: |
2194 | - desktop->scroll_world(0, -wheel_scroll); |
2195 | - break; |
2196 | - |
2197 | - case GDK_SCROLL_LEFT: |
2198 | - desktop->scroll_world(wheel_scroll, 0); |
2199 | - break; |
2200 | - |
2201 | - case GDK_SCROLL_RIGHT: |
2202 | - desktop->scroll_world(-wheel_scroll, 0); |
2203 | - break; |
2204 | - |
2205 | - case GDK_SCROLL_SMOOTH: |
2206 | - gdk_event_get_scroll_deltas(event, &delta_x, &delta_y); |
2207 | - desktop->scroll_world(delta_x, delta_y); |
2208 | - break; |
2209 | - } |
2210 | - } |
2211 | - break; |
2212 | - } |
2213 | - default: |
2214 | - break; |
2215 | - } |
2216 | - |
2217 | + event->key.time); |
2218 | + |
2219 | + desktop->updateNow(); |
2220 | + } |
2221 | + |
2222 | + if (panning_cursor == 1) { |
2223 | + panning_cursor = 0; |
2224 | + GtkWidget *w = GTK_WIDGET(this->desktop->getCanvas()); |
2225 | + gdk_window_set_cursor(gtk_widget_get_window (w), this->cursor); |
2226 | + } |
2227 | + |
2228 | + switch (get_group0_keyval(&event->key)) { |
2229 | + case GDK_KEY_space: |
2230 | + if (this->rotating_mode) { |
2231 | + desktop->canvas->clearRotateTo(); |
2232 | + this->rotating_mode = false; |
2233 | + ret = TRUE; |
2234 | + if (desktop->canvas->endRotateTo()) { |
2235 | + sp_repr_set_svg_double(desktop->namedview->getRepr(), "inkscape:document-rotation", angle); |
2236 | + } |
2237 | + } |
2238 | + if (within_tolerance) { |
2239 | + // Space was pressed, but not panned |
2240 | + sp_toggle_selector(desktop); |
2241 | + |
2242 | + // Be careful, sp_toggle_selector will delete ourselves. |
2243 | + // Thus, make sure we return immediately. |
2244 | + return true; |
2245 | + } |
2246 | + break; |
2247 | + |
2248 | + case GDK_KEY_Q: |
2249 | + case GDK_KEY_q: |
2250 | + if (desktop->quick_zoomed()) { |
2251 | + desktop->zoom_quick(false); |
2252 | + ret = TRUE; |
2253 | + } |
2254 | + break; |
2255 | + |
2256 | + default: |
2257 | + break; |
2258 | + } |
2259 | + break; |
2260 | + |
2261 | + case GDK_SCROLL: { |
2262 | + if (this->rotating_mode) { |
2263 | + desktop->canvas->clearRotateTo(); |
2264 | + this->rotating_mode = false; |
2265 | + desktop->canvas->endRotateTo(); |
2266 | + } |
2267 | + bool ctrl = (event->scroll.state & GDK_CONTROL_MASK); |
2268 | + bool wheelzooms = prefs->getBool("/options/wheelzooms/value"); |
2269 | + |
2270 | + int const wheel_scroll = prefs->getIntLimited( |
2271 | + "/options/wheelscroll/value", 40, 0, 1000); |
2272 | + |
2273 | + // Size of smooth-scrolls (only used in GTK+ 3) |
2274 | + gdouble delta_x = 0; |
2275 | + gdouble delta_y = 0; |
2276 | + |
2277 | + /* shift + wheel, pan left--right */ |
2278 | + if (event->scroll.state & GDK_SHIFT_MASK) { |
2279 | + switch (event->scroll.direction) { |
2280 | + case GDK_SCROLL_UP: |
2281 | + desktop->scroll_world(wheel_scroll, 0); |
2282 | + break; |
2283 | + |
2284 | + case GDK_SCROLL_DOWN: |
2285 | + desktop->scroll_world(-wheel_scroll, 0); |
2286 | + break; |
2287 | + |
2288 | + default: |
2289 | + break; |
2290 | + } |
2291 | + |
2292 | + /* ctrl + wheel, zoom in--out */ |
2293 | + } else if ((ctrl && !wheelzooms) || (!ctrl && wheelzooms)) { |
2294 | + double rel_zoom; |
2295 | + double const zoom_inc = prefs->getDoubleLimited( |
2296 | + "/options/zoomincrement/value", M_SQRT2, 1.01, 10); |
2297 | + |
2298 | + switch (event->scroll.direction) { |
2299 | + case GDK_SCROLL_UP: |
2300 | + rel_zoom = zoom_inc; |
2301 | + break; |
2302 | + |
2303 | + case GDK_SCROLL_DOWN: |
2304 | + rel_zoom = 1 / zoom_inc; |
2305 | + break; |
2306 | + |
2307 | + default: |
2308 | + rel_zoom = 0.0; |
2309 | + break; |
2310 | + } |
2311 | + |
2312 | + if (rel_zoom != 0.0) { |
2313 | + Geom::Point const scroll_dt = desktop->point(); |
2314 | + desktop->zoom_relative_keep_point(scroll_dt, rel_zoom); |
2315 | + } |
2316 | + |
2317 | + /* no modifier, pan up--down (left--right on multiwheel mice?) */ |
2318 | + } else { |
2319 | + switch (event->scroll.direction) { |
2320 | + case GDK_SCROLL_UP: |
2321 | + desktop->scroll_world(0, wheel_scroll); |
2322 | + break; |
2323 | + |
2324 | + case GDK_SCROLL_DOWN: |
2325 | + desktop->scroll_world(0, -wheel_scroll); |
2326 | + break; |
2327 | + |
2328 | + case GDK_SCROLL_LEFT: |
2329 | + desktop->scroll_world(wheel_scroll, 0); |
2330 | + break; |
2331 | + |
2332 | + case GDK_SCROLL_RIGHT: |
2333 | + desktop->scroll_world(-wheel_scroll, 0); |
2334 | + break; |
2335 | + |
2336 | + case GDK_SCROLL_SMOOTH: |
2337 | + gdk_event_get_scroll_deltas(event, &delta_x, &delta_y); |
2338 | + desktop->scroll_world(delta_x, delta_y); |
2339 | + break; |
2340 | + } |
2341 | + } |
2342 | + break; |
2343 | + } |
2344 | + default: |
2345 | + break; |
2346 | + } |
2347 | return ret; |
2348 | } |
2349 | |
2350 | |
2351 | === modified file 'src/ui/tools/tool-base.h' |
2352 | --- src/ui/tools/tool-base.h 2015-07-24 19:38:06 +0000 |
2353 | +++ src/ui/tools/tool-base.h 2017-01-24 17:53:20 +0000 |
2354 | @@ -176,6 +176,7 @@ |
2355 | ShapeEditor* shape_editor; |
2356 | |
2357 | bool space_panning; |
2358 | + bool rotating_mode; |
2359 | |
2360 | DelayedSnapEvent *_delayed_snap_event; |
2361 | bool _dse_callback_in_process; |
2362 | |
2363 | === modified file 'src/viewbox.cpp' |
2364 | --- src/viewbox.cpp 2016-08-03 13:29:38 +0000 |
2365 | +++ src/viewbox.cpp 2017-01-24 17:53:20 +0000 |
2366 | @@ -17,6 +17,8 @@ |
2367 | #include "viewbox.h" |
2368 | #include "enums.h" |
2369 | #include "sp-item.h" |
2370 | +#include "inkscape.h" |
2371 | +#include "desktop.h" |
2372 | |
2373 | SPViewBox::SPViewBox() |
2374 | : viewBox_set(false) |
2375 | @@ -25,6 +27,11 @@ |
2376 | , aspect_align(SP_ASPECT_XMID_YMID) // Default per spec |
2377 | , aspect_clip(SP_ASPECT_MEET) |
2378 | , c2p(Geom::identity()) |
2379 | + , vbt(Geom::identity()) |
2380 | + , rotation(Geom::identity()) |
2381 | + , angle(0) |
2382 | + , previous_angle(0) |
2383 | + , rotated(false) |
2384 | { |
2385 | } |
2386 | |
2387 | @@ -159,6 +166,16 @@ |
2388 | } |
2389 | } |
2390 | |
2391 | +double SPViewBox::get_rotation() { |
2392 | + return this->angle; |
2393 | +} |
2394 | + |
2395 | +void SPViewBox::set_rotation(double angle_val) { |
2396 | + this->previous_angle = this->angle; |
2397 | + this->angle = angle_val; |
2398 | + this->rotated = true; |
2399 | +} |
2400 | + |
2401 | // Apply scaling from viewbox |
2402 | void SPViewBox::apply_viewbox(const Geom::Rect& in, double scale_none) { |
2403 | |
2404 | @@ -222,22 +239,41 @@ |
2405 | break; |
2406 | } |
2407 | } |
2408 | - |
2409 | /* Viewbox transform from scale and position */ |
2410 | - Geom::Affine q; |
2411 | - q[0] = scale_x; |
2412 | - q[1] = 0.0; |
2413 | - q[2] = 0.0; |
2414 | - q[3] = scale_y; |
2415 | - q[4] = x - scale_x * this->viewBox.left(); |
2416 | - q[5] = y - scale_y * this->viewBox.top(); |
2417 | - |
2418 | - // std::cout << " q\n" << q << std::endl; |
2419 | - |
2420 | - /* Append viewbox transformation */ |
2421 | - this->c2p = q * this->c2p; |
2422 | + vbt = Geom::identity(); |
2423 | + vbt[0] = scale_x; |
2424 | + vbt[1] = 0.0; |
2425 | + vbt[2] = 0.0; |
2426 | + vbt[3] = scale_y; |
2427 | + vbt[4] = x - scale_x * this->viewBox.left(); |
2428 | + vbt[5] = y - scale_y * this->viewBox.top(); |
2429 | + /* Append viewbox and turn transformation */ |
2430 | + Geom::Point page_center = this->viewBox.midpoint(); |
2431 | + SPDesktop * desktop = SP_ACTIVE_DESKTOP; |
2432 | + if (this->angle > 0.0 || this->angle < 0.0 ) { //!0 |
2433 | + if (desktop) { |
2434 | + rotation = Geom::Translate(page_center).inverse() * Geom::Rotate(Geom::rad_from_deg(angle)) * Geom::Translate(page_center); |
2435 | + this->c2p = rotation * vbt * this->c2p; |
2436 | + } else { |
2437 | + this->c2p = vbt * this->c2p; |
2438 | + } |
2439 | + } else { |
2440 | + this->c2p = vbt * this->c2p; |
2441 | + } |
2442 | + if (desktop && this->rotated) { |
2443 | + Geom::Rect view = desktop->get_display_area(); |
2444 | + Geom::Point view_center = desktop->doc2dt(view.midpoint()); |
2445 | + Geom::Affine center_rotation = Geom::identity(); |
2446 | + center_rotation *= Geom::Translate(page_center * vbt).inverse(); |
2447 | + center_rotation *= Geom::Rotate(Geom::rad_from_deg(this->angle - this->previous_angle)); |
2448 | + center_rotation *= Geom::Translate(page_center * vbt); |
2449 | + view_center = desktop->dt2doc(view_center * center_rotation); |
2450 | + desktop->zoom_relative(view_center[Geom::X], view_center[Geom::Y], 1.0); |
2451 | + this->rotated = false; |
2452 | + } |
2453 | } |
2454 | |
2455 | + |
2456 | SPItemCtx SPViewBox::get_rctx(const SPItemCtx* ictx, double scale_none) { |
2457 | |
2458 | /* Create copy of item context */ |
2459 | |
2460 | === modified file 'src/viewbox.h' |
2461 | --- src/viewbox.h 2015-02-12 16:17:54 +0000 |
2462 | +++ src/viewbox.h 2017-01-24 17:53:20 +0000 |
2463 | @@ -36,7 +36,14 @@ |
2464 | |
2465 | /* Child to parent additional transform */ |
2466 | Geom::Affine c2p; |
2467 | + Geom::Affine vbt; |
2468 | + Geom::Affine rotation; |
2469 | + double angle; |
2470 | + double previous_angle; |
2471 | + bool rotated; |
2472 | |
2473 | + double get_rotation(); |
2474 | + void set_rotation(double angle_val); |
2475 | void set_viewBox(const gchar* value); |
2476 | void set_preserveAspectRatio(const gchar* value); |
2477 | |
2478 | |
2479 | === modified file 'src/widgets/desktop-widget.cpp' |
2480 | --- src/widgets/desktop-widget.cpp 2016-11-11 20:04:49 +0000 |
2481 | +++ src/widgets/desktop-widget.cpp 2017-01-24 17:53:20 +0000 |
2482 | @@ -54,7 +54,7 @@ |
2483 | #include "ui/uxmanager.h" |
2484 | #include "util/ege-appear-time-tracker.h" |
2485 | #include "sp-root.h" |
2486 | - |
2487 | +#include "attributes.h" |
2488 | // We're in the "widgets" directory, so no need to explicitly prefix these: |
2489 | #include "button.h" |
2490 | #include "gimp/ruler.h" |
2491 | @@ -62,11 +62,11 @@ |
2492 | #include "spw-utilities.h" |
2493 | #include "toolbox.h" |
2494 | #include "widget-sizes.h" |
2495 | - |
2496 | #include "verbs.h" |
2497 | #include <gtkmm/cssprovider.h> |
2498 | #include <gtkmm/paned.h> |
2499 | #include <gtkmm/messagedialog.h> |
2500 | +#include <iomanip> |
2501 | |
2502 | #if defined (SOLARIS) && (SOLARIS == 8) |
2503 | #include "round.h" |
2504 | @@ -105,8 +105,20 @@ |
2505 | static void cms_adjust_toggled( GtkWidget *button, gpointer data ); |
2506 | #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) |
2507 | static void cms_adjust_set_sensitive( SPDesktopWidget *dtw, bool enabled ); |
2508 | +static void sp_desktop_widget_rotate_document(GtkSpinButton *spin, SPDesktopWidget *dtw); |
2509 | static void sp_desktop_widget_adjustment_value_changed (GtkAdjustment *adj, SPDesktopWidget *dtw); |
2510 | |
2511 | +static gint sp_dtw_rotation_input (GtkSpinButton *spin, gdouble *new_val, gpointer data); |
2512 | +static bool sp_dtw_rotation_output (GtkSpinButton *spin, gpointer data); |
2513 | +static void sp_dtw_rotation_populate_popup (GtkEntry *entry, GtkMenu *menu, gpointer data); |
2514 | +static void sp_dtw_rotate_minus_180 (GtkMenuItem *item, SPDesktopWidget * data); |
2515 | +static void sp_dtw_rotate_minus_135 (GtkMenuItem *item, SPDesktopWidget * data); |
2516 | +static void sp_dtw_rotate_minus_90 (GtkMenuItem *item, SPDesktopWidget * data); |
2517 | +static void sp_dtw_rotate_minus_45 (GtkMenuItem *item, SPDesktopWidget * data); |
2518 | +static void sp_dtw_rotate_0 (GtkMenuItem *item, SPDesktopWidget * data); |
2519 | +static void sp_dtw_rotate_45 (GtkMenuItem *item, SPDesktopWidget * data); |
2520 | +static void sp_dtw_rotate_90 (GtkMenuItem *item, SPDesktopWidget * data); |
2521 | +static void sp_dtw_rotate_135 (GtkMenuItem *item, SPDesktopWidget * data); |
2522 | static gdouble sp_dtw_zoom_value_to_display (gdouble value); |
2523 | static gdouble sp_dtw_zoom_display_to_value (gdouble value); |
2524 | static gint sp_dtw_zoom_input (GtkSpinButton *spin, gdouble *new_val, gpointer data); |
2525 | @@ -593,6 +605,34 @@ |
2526 | g_signal_connect (G_OBJECT (dtw->zoom_status), "key-press-event", G_CALLBACK (spinbutton_keypress), dtw->zoom_status); |
2527 | dtw->zoom_update = g_signal_connect (G_OBJECT (dtw->zoom_status), "value_changed", G_CALLBACK (sp_dtw_zoom_value_changed), dtw); |
2528 | dtw->zoom_update = g_signal_connect (G_OBJECT (dtw->zoom_status), "populate_popup", G_CALLBACK (sp_dtw_zoom_populate_popup), dtw); |
2529 | + auto css_provider_spinbutton = Gtk::CssProvider::create(); |
2530 | + css_provider_spinbutton->load_from_data("* { padding-left: 2; padding-right: 2; padding-top: 0; padding-bottom: 0;}"); |
2531 | + auto zoomstat = Glib::wrap(dtw->zoom_status); |
2532 | + zoomstat->set_name("ZoomStatus"); |
2533 | + auto context_zoom = zoomstat->get_style_context(); |
2534 | + context_zoom->add_provider(css_provider_spinbutton, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); |
2535 | + |
2536 | + // Rotate status spinbutton |
2537 | + dtw->rotation_status = gtk_spin_button_new_with_range (-360.0,360.0, 1.0); |
2538 | + gtk_widget_set_tooltip_text (dtw->rotation_status, _("Rotation")); |
2539 | + gtk_widget_set_size_request (dtw->rotation_status, STATUS_ROTATION_WIDTH, -1); |
2540 | + gtk_entry_set_width_chars (GTK_ENTRY (dtw->rotation_status), 7); |
2541 | + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (dtw->rotation_status), FALSE); |
2542 | + gtk_spin_button_set_digits (GTK_SPIN_BUTTON (dtw->rotation_status), 2); |
2543 | + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (dtw->rotation_status), GTK_UPDATE_ALWAYS); |
2544 | + g_signal_connect (G_OBJECT (dtw->rotation_status), "input", G_CALLBACK (sp_dtw_rotation_input), dtw); |
2545 | + g_signal_connect (G_OBJECT (dtw->rotation_status), "output", G_CALLBACK (sp_dtw_rotation_output), dtw); |
2546 | + g_object_set_data (G_OBJECT (dtw->rotation_status), "dtw", dtw->canvas); |
2547 | + g_signal_connect (G_OBJECT (dtw->rotation_status), "focus-in-event", G_CALLBACK (spinbutton_focus_in), dtw->rotation_status); |
2548 | + g_signal_connect (G_OBJECT (dtw->rotation_status), "key-press-event", G_CALLBACK (spinbutton_keypress), dtw->rotation_status); |
2549 | + dtw->rotation_update = g_signal_connect (G_OBJECT (dtw->rotation_status), "value_changed", G_CALLBACK (sp_desktop_widget_rotate_document), dtw); |
2550 | + dtw->rotation_update = g_signal_connect (G_OBJECT (dtw->rotation_status), "populate_popup", G_CALLBACK (sp_dtw_rotation_populate_popup), dtw); |
2551 | + |
2552 | + auto rotstat = Glib::wrap(dtw->rotation_status); |
2553 | + rotstat->set_name("RotationStatus"); |
2554 | + auto context_rotation = rotstat->get_style_context(); |
2555 | + context_rotation->add_provider(css_provider_spinbutton, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); |
2556 | + |
2557 | |
2558 | // Cursor coordinates |
2559 | dtw->coord_status = gtk_grid_new(); |
2560 | @@ -619,12 +659,16 @@ |
2561 | |
2562 | auto label_z = gtk_label_new(_("Z:")); |
2563 | gtk_widget_set_name(label_z, "ZLabel"); |
2564 | + auto label_r = gtk_label_new(_("R:")); |
2565 | + gtk_widget_set_name(label_r, "RLabel"); |
2566 | gtk_widget_set_halign(dtw->coord_status_x, GTK_ALIGN_END); |
2567 | gtk_widget_set_halign(dtw->coord_status_y, GTK_ALIGN_END); |
2568 | gtk_grid_attach(GTK_GRID(dtw->coord_status), dtw->coord_status_x, 2, 0, 1, 1); |
2569 | gtk_grid_attach(GTK_GRID(dtw->coord_status), dtw->coord_status_y, 2, 1, 1, 1); |
2570 | gtk_grid_attach(GTK_GRID(dtw->coord_status), label_z, 3, 0, 1, 2); |
2571 | + gtk_grid_attach(GTK_GRID(dtw->coord_status), label_r, 5, 0, 1, 2); |
2572 | gtk_grid_attach(GTK_GRID(dtw->coord_status), dtw->zoom_status, 4, 0, 1, 2); |
2573 | + gtk_grid_attach(GTK_GRID(dtw->coord_status), dtw->rotation_status, 6, 0, 1, 2); |
2574 | |
2575 | sp_set_font_size_smaller (dtw->coord_status); |
2576 | |
2577 | @@ -692,6 +736,11 @@ |
2578 | g_signal_handlers_disconnect_matched (G_OBJECT (dtw->zoom_status), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, dtw->zoom_status); |
2579 | g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->zoom_status), (gpointer) G_CALLBACK (sp_dtw_zoom_value_changed), dtw); |
2580 | g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->zoom_status), (gpointer) G_CALLBACK (sp_dtw_zoom_populate_popup), dtw); |
2581 | + g_signal_handlers_disconnect_by_func(G_OBJECT (dtw->rotation_status), (gpointer) G_CALLBACK(sp_dtw_rotation_input), dtw); |
2582 | + g_signal_handlers_disconnect_by_func(G_OBJECT (dtw->rotation_status), (gpointer) G_CALLBACK(sp_dtw_rotation_output), dtw); |
2583 | + g_signal_handlers_disconnect_matched (G_OBJECT (dtw->rotation_status), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, dtw->rotation_status); |
2584 | + g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->rotation_status), (gpointer) G_CALLBACK (sp_desktop_widget_rotate_document), dtw); |
2585 | + g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->rotation_status), (gpointer) G_CALLBACK (sp_dtw_rotation_populate_popup), dtw); |
2586 | g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->canvas), (gpointer) G_CALLBACK (sp_desktop_widget_event), dtw); |
2587 | g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->canvas_tbl), (gpointer) G_CALLBACK (canvas_tbl_size_allocate), dtw); |
2588 | |
2589 | @@ -1423,7 +1472,7 @@ |
2590 | } else { |
2591 | gtk_widget_show_all (dtw->menubar); |
2592 | } |
2593 | - |
2594 | + |
2595 | if (!prefs->getBool(pref_root + "commands/state", true)) { |
2596 | gtk_widget_hide (dtw->commands_toolbox); |
2597 | } else { |
2598 | @@ -1629,10 +1678,11 @@ |
2599 | dtw->menubar = sp_ui_main_menubar (dtw->desktop); |
2600 | gtk_widget_set_name(dtw->menubar, "MenuBar"); |
2601 | gtk_widget_show_all (dtw->menubar); |
2602 | - gtk_box_pack_start (GTK_BOX (dtw->vbox), dtw->menubar, FALSE, FALSE, 0); |
2603 | - |
2604 | + SPNamedView *nv = dtw->desktop->namedview; |
2605 | + gtk_box_pack_start (GTK_BOX (dtw->vbox), dtw->menubar, TRUE, TRUE, 0); |
2606 | dtw->layoutWidgets(); |
2607 | - |
2608 | + gtk_spin_button_set_value(GTK_SPIN_BUTTON (dtw->rotation_status), namedview->document_rotation); |
2609 | + sp_namedview_set_document_rotation(namedview); |
2610 | std::vector<GtkWidget *> toolboxes; |
2611 | toolboxes.push_back(dtw->tool_toolbox); |
2612 | toolboxes.push_back(dtw->aux_toolbox); |
2613 | @@ -1672,6 +1722,8 @@ |
2614 | void SPDesktopWidget::namedviewModified(SPObject *obj, guint flags) |
2615 | { |
2616 | SPNamedView *nv=SP_NAMEDVIEW(obj); |
2617 | + gtk_spin_button_set_value(GTK_SPIN_BUTTON(this->rotation_status), desktop->namedview->document_rotation); |
2618 | + sp_namedview_set_document_rotation(nv); |
2619 | |
2620 | if (flags & SP_OBJECT_MODIFIED_FLAG) { |
2621 | this->dt2r = 1. / nv->display_units->factor; |
2622 | @@ -1723,6 +1775,18 @@ |
2623 | } |
2624 | |
2625 | static void |
2626 | +sp_desktop_widget_rotate_document(GtkSpinButton *spin, SPDesktopWidget *dtw) |
2627 | +{ |
2628 | + SPNamedView *nv = dtw->desktop->namedview; |
2629 | + double value = gtk_spin_button_get_value (spin); |
2630 | + if (!dtw->desktop->getDocument()->getRoot()->rotated && value != nv->document_rotation) { |
2631 | + sp_repr_set_svg_double(nv->getRepr(), "inkscape:document-rotation", value); |
2632 | + } |
2633 | + spinbutton_defocus (GTK_WIDGET(spin)); |
2634 | +} |
2635 | + |
2636 | + |
2637 | +static void |
2638 | sp_desktop_widget_adjustment_value_changed (GtkAdjustment */*adj*/, SPDesktopWidget *dtw) |
2639 | { |
2640 | if (dtw->update) |
2641 | @@ -1802,6 +1866,34 @@ |
2642 | return TRUE; |
2643 | } |
2644 | |
2645 | +static gint |
2646 | +sp_dtw_rotation_input (GtkSpinButton *spin, gdouble *new_val, gpointer /*data*/) |
2647 | +{ |
2648 | + gdouble new_scrolled = gtk_spin_button_get_value (spin); |
2649 | + const gchar *b = gtk_entry_get_text (GTK_ENTRY (spin)); |
2650 | + gdouble new_typed = atof (b); |
2651 | + |
2652 | + if (new_scrolled == new_typed) { // the new value is set by scrolling |
2653 | + *new_val = new_scrolled; |
2654 | + } else { // the new value is typed in |
2655 | + *new_val = new_typed; |
2656 | + } |
2657 | + |
2658 | + return TRUE; |
2659 | +} |
2660 | + |
2661 | +static bool |
2662 | +sp_dtw_rotation_output (GtkSpinButton *spin, gpointer /*data*/) |
2663 | +{ |
2664 | + gchar b[64]; |
2665 | + double val = gtk_spin_button_get_value (spin); |
2666 | + std::ostringstream s; |
2667 | + s.imbue(std::locale(""));; |
2668 | + s << std::fixed << std::setprecision(2) << val << "º"; |
2669 | + gtk_entry_set_text (GTK_ENTRY (spin), s.str().c_str()); |
2670 | + return TRUE; |
2671 | +} |
2672 | + |
2673 | static void |
2674 | sp_dtw_zoom_value_changed (GtkSpinButton *spin, gpointer data) |
2675 | { |
2676 | @@ -1940,6 +2032,110 @@ |
2677 | gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); |
2678 | } |
2679 | |
2680 | + |
2681 | +static void |
2682 | +sp_dtw_rotation_populate_popup (GtkEntry */*entry*/, GtkMenu *menu, gpointer data) |
2683 | +{ |
2684 | + GList *children, *iter; |
2685 | + GtkWidget *item; |
2686 | + SPDesktopWidget *dtw = static_cast<SPDesktopWidget*>(data); |
2687 | + children = gtk_container_get_children (GTK_CONTAINER (menu)); |
2688 | + for ( iter = children ; iter ; iter = g_list_next (iter)) { |
2689 | + gtk_container_remove (GTK_CONTAINER (menu), GTK_WIDGET (iter->data)); |
2690 | + } |
2691 | + g_list_free (children); |
2692 | + |
2693 | + item = gtk_menu_item_new_with_label ("-180º"); |
2694 | + g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_minus_180), dtw); |
2695 | + gtk_widget_show (item); |
2696 | + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); |
2697 | + |
2698 | + item = gtk_menu_item_new_with_label ("-135º"); |
2699 | + g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_minus_135), dtw); |
2700 | + gtk_widget_show (item); |
2701 | + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); |
2702 | + |
2703 | + item = gtk_menu_item_new_with_label ("-90º"); |
2704 | + g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_minus_90), dtw); |
2705 | + gtk_widget_show (item); |
2706 | + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); |
2707 | + |
2708 | + item = gtk_menu_item_new_with_label ("-45º"); |
2709 | + g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_minus_45), dtw); |
2710 | + gtk_widget_show (item); |
2711 | + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); |
2712 | + |
2713 | + item = gtk_menu_item_new_with_label ("0º"); |
2714 | + g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_0), dtw); |
2715 | + gtk_widget_show (item); |
2716 | + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); |
2717 | + |
2718 | + item = gtk_menu_item_new_with_label ("45º"); |
2719 | + g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_45), dtw); |
2720 | + gtk_widget_show (item); |
2721 | + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); |
2722 | + |
2723 | + |
2724 | + item = gtk_menu_item_new_with_label ("90º"); |
2725 | + g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_90), dtw); |
2726 | + gtk_widget_show (item); |
2727 | + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); |
2728 | + |
2729 | + |
2730 | + item = gtk_menu_item_new_with_label ("135º"); |
2731 | + g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_135), dtw); |
2732 | + gtk_widget_show (item); |
2733 | + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); |
2734 | +} |
2735 | + |
2736 | +static void |
2737 | +sp_dtw_rotate_minus_180 (GtkMenuItem */*item*/, SPDesktopWidget * data) |
2738 | +{ |
2739 | + gtk_spin_button_set_value (GTK_SPIN_BUTTON((data)->rotation_status),-180); |
2740 | +} |
2741 | + |
2742 | +static void |
2743 | +sp_dtw_rotate_minus_135 (GtkMenuItem */*item*/, SPDesktopWidget * data) |
2744 | +{ |
2745 | + gtk_spin_button_set_value (GTK_SPIN_BUTTON((data)->rotation_status), -135); |
2746 | +} |
2747 | + |
2748 | +static void |
2749 | +sp_dtw_rotate_minus_90 (GtkMenuItem */*item*/, SPDesktopWidget * data) |
2750 | +{ |
2751 | + gtk_spin_button_set_value (GTK_SPIN_BUTTON((data)->rotation_status), -90); |
2752 | +} |
2753 | + |
2754 | +static void |
2755 | +sp_dtw_rotate_minus_45 (GtkMenuItem */*item*/, SPDesktopWidget * data) |
2756 | +{ |
2757 | + gtk_spin_button_set_value (GTK_SPIN_BUTTON((data)->rotation_status), -45); |
2758 | +} |
2759 | + |
2760 | +static void |
2761 | +sp_dtw_rotate_0 (GtkMenuItem */*item*/,SPDesktopWidget * data) |
2762 | +{ |
2763 | + gtk_spin_button_set_value (GTK_SPIN_BUTTON((data)->rotation_status), 0); |
2764 | +} |
2765 | + |
2766 | +static void |
2767 | +sp_dtw_rotate_45 (GtkMenuItem */*item*/, SPDesktopWidget * data) |
2768 | +{ |
2769 | + gtk_spin_button_set_value (GTK_SPIN_BUTTON((data)->rotation_status), 45); |
2770 | +} |
2771 | + |
2772 | +static void |
2773 | +sp_dtw_rotate_90 (GtkMenuItem */*item*/, SPDesktopWidget * data) |
2774 | +{ |
2775 | + gtk_spin_button_set_value (GTK_SPIN_BUTTON((data)->rotation_status), 90); |
2776 | +} |
2777 | + |
2778 | +static void |
2779 | +sp_dtw_rotate_135 (GtkMenuItem */*item*/, SPDesktopWidget * data) |
2780 | +{ |
2781 | + gtk_spin_button_set_value (GTK_SPIN_BUTTON((data)->rotation_status), 135); |
2782 | +} |
2783 | + |
2784 | static void |
2785 | sp_dtw_zoom_menu_handler (SPDesktop *dt, gdouble factor) |
2786 | { |
2787 | |
2788 | === modified file 'src/widgets/desktop-widget.h' |
2789 | --- src/widgets/desktop-widget.h 2015-12-09 15:13:54 +0000 |
2790 | +++ src/widgets/desktop-widget.h 2017-01-24 17:53:20 +0000 |
2791 | @@ -78,7 +78,7 @@ |
2792 | |
2793 | GtkWidget *hbox; |
2794 | |
2795 | - GtkWidget *menubar, *statusbar; |
2796 | + GtkWidget *menubar, *statusbar, *rotatebar; |
2797 | |
2798 | Inkscape::UI::Dialogs::SwatchesPanel *panels; |
2799 | |
2800 | @@ -97,7 +97,9 @@ |
2801 | GtkWidget *select_status; |
2802 | GtkWidget *select_status_eventbox; |
2803 | GtkWidget *zoom_status; |
2804 | + GtkWidget *rotation_status; |
2805 | gulong zoom_update; |
2806 | + gulong rotation_update; |
2807 | |
2808 | Inkscape::UI::Widget::Dock *dock; |
2809 | |
2810 | |
2811 | === modified file 'src/widgets/widget-sizes.h' |
2812 | --- src/widgets/widget-sizes.h 2014-03-27 01:33:44 +0000 |
2813 | +++ src/widgets/widget-sizes.h 2017-01-24 17:53:20 +0000 |
2814 | @@ -28,6 +28,7 @@ |
2815 | #define STATUS_BAR_FONT_SIZE 10000 |
2816 | |
2817 | #define STATUS_ZOOM_WIDTH 57 |
2818 | +#define STATUS_ROTATION_WIDTH 57 |
2819 | |
2820 | #define SELECTED_STYLE_SB_WIDTH 48 |
2821 | #define SELECTED_STYLE_WIDTH 190 |
The namespace should be saved somewhere instead of re-specified each time:
DOCROTATE = "{http:// www.inkscape. org/namespaces/ inkscape}document_rotation"
for example.
Everything else looks remarkably good for such a large diff.