Merge lp:~inkscape.dev/inkscape/doc_rotate into lp:~inkscape.dev/inkscape/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
Reviewer Review Type Date Requested Status
Martin Owens Approve
Inkscape Developers Pending
Review via email: mp+310123@code.launchpad.net

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.
lp:~inkscape.dev/inkscape/doc_rotate updated
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

Revision history for this message
Martin Owens (doctormo) wrote :

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.

review: Approve
lp:~inkscape.dev/inkscape/doc_rotate updated
15182. By Jabiertxof

Put namespace as constant

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'share/extensions/hpgl_output.py'
--- share/extensions/hpgl_output.py 2016-05-26 09:28:23 +0000
+++ share/extensions/hpgl_output.py 2017-01-24 17:53:20 +0000
@@ -20,6 +20,7 @@
2020
21# standard library21# standard library
22import sys22import sys
23from inkex import NSS
23# local libraries24# local libraries
24import hpgl_encoder25import hpgl_encoder
25import inkex26import inkex
@@ -44,10 +45,18 @@
44 self.OptionParser.add_option('--precut', action='store', type='inkbool', dest='precut', default='TRUE', help='Use precut')45 self.OptionParser.add_option('--precut', action='store', type='inkbool', dest='precut', default='TRUE', help='Use precut')
45 self.OptionParser.add_option('--flat', action='store', type='float', dest='flat', default=1.2, help='Curve flatness')46 self.OptionParser.add_option('--flat', action='store', type='float', dest='flat', default=1.2, help='Curve flatness')
46 self.OptionParser.add_option('--autoAlign', action='store', type='inkbool', dest='autoAlign', default='TRUE', help='Auto align')47 self.OptionParser.add_option('--autoAlign', action='store', type='inkbool', dest='autoAlign', default='TRUE', help='Auto align')
48 self.DOCROTATE = "{http://www.inkscape.org/namespaces/inkscape}document_rotation"
4749
48 def effect(self):50 def effect(self):
49 self.options.debug = False51 self.options.debug = False
50 # get hpgl data52 # get hpgl data
53 svg = self.document.getroot()
54 xpathStr = '//sodipodi:namedview'
55 nv = svg.xpath(xpathStr, namespaces=NSS)
56 document_rotate = "0"
57 if nv != []:
58 document_rotate = nv[0].get(self.DOCROTATE)
59 nv[0].set(self.DOCROTATE,"0")
51 myHpglEncoder = hpgl_encoder.hpglEncoder(self)60 myHpglEncoder = hpgl_encoder.hpglEncoder(self)
52 try:61 try:
53 self.hpgl, debugObject = myHpglEncoder.getHpgl()62 self.hpgl, debugObject = myHpglEncoder.getHpgl()
@@ -56,9 +65,13 @@
56 # issue error if no paths found65 # issue error if no paths found
57 inkex.errormsg(_("No paths where found. Please convert all objects you want to save into paths."))66 inkex.errormsg(_("No paths where found. Please convert all objects you want to save into paths."))
58 self.hpgl = ''67 self.hpgl = ''
68 if nv != [] and document_rotate:
69 nv[0].set("inkscape:document_rotation",document_rotate)
59 return70 return
60 else:71 else:
61 type, value, traceback = sys.exc_info()72 type, value, traceback = sys.exc_info()
73 if nv != [] and document_rotate:
74 nv[0].set("inkscape:document_rotation",document_rotate)
62 raise ValueError, ("", type, value), traceback75 raise ValueError, ("", type, value), traceback
63 # convert raw HPGL to HPGL76 # convert raw HPGL to HPGL
64 hpglInit = 'IN'77 hpglInit = 'IN'
@@ -67,6 +80,8 @@
67 if self.options.speed > 0:80 if self.options.speed > 0:
68 hpglInit += ';VS%d' % self.options.speed81 hpglInit += ';VS%d' % self.options.speed
69 self.hpgl = hpglInit + self.hpgl + ';SP0;PU0,0;IN; '82 self.hpgl = hpglInit + self.hpgl + ';SP0;PU0,0;IN; '
83 if nv != [] and document_rotate:
84 nv[0].set("inkscape:document_rotation",document_rotate)
7085
71 def output(self):86 def output(self):
72 # print to file87 # print to file
7388
=== modified file 'share/extensions/synfig_output.py'
--- share/extensions/synfig_output.py 2011-11-25 19:00:24 +0000
+++ share/extensions/synfig_output.py 2017-01-24 17:53:20 +0000
@@ -1046,6 +1046,11 @@
1046###### Main Class #########################################1046###### Main Class #########################################
1047class SynfigExport(SynfigPrep):1047class SynfigExport(SynfigPrep):
1048 def __init__(self):1048 def __init__(self):
1049 svg = self.document.getroot()
1050 xpathStr = '//http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd}:namedview'
1051 res = svg.xpath(xpathStr, namespaces=inkex.NSS)
1052 self.document_rotate = res[0].get("inkscape:document_rotation")
1053 res[0].set("inkscape:document_rotation","0")
1049 SynfigPrep.__init__(self)1054 SynfigPrep.__init__(self)
10501055
1051 def effect(self):1056 def effect(self):
@@ -1073,6 +1078,10 @@
1073 root_canvas.append(layer)1078 root_canvas.append(layer)
10741079
1075 d.get_root_tree().write(sys.stdout)1080 d.get_root_tree().write(sys.stdout)
1081 svg = self.document.getroot()
1082 xpathStr = '//http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd}:namedview'
1083 res = svg.xpath(xpathStr, namespaces=inkex.NSS)
1084 res[0].set("inkscape:document_rotation",self.document_rotate)
10761085
1077 def convert_node(self, node, d):1086 def convert_node(self, node, d):
1078 """Convert an SVG node to a list of Synfig layers"""1087 """Convert an SVG node to a list of Synfig layers"""
10791088
=== modified file 'src/attributes.cpp'
--- src/attributes.cpp 2016-10-19 11:11:05 +0000
+++ src/attributes.cpp 2017-01-24 17:53:20 +0000
@@ -89,6 +89,7 @@
89 {SP_ATTR_INKSCAPE_ZOOM, "inkscape:zoom"},89 {SP_ATTR_INKSCAPE_ZOOM, "inkscape:zoom"},
90 {SP_ATTR_INKSCAPE_CX, "inkscape:cx"},90 {SP_ATTR_INKSCAPE_CX, "inkscape:cx"},
91 {SP_ATTR_INKSCAPE_CY, "inkscape:cy"},91 {SP_ATTR_INKSCAPE_CY, "inkscape:cy"},
92 {SP_ATTR_INKSCAPE_DOCUMENT_ROTATION, "inkscape:document-rotation"},
92 {SP_ATTR_INKSCAPE_WINDOW_WIDTH, "inkscape:window-width"},93 {SP_ATTR_INKSCAPE_WINDOW_WIDTH, "inkscape:window-width"},
93 {SP_ATTR_INKSCAPE_WINDOW_HEIGHT, "inkscape:window-height"},94 {SP_ATTR_INKSCAPE_WINDOW_HEIGHT, "inkscape:window-height"},
94 {SP_ATTR_INKSCAPE_WINDOW_X, "inkscape:window-x"},95 {SP_ATTR_INKSCAPE_WINDOW_X, "inkscape:window-x"},
9596
=== modified file 'src/attributes.h'
--- src/attributes.h 2016-10-19 11:11:05 +0000
+++ src/attributes.h 2017-01-24 17:53:20 +0000
@@ -97,6 +97,7 @@
97 SP_ATTR_INKSCAPE_ZOOM,97 SP_ATTR_INKSCAPE_ZOOM,
98 SP_ATTR_INKSCAPE_CX,98 SP_ATTR_INKSCAPE_CX,
99 SP_ATTR_INKSCAPE_CY,99 SP_ATTR_INKSCAPE_CY,
100 SP_ATTR_INKSCAPE_DOCUMENT_ROTATION,
100 SP_ATTR_INKSCAPE_WINDOW_WIDTH,101 SP_ATTR_INKSCAPE_WINDOW_WIDTH,
101 SP_ATTR_INKSCAPE_WINDOW_HEIGHT,102 SP_ATTR_INKSCAPE_WINDOW_HEIGHT,
102 SP_ATTR_INKSCAPE_WINDOW_X,103 SP_ATTR_INKSCAPE_WINDOW_X,
103104
=== modified file 'src/desktop-events.cpp'
--- src/desktop-events.cpp 2016-08-08 23:57:01 +0000
+++ src/desktop-events.cpp 2017-01-24 17:53:20 +0000
@@ -155,6 +155,10 @@
155 }155 }
156 }156 }
157157
158 SPNamedView *namedview = desktop->namedview;
159 if (namedview && namedview->document_rotation) {
160 normal *= Geom::Rotate(Geom::rad_from_deg(namedview->document_rotation * -1));
161 }
158 guide = sp_guideline_new(desktop->guides, NULL, event_dt, normal);162 guide = sp_guideline_new(desktop->guides, NULL, event_dt, normal);
159 sp_guideline_set_color(SP_GUIDELINE(guide), desktop->namedview->guidehicolor);163 sp_guideline_set_color(SP_GUIDELINE(guide), desktop->namedview->guidehicolor);
160164
161165
=== modified file 'src/display/canvas-temporary-item-list.h'
--- src/display/canvas-temporary-item-list.h 2014-10-08 02:22:03 +0000
+++ src/display/canvas-temporary-item-list.h 2017-01-24 17:53:20 +0000
@@ -14,6 +14,7 @@
1414
15struct SPCanvasItem;15struct SPCanvasItem;
16class SPDesktop;16class SPDesktop;
17class SPViewBox;
1718
18namespace Inkscape {19namespace Inkscape {
19namespace Display {20namespace Display {
2021
=== modified file 'src/display/sp-canvas.cpp'
--- src/display/sp-canvas.cpp 2016-12-25 19:26:50 +0000
+++ src/display/sp-canvas.cpp 2017-01-24 17:53:20 +0000
@@ -29,18 +29,24 @@
29#include "helper/sp-marshal.h"29#include "helper/sp-marshal.h"
30#include <2geom/rect.h>30#include <2geom/rect.h>
31#include <2geom/affine.h>31#include <2geom/affine.h>
32#include "display/cairo-utils.h"
33#include "display/sp-canvas.h"32#include "display/sp-canvas.h"
34#include "display/sp-canvas-group.h"33#include "display/sp-canvas-group.h"
34#include "display/rendermode.h"
35#include "display/cairo-utils.h"
36#include "display/cairo-templates.h"
37#include "display/drawing-context.h"
38#include "display/drawing-item.h"
39#include "display/nr-filter-colormatrix.h"
40#include "display/canvas-arena.h"
35#include "preferences.h"41#include "preferences.h"
36#include "inkscape.h"42#include "inkscape.h"
37#include "sodipodi-ctrlrect.h"43#include "sodipodi-ctrlrect.h"
38#include "cms-system.h"44#include "cms-system.h"
39#include "display/rendermode.h"
40#include "display/cairo-utils.h"
41#include "debug/gdk-event-latency-tracker.h"45#include "debug/gdk-event-latency-tracker.h"
42#include "desktop.h"46#include "desktop.h"
43#include "color.h"47#include "color.h"
48#include <iomanip>
49#include <glibmm/i18n.h>
4450
45using Inkscape::Debug::GdkEventLatencyTracker;51using Inkscape::Debug::GdkEventLatencyTracker;
4652
@@ -1888,6 +1894,19 @@
1888 return SP_CANVAS_GROUP(_root);1894 return SP_CANVAS_GROUP(_root);
1889}1895}
18901896
1897gdouble grayscale_value_matrix[20] = {
1898 0.21, 0.72, 0.072, 0, 0,
1899 0.21, 0.72, 0.072, 0, 0,
1900 0.21, 0.72, 0.072, 0, 0,
1901 0 , 0 , 0 , 1, 0
1902 };
1903cairo_surface_t *surface_rotated;
1904cairo_surface_t *surface_origin;
1905cairo_surface_t *surface_measure;
1906double start_angle = 0;
1907bool started = false;
1908bool rotated = false;
1909
1891void SPCanvas::scrollTo(double cx, double cy, unsigned int clear, bool is_scrolling)1910void SPCanvas::scrollTo(double cx, double cy, unsigned int clear, bool is_scrolling)
1892{1911{
1893 GtkAllocation allocation;1912 GtkAllocation allocation;
@@ -1910,9 +1929,14 @@
1910 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);1929 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1911 // Paint the background1930 // Paint the background
1912 cairo_translate(cr, -ix, -iy);1931 cairo_translate(cr, -ix, -iy);
1932 if (rotated) {
1933 cairo_translate(cr, dx, dy);
1934 rotated = false;
1935 }
1913 cairo_set_source(cr, _background);1936 cairo_set_source(cr, _background);
1914 cairo_paint(cr);1937 cairo_paint(cr);
1915 // Copy the old backing store contents1938 // Copy the old backing store contents
1939
1916 cairo_set_source_surface(cr, _backing_store, _x0, _y0);1940 cairo_set_source_surface(cr, _backing_store, _x0, _y0);
1917 cairo_rectangle(cr, _x0, _y0, allocation.width, allocation.height);1941 cairo_rectangle(cr, _x0, _y0, allocation.width, allocation.height);
1918 cairo_clip(cr);1942 cairo_clip(cr);
@@ -1949,6 +1973,271 @@
1949 addIdle();1973 addIdle();
1950}1974}
19511975
1976void SPCanvas::startRotateTo(double angle)
1977{
1978 if (!_backing_store || started) {
1979 return;
1980 }
1981 start_angle = angle;
1982 started = true;
1983 GtkAllocation allocation;
1984 gtk_widget_get_allocation(&_widget, &allocation);
1985 int half_w = allocation.width/2;
1986 int half_h = allocation.height/2;
1987 int half_min = std::min(half_w,half_h);
1988
1989 cairo_surface_t *new_backing_store = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height);
1990 cairo_t *cr = cairo_create(new_backing_store);
1991 cairo_arc(cr, half_w, half_h, half_min-15, 0, 2*M_PI);
1992 cairo_fill(cr);
1993 cairo_set_operator(cr, CAIRO_OPERATOR_IN);
1994 cairo_set_source_surface(cr, _backing_store, 0, 0);
1995 cairo_paint(cr);
1996 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1997 cairo_arc(cr, half_w, half_h, half_min-16, 0, 2*M_PI);
1998 cairo_set_source_rgba (cr, 1, 1, 1, 0.5);
1999 cairo_stroke(cr);
2000 cairo_destroy(cr);
2001 surface_rotated = new_backing_store;
2002
2003 cairo_surface_t *new_backing_store_measure = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height);
2004 cr = cairo_create(new_backing_store_measure);
2005 cairo_arc(cr, half_w, half_h, half_min-15, 0, 2*M_PI);
2006 cairo_set_source_rgba (cr, 1, 1, 1, 0.2);
2007 cairo_fill(cr);
2008 cairo_translate(cr, half_w, half_h);
2009 cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
2010 cairo_set_font_size(cr, 10.0);
2011 for (gint x = 0; x < 360 ; x++){
2012 gint ang = 360 - x ;//+ 90;
2013 if (ang > 180) {
2014 ang -= 360;
2015 }
2016 double rot = (-180.0 + x)*(M_PI/180.);
2017 double dist = half_min-9;
2018 gint inverse = 1;
2019 if((x) < 91 || (x) > 270) {
2020 inverse = -1;
2021 }
2022 if(x%10 == 0) {
2023 cairo_rotate(cr, -rot);
2024 cairo_text_extents_t extents;
2025 std::string s = std::to_string(ang) + "º";
2026 cairo_text_extents(cr, s.c_str(), &extents);
2027 //std::cout << extents.width/2 << "extents.x_bearing\n";
2028 cairo_translate(cr, (extents.width/2) * inverse * -1, (dist + ((extents.height/2)* inverse)));
2029 if((x) < 91 || (x) > 270) {
2030 cairo_rotate(cr, 180*(M_PI/180.0));
2031 }
2032 cairo_text_path(cr, s.c_str());
2033 if((x) < 91 || (x) > 270) {
2034 cairo_rotate(cr, -180*(M_PI/180.0));
2035 }
2036 cairo_translate(cr, (extents.width/2) * inverse , (dist + ((extents.height/2)* inverse)) * -1);
2037 cairo_set_source_rgba (cr, 1, 1, 1, 1);
2038 cairo_fill(cr);
2039 cairo_rotate(cr, rot);
2040 }
2041 cairo_rotate(cr, x*(M_PI/180.));
2042 if(x%5 == 0) {
2043 cairo_move_to(cr, 0, half_min-30);
2044 cairo_line_to(cr, 0, half_min-17);
2045 } else {
2046 cairo_move_to(cr, 0, half_min-20);
2047 cairo_line_to(cr, 0, half_min-15);
2048 }
2049 cairo_line_to(cr, 0, half_min-15);
2050 cairo_set_source_rgba (cr, 0, 0, 0, 0.4);
2051 cairo_set_line_width (cr,1);
2052 cairo_stroke(cr);
2053 cairo_rotate(cr, -x*(M_PI/180.));
2054 }
2055 cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
2056 cairo_translate(cr, -half_w, -half_h);
2057 cairo_arc(cr, half_w, half_h, half_min-30, 0, 2*M_PI);
2058 cairo_set_source_rgba (cr, 1, 1, 1, 1);
2059 cairo_fill(cr);
2060 cairo_translate(cr, half_w, half_h);
2061 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
2062 cairo_rotate(cr, start_angle*(M_PI/180.));
2063 cairo_move_to(cr, 0, 0);
2064 cairo_line_to(cr, 0, (half_min-17) * -1);
2065 cairo_set_source_rgba (cr, 1, 1, 1, 0.25);
2066 cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
2067 cairo_set_line_width (cr,5);
2068 cairo_stroke(cr);
2069 cairo_move_to(cr, 0, 0);
2070 cairo_line_to(cr, 0, (half_min-17) * -1);
2071 cairo_set_source_rgba (cr, 1, 0, 0, 0.9);
2072 cairo_set_line_width (cr,1);
2073 cairo_stroke(cr);
2074 cairo_rotate(cr, -start_angle*(M_PI/180.));
2075 cairo_destroy(cr);
2076 surface_measure = new_backing_store_measure;
2077
2078 cairo_surface_t *new_backing_store_grey = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height);
2079 cr = cairo_create(new_backing_store_grey);
2080 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
2081 cairo_set_source_surface(cr, _backing_store, 0, 0);
2082 cairo_paint(cr);
2083 Inkscape::Filters::FilterColorMatrix::ColorMatrixMatrix _grayscale_colormatrix = std::vector<gdouble> (grayscale_value_matrix, grayscale_value_matrix + 20);
2084 cairo_surface_t *out = ink_cairo_surface_create_identical(new_backing_store_grey);
2085 ink_cairo_surface_filter(new_backing_store_grey, out, _grayscale_colormatrix);
2086 cairo_set_source_surface(cr, out, 0, 0);
2087 cairo_surface_destroy(out);
2088 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
2089 cairo_paint(cr);
2090 cairo_destroy(cr);
2091 surface_origin = new_backing_store_grey;
2092}
2093
2094bool SPCanvas::endRotateTo()
2095{
2096 if (!_backing_store || !started) {
2097 return false;
2098 }
2099 started = false;
2100 surface_rotated = NULL;
2101 surface_origin = NULL;
2102 gtk_widget_queue_draw(GTK_WIDGET(this));
2103 dirtyAll();
2104 addIdle();
2105 rotated = true;
2106 return true;
2107}
2108
2109void SPCanvas::clearRotateTo()
2110{
2111 if (!started) {
2112 return;
2113 }
2114 gtk_widget_queue_draw(GTK_WIDGET(this));
2115 dirtyAll();
2116 addIdle();
2117}
2118
2119void SPCanvas::rotateTo(double angle)
2120{
2121 if (!_backing_store || !started) {
2122 return;
2123 }
2124 GtkAllocation allocation;
2125 gtk_widget_get_allocation(&_widget, &allocation);
2126 int half_w = allocation.width/2;
2127 int half_h = allocation.height/2;
2128 int half_min = std::min(half_w,half_h);
2129 cairo_surface_t *new_backing_store = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height);
2130 cairo_t *cr = cairo_create(new_backing_store);
2131 cairo_set_source_surface(cr, surface_origin, 0, 0);
2132 cairo_paint(cr);
2133 cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
2134 cairo_paint(cr);
2135 cairo_pattern_t *source_pattern;
2136 cairo_matrix_t matrix;
2137 source_pattern = cairo_pattern_create_for_surface (surface_rotated);
2138 cairo_matrix_init_identity (&matrix);
2139 cairo_matrix_translate (&matrix, allocation.width/2.0, allocation.height/2.0);
2140 cairo_matrix_rotate (&matrix, Geom::rad_from_deg(angle - start_angle) * -1);
2141 cairo_matrix_translate (&matrix, -allocation.width/2.0, -allocation.height/2.0);
2142 cairo_pattern_set_matrix (source_pattern, &matrix);
2143 cairo_set_source(cr, source_pattern);
2144 cairo_paint(cr);
2145 cairo_set_source_surface(cr, surface_measure, 0, 0);
2146 cairo_paint(cr);
2147 cairo_translate(cr, half_w, half_h);
2148 cairo_rotate(cr, angle*(M_PI/180.));
2149 cairo_move_to(cr, 0, 0);
2150 cairo_line_to(cr, 0, (half_min-17) * -1);
2151 cairo_set_source_rgba (cr, 1, 1, 1, 0.25);
2152 cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
2153 cairo_set_line_width (cr,5);
2154 cairo_stroke(cr);
2155 cairo_move_to(cr, 0, 0);
2156 cairo_line_to(cr, 0, (half_min-17) * -1);
2157 cairo_set_source_rgba (cr, 1, 1, 1, 0.9);
2158 cairo_set_line_width (cr,1);
2159 cairo_stroke(cr);
2160 cairo_move_to(cr, 0, 0);
2161 cairo_line_to(cr, 0, (half_min-17) * -1);
2162 cairo_set_source_rgba (cr, 1, 0, 0, 0.9);
2163 const double dashed[] = {6.0, 3.0};
2164 int len = sizeof(dashed) / sizeof(dashed[0]);
2165 cairo_set_dash(cr, dashed, len, 1);
2166 cairo_stroke(cr);
2167 cairo_translate(cr, -half_w, -half_h);
2168 cairo_set_source_rgba (cr, 1, 1, 1, 0.25);
2169 cairo_arc(cr, half_w, half_h, 7, 0, 2*M_PI);
2170 cairo_fill(cr);
2171 cairo_set_source_rgba (cr, 1, 0, 0, 0.7);
2172 cairo_arc(cr, half_w, half_h, 5, 0, 2*M_PI);
2173 cairo_fill(cr);
2174 cairo_translate(cr, half_w, half_h);
2175 cairo_rotate(cr, -angle*(M_PI/180.));
2176 cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
2177 cairo_set_font_size(cr, 15.0);
2178 cairo_text_extents_t extents;
2179 std::ostringstream s;
2180 s << _("Original angle ") << std::fixed << std::setprecision(2) << start_angle << "º";
2181 cairo_text_extents(cr, s.str().c_str(), &extents);
2182 cairo_translate(cr, half_w - extents.width -15 ,-half_h + 25);
2183 cairo_set_source_rgba (cr, 1, 1, 1, 1);
2184 cairo_text_path(cr, s.str().c_str());
2185 cairo_fill(cr);
2186 cairo_translate(cr, (half_w - extents.width -15) *-1 ,(-half_h + 25) *-1);
2187 s.str("");
2188 s << _("New angle ") << std::fixed << std::setprecision(2) << angle << "º";
2189 cairo_text_extents(cr, s.str().c_str(), &extents);
2190 cairo_translate(cr, half_w - extents.width -15 ,-half_h + 45);
2191 cairo_text_path(cr, s.str().c_str());
2192 cairo_fill(cr);
2193 cairo_translate(cr, (half_w - extents.width -15) *-1 ,(-half_h + 45) *-1);
2194 s.str("");
2195 s << _("Gap ") << std::fixed << std::setprecision(2) << std::abs(start_angle-angle) << "º";
2196 cairo_text_extents(cr, s.str().c_str(), &extents);
2197 cairo_translate(cr, half_w - extents.width -15 ,-half_h + 65);
2198 cairo_text_path(cr, s.str().c_str());
2199 cairo_fill(cr);
2200 cairo_translate(cr, (half_w - extents.width -15) *-1 ,(-half_h + 65) *-1);
2201 cairo_translate(cr, -half_w + 10 ,-half_h + 25);
2202 s.str("");
2203 cairo_set_font_size(cr, 12.0);
2204 s << _("Normal mode, 1º round step");
2205 cairo_text_path(cr, s.str().c_str());
2206 cairo_fill(cr);
2207 cairo_translate(cr, (-half_w +10) * -1 ,(-half_h + 25) * -1);
2208 cairo_translate(cr, -half_w + 10 ,-half_h + 40);
2209 s.str("");
2210 s << _("+ALT, Fractional degrees");
2211 cairo_text_path(cr, s.str().c_str());
2212 cairo_fill(cr);
2213 cairo_translate(cr, (-half_w + 10) * -1 ,(-half_h + 40) * -1);
2214 cairo_translate(cr, -half_w + 10 ,-half_h + 55);
2215 s.str("");
2216 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
2217 s << _("+CTRL, ") << 180.0/prefs->getInt("/options/rotationsnapsperpi/value", 12) << _("º round step");
2218 cairo_text_path(cr, s.str().c_str());
2219 cairo_fill(cr);
2220 cairo_translate(cr, (-half_w + 10) * -1 ,(-half_h + 55) * -1);
2221 cairo_translate(cr, -half_w + 10 ,-half_h + 70);
2222 s.str("");
2223 s << _("+SHIFT, Reset");
2224 cairo_text_path(cr, s.str().c_str());
2225 cairo_fill(cr);
2226 cairo_translate(cr, (-half_w + 10) * -1 ,(-half_h + 70) * -1);
2227 cairo_translate(cr, -half_w + 10 ,-half_h + 85);
2228 s.str("");
2229 s << _("+CTRL+SHIFT, 0º");
2230 cairo_text_path(cr, s.str().c_str());
2231 cairo_fill(cr);
2232 //cairo_translate(cr, (-half_w + 10) * -1 ,(-half_h + 60) * -1);
2233 cairo_destroy(cr);
2234 cairo_surface_destroy(_backing_store);
2235 _backing_store = new_backing_store;
2236 cairo_pattern_destroy (source_pattern);
2237 gtk_widget_queue_draw(GTK_WIDGET(this));
2238 addIdle();
2239}
2240
1952void SPCanvas::updateNow()2241void SPCanvas::updateNow()
1953{2242{
1954 if (_need_update) {2243 if (_need_update) {
19552244
=== modified file 'src/display/sp-canvas.h'
--- src/display/sp-canvas.h 2016-08-12 04:11:03 +0000
+++ src/display/sp-canvas.h 2017-01-24 17:53:20 +0000
@@ -72,7 +72,10 @@
72struct SPCanvas {72struct SPCanvas {
73 /// Scrolls canvas to specific position (cx and cy are measured in screen pixels).73 /// Scrolls canvas to specific position (cx and cy are measured in screen pixels).
74 void scrollTo(double cx, double cy, unsigned int clear, bool is_scrolling = false);74 void scrollTo(double cx, double cy, unsigned int clear, bool is_scrolling = false);
7575 void startRotateTo(double angle);
76 void rotateTo(double angle);
77 bool endRotateTo();
78 void clearRotateTo();
76 /// Synchronously updates the canvas if necessary.79 /// Synchronously updates the canvas if necessary.
77 void updateNow();80 void updateNow();
7881
7982
=== modified file 'src/document-undo.cpp'
--- src/document-undo.cpp 2017-01-24 00:02:46 +0000
+++ src/document-undo.cpp 2017-01-24 17:53:20 +0000
@@ -240,49 +240,52 @@
240240
241gboolean Inkscape::DocumentUndo::undo(SPDocument *doc)241gboolean Inkscape::DocumentUndo::undo(SPDocument *doc)
242{242{
243 using Inkscape::Debug::EventTracker;243 using Inkscape::Debug::EventTracker;
244 using Inkscape::Debug::SimpleEvent;244 using Inkscape::Debug::SimpleEvent;
245245
246 gboolean ret;246 gboolean ret;
247247
248 EventTracker<SimpleEvent<Inkscape::Debug::Event::DOCUMENT> > tracker("undo");248 EventTracker<SimpleEvent<Inkscape::Debug::Event::DOCUMENT> > tracker("undo");
249249
250 g_assert (doc != NULL);250 g_assert (doc != NULL);
251 g_assert (doc->priv != NULL);251 g_assert (doc->priv != NULL);
252 g_assert (doc->priv->sensitive);252 g_assert (doc->priv->sensitive);
253253
254 doc->priv->sensitive = FALSE;254 doc->priv->sensitive = FALSE;
255 doc->priv->seeking = true;255 doc->priv->seeking = true;
256256
257 doc->actionkey.clear();257 doc->actionkey.clear();
258258
259 finish_incomplete_transaction(*doc);259 finish_incomplete_transaction(*doc);
260260
261 if (! doc->priv->undo.empty()) {261 if (! doc->priv->undo.empty()) {
262 Inkscape::Event *log = doc->priv->undo.back();262 Inkscape::Event *log = doc->priv->undo.back();
263 doc->priv->undo.pop_back();263 doc->priv->undo.pop_back();
264 sp_repr_undo_log (log->event);264 sp_repr_undo_log (log->event);
265 perform_document_update(*doc);265 perform_document_update(*doc);
266266
267 doc->priv->redo.push_back(log);267 doc->priv->redo.push_back(log);
268268
269 doc->setModifiedSinceSave();269 doc->setModifiedSinceSave();
270 doc->priv->undoStackObservers.notifyUndoEvent(log);270 doc->priv->undoStackObservers.notifyUndoEvent(log);
271271
272 ret = TRUE;272 ret = TRUE;
273 } else {273 } else {
274 ret = FALSE;274 ret = FALSE;
275 }275 }
276276
277 sp_repr_begin_transaction (doc->rdoc);277 sp_repr_begin_transaction (doc->rdoc);
278278
279 doc->priv->sensitive = TRUE;279 doc->priv->sensitive = TRUE;
280 doc->priv->seeking = false;280 doc->priv->seeking = false;
281281
282 if (ret)282 if (ret) INKSCAPE.external_change();
283 INKSCAPE.external_change();
284283
285 return ret;284 SPObject *updated = doc->getRoot();
285 if (updated) {
286 updated->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
287 }
288 return ret;
286}289}
287290
288gboolean Inkscape::DocumentUndo::redo(SPDocument *doc)291gboolean Inkscape::DocumentUndo::redo(SPDocument *doc)
289292
=== modified file 'src/document.cpp'
--- src/document.cpp 2016-11-28 22:07:00 +0000
+++ src/document.cpp 2017-01-24 17:53:20 +0000
@@ -386,6 +386,7 @@
386 if (!bordercolor.empty()) {386 if (!bordercolor.empty()) {
387 rnew->setAttribute("bordercolor", bordercolor.data());387 rnew->setAttribute("bordercolor", bordercolor.data());
388 }388 }
389 sp_repr_set_svg_double(rnew, "inkscape:document-rotation", 0.);
389 sp_repr_set_svg_double(rnew, "borderopacity",390 sp_repr_set_svg_double(rnew, "borderopacity",
390 prefs->getDouble("/template/base/borderopacity", 1.0));391 prefs->getDouble("/template/base/borderopacity", 1.0));
391 sp_repr_set_svg_double(rnew, "objecttolerance",392 sp_repr_set_svg_double(rnew, "objecttolerance",
@@ -407,6 +408,11 @@
407 rroot->addChild(rnew, NULL);408 rroot->addChild(rnew, NULL);
408 // clean up409 // clean up
409 Inkscape::GC::release(rnew);410 Inkscape::GC::release(rnew);
411 } else {
412 Inkscape::XML::Node *nv_repr = sp_item_group_get_child_by_name(document->root, NULL, "sodipodi:namedview")->getRepr();
413 if (!nv_repr->attribute("inkscape:document-rotation")) {
414 sp_repr_set_svg_double(nv_repr, "inkscape:document-rotation", 0.);
415 }
410 }416 }
411417
412 // Defs418 // Defs
413419
=== modified file 'src/extension/internal/cairo-png-out.cpp'
--- src/extension/internal/cairo-png-out.cpp 2014-03-27 01:33:44 +0000
+++ src/extension/internal/cairo-png-out.cpp 2017-01-24 17:53:20 +0000
@@ -53,11 +53,10 @@
53{53{
54 CairoRenderer *renderer;54 CairoRenderer *renderer;
55 CairoRenderContext *ctx;55 CairoRenderContext *ctx;
5656 doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p;
57 doc->ensureUpToDate();57 doc->ensureUpToDate();
5858
59/* Start */59/* Start */
60
61 SPItem *base = doc->getRoot();60 SPItem *base = doc->getRoot();
62 Inkscape::Drawing drawing;61 Inkscape::Drawing drawing;
63 unsigned dkey = SPItem::display_key_new(1);62 unsigned dkey = SPItem::display_key_new(1);
@@ -77,6 +76,7 @@
77 renderer->destroyContext(ctx);76 renderer->destroyContext(ctx);
7877
79 base->invoke_hide(dkey);78 base->invoke_hide(dkey);
79 doc->getRoot()->c2p *= doc->getRoot()->rotation;
80/* end */80/* end */
81 delete renderer;81 delete renderer;
8282
8383
=== modified file 'src/extension/internal/cairo-ps-out.cpp'
--- src/extension/internal/cairo-ps-out.cpp 2016-06-11 17:25:23 +0000
+++ src/extension/internal/cairo-ps-out.cpp 2017-01-24 17:53:20 +0000
@@ -68,6 +68,7 @@
68ps_print_document_to_file(SPDocument *doc, gchar const *filename, unsigned int level, bool texttopath, bool omittext,68ps_print_document_to_file(SPDocument *doc, gchar const *filename, unsigned int level, bool texttopath, bool omittext,
69 bool filtertobitmap, int resolution, const gchar * const exportId, bool exportDrawing, bool exportCanvas, float bleedmargin_px, bool eps = false)69 bool filtertobitmap, int resolution, const gchar * const exportId, bool exportDrawing, bool exportCanvas, float bleedmargin_px, bool eps = false)
70{70{
71 doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p;
71 doc->ensureUpToDate();72 doc->ensureUpToDate();
7273
73 SPItem *base = NULL;74 SPItem *base = NULL;
@@ -84,9 +85,10 @@
84 pageBoundingBox = !exportDrawing;85 pageBoundingBox = !exportDrawing;
85 }86 }
8687
87 if (!base)88 if (!base) {
89 doc->getRoot()->c2p *= doc->getRoot()->rotation;
88 return false;90 return false;
8991 }
90 Inkscape::Drawing drawing;92 Inkscape::Drawing drawing;
91 unsigned dkey = SPItem::display_key_new(1);93 unsigned dkey = SPItem::display_key_new(1);
92 base->invoke_show(drawing, dkey, SP_ITEM_SHOW_DISPLAY);94 base->invoke_show(drawing, dkey, SP_ITEM_SHOW_DISPLAY);
@@ -115,6 +117,7 @@
115117
116 renderer->destroyContext(ctx);118 renderer->destroyContext(ctx);
117 delete renderer;119 delete renderer;
120 doc->getRoot()->c2p *= doc->getRoot()->rotation;
118121
119 return ret;122 return ret;
120}123}
121124
=== modified file 'src/extension/internal/cairo-renderer-pdf-out.cpp'
--- src/extension/internal/cairo-renderer-pdf-out.cpp 2016-06-11 17:25:23 +0000
+++ src/extension/internal/cairo-renderer-pdf-out.cpp 2017-01-24 17:53:20 +0000
@@ -61,6 +61,7 @@
61 bool texttopath, bool omittext, bool filtertobitmap, int resolution,61 bool texttopath, bool omittext, bool filtertobitmap, int resolution,
62 const gchar * const exportId, bool exportDrawing, bool exportCanvas, float bleedmargin_px)62 const gchar * const exportId, bool exportDrawing, bool exportCanvas, float bleedmargin_px)
63{63{
64 doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p;
64 doc->ensureUpToDate();65 doc->ensureUpToDate();
6566
66/* Start */67/* Start */
@@ -80,6 +81,7 @@
80 }81 }
8182
82 if (!base) {83 if (!base) {
84 doc->getRoot()->c2p *= doc->getRoot()->rotation;
83 return false;85 return false;
84 }86 }
85 87
@@ -112,7 +114,7 @@
112114
113 renderer->destroyContext(ctx);115 renderer->destroyContext(ctx);
114 delete renderer;116 delete renderer;
115117 doc->getRoot()->c2p *= doc->getRoot()->rotation;
116 return ret;118 return ret;
117}119}
118120
119121
=== modified file 'src/extension/internal/emf-inout.cpp'
--- src/extension/internal/emf-inout.cpp 2016-06-11 17:25:23 +0000
+++ src/extension/internal/emf-inout.cpp 2017-01-24 17:53:20 +0000
@@ -94,7 +94,7 @@
94 const gchar *oldconst;94 const gchar *oldconst;
95 gchar *oldoutput;95 gchar *oldoutput;
96 unsigned int ret;96 unsigned int ret;
9797 doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p;
98 doc->ensureUpToDate();98 doc->ensureUpToDate();
9999
100 mod = Inkscape::Extension::get_print(PRINT_EMF);100 mod = Inkscape::Extension::get_print(PRINT_EMF);
@@ -114,6 +114,7 @@
114 /* Print document */114 /* Print document */
115 ret = mod->begin(doc);115 ret = mod->begin(doc);
116 if (ret) {116 if (ret) {
117 doc->getRoot()->c2p *= doc->getRoot()->rotation;
117 g_free(oldoutput);118 g_free(oldoutput);
118 throw Inkscape::Extension::Output::save_failed();119 throw Inkscape::Extension::Output::save_failed();
119 }120 }
@@ -127,7 +128,7 @@
127128
128 mod->set_param_string("destination", oldoutput);129 mod->set_param_string("destination", oldoutput);
129 g_free(oldoutput);130 g_free(oldoutput);
130131 doc->getRoot()->c2p *= doc->getRoot()->rotation;
131 return;132 return;
132}133}
133134
134135
=== modified file 'src/extension/internal/javafx-out.cpp'
--- src/extension/internal/javafx-out.cpp 2016-07-14 11:17:21 +0000
+++ src/extension/internal/javafx-out.cpp 2017-01-24 17:53:20 +0000
@@ -843,7 +843,8 @@
843bool JavaFXOutput::saveDocument(SPDocument *doc, gchar const *filename_utf8)843bool JavaFXOutput::saveDocument(SPDocument *doc, gchar const *filename_utf8)
844{844{
845 reset();845 reset();
846846 doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p;
847 doc->ensureUpToDate();
847848
848 name = Glib::path_get_basename(filename_utf8);849 name = Glib::path_get_basename(filename_utf8);
849 int pos = name.find('.');850 int pos = name.find('.');
@@ -856,12 +857,14 @@
856 //# Lets do the curves first, to get the stats857 //# Lets do the curves first, to get the stats
857858
858 if (!doTree(doc)) {859 if (!doTree(doc)) {
860 doc->getRoot()->c2p *= doc->getRoot()->rotation;
859 return false;861 return false;
860 }862 }
861 String curveBuf = outbuf;863 String curveBuf = outbuf;
862 outbuf.clear();864 outbuf.clear();
863865
864 if (!doHeader()) {866 if (!doHeader()) {
867 doc->getRoot()->c2p *= doc->getRoot()->rotation;
865 return false;868 return false;
866 }869 }
867870
@@ -875,6 +878,7 @@
875 doBody(doc, doc->getRoot());878 doBody(doc, doc->getRoot());
876879
877 if (!doTail()) {880 if (!doTail()) {
881 doc->getRoot()->c2p *= doc->getRoot()->rotation;
878 return false;882 return false;
879 }883 }
880884
@@ -884,6 +888,7 @@
884 FILE *f = Inkscape::IO::fopen_utf8name(filename_utf8, "w");888 FILE *f = Inkscape::IO::fopen_utf8name(filename_utf8, "w");
885 if (!f)889 if (!f)
886 {890 {
891 doc->getRoot()->c2p *= doc->getRoot()->rotation;
887 err("Could open JavaFX file '%s' for writing", filename_utf8);892 err("Could open JavaFX file '%s' for writing", filename_utf8);
888 return false;893 return false;
889 }894 }
@@ -894,7 +899,7 @@
894 }899 }
895900
896 fclose(f);901 fclose(f);
897902 doc->getRoot()->c2p *= doc->getRoot()->rotation;
898 return true;903 return true;
899}904}
900905
901906
=== modified file 'src/extension/internal/latex-pstricks-out.cpp'
--- src/extension/internal/latex-pstricks-out.cpp 2012-04-18 07:02:24 +0000
+++ src/extension/internal/latex-pstricks-out.cpp 2017-01-24 17:53:20 +0000
@@ -49,6 +49,7 @@
49void LatexOutput::save(Inkscape::Extension::Output * /*mod2*/, SPDocument *doc, gchar const *filename)49void LatexOutput::save(Inkscape::Extension::Output * /*mod2*/, SPDocument *doc, gchar const *filename)
50{50{
51 SPPrintContext context;51 SPPrintContext context;
52 doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p;
52 doc->ensureUpToDate();53 doc->ensureUpToDate();
5354
54 Inkscape::Extension::Print *mod = Inkscape::Extension::get_print(SP_MODULE_KEY_PRINT_LATEX);55 Inkscape::Extension::Print *mod = Inkscape::Extension::get_print(SP_MODULE_KEY_PRINT_LATEX);
@@ -76,6 +77,7 @@
7677
77 mod->set_param_string("destination", oldoutput);78 mod->set_param_string("destination", oldoutput);
78 g_free(oldoutput);79 g_free(oldoutput);
80 doc->getRoot()->c2p *= doc->getRoot()->rotation;
79}81}
8082
81#include "clear-n_.h"83#include "clear-n_.h"
8284
=== modified file 'src/extension/internal/odf.cpp'
--- src/extension/internal/odf.cpp 2016-08-17 07:39:43 +0000
+++ src/extension/internal/odf.cpp 2017-01-24 17:53:20 +0000
@@ -72,6 +72,7 @@
72#include "sp-path.h"72#include "sp-path.h"
73#include "sp-text.h"73#include "sp-text.h"
74#include "sp-flowtext.h"74#include "sp-flowtext.h"
75#include "sp-root.h"
75#include "svg/svg.h"76#include "svg/svg.h"
76#include "text-editing.h"77#include "text-editing.h"
77#include "util/units.h"78#include "util/units.h"
@@ -2095,7 +2096,8 @@
2095void OdfOutput::save(Inkscape::Extension::Output */*mod*/, SPDocument *doc, gchar const *filename)2096void OdfOutput::save(Inkscape::Extension::Output */*mod*/, SPDocument *doc, gchar const *filename)
2096{2097{
2097 reset();2098 reset();
20982099 doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p;
2100 doc->ensureUpToDate();
2099 documentUri = Inkscape::URI(filename);2101 documentUri = Inkscape::URI(filename);
21002102
2101 ZipFile zf;2103 ZipFile zf;
@@ -2104,25 +2106,30 @@
2104 if (!writeManifest(zf))2106 if (!writeManifest(zf))
2105 {2107 {
2106 g_warning("Failed to write manifest");2108 g_warning("Failed to write manifest");
2109 doc->getRoot()->c2p *= doc->getRoot()->rotation;
2107 return;2110 return;
2108 }2111 }
21092112
2110 if (!writeContent(zf, doc->rroot))2113 if (!writeContent(zf, doc->rroot))
2111 {2114 {
2112 g_warning("Failed to write content");2115 g_warning("Failed to write content");
2116 doc->getRoot()->c2p *= doc->getRoot()->rotation;
2113 return;2117 return;
2114 }2118 }
21152119
2116 if (!writeMeta(zf))2120 if (!writeMeta(zf))
2117 {2121 {
2118 g_warning("Failed to write metafile");2122 g_warning("Failed to write metafile");
2123 doc->getRoot()->c2p *= doc->getRoot()->rotation;
2119 return;2124 return;
2120 }2125 }
21212126
2122 if (!zf.writeFile(filename))2127 if (!zf.writeFile(filename))
2123 {2128 {
2129 doc->getRoot()->c2p *= doc->getRoot()->rotation;
2124 return;2130 return;
2125 }2131 }
2132 doc->getRoot()->c2p *= doc->getRoot()->rotation;
2126}2133}
21272134
21282135
21292136
=== modified file 'src/extension/internal/pov-out.cpp'
--- src/extension/internal/pov-out.cpp 2016-07-14 11:17:21 +0000
+++ src/extension/internal/pov-out.cpp 2017-01-24 17:53:20 +0000
@@ -616,11 +616,13 @@
616void PovOutput::saveDocument(SPDocument *doc, gchar const *filename_utf8)616void PovOutput::saveDocument(SPDocument *doc, gchar const *filename_utf8)
617{617{
618 reset();618 reset();
619619 doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p;
620 doc->ensureUpToDate();
620 //###### SAVE IN POV FORMAT TO BUFFER621 //###### SAVE IN POV FORMAT TO BUFFER
621 //# Lets do the curves first, to get the stats622 //# Lets do the curves first, to get the stats
622 if (!doTree(doc))623 if (!doTree(doc))
623 {624 {
625 doc->getRoot()->c2p *= doc->getRoot()->rotation;
624 err("Could not output curves for %s", filename_utf8);626 err("Could not output curves for %s", filename_utf8);
625 return;627 return;
626 }628 }
@@ -630,6 +632,7 @@
630632
631 if (!doHeader())633 if (!doHeader())
632 {634 {
635 doc->getRoot()->c2p *= doc->getRoot()->rotation;
633 err("Could not write header for %s", filename_utf8);636 err("Could not write header for %s", filename_utf8);
634 return;637 return;
635 }638 }
@@ -638,6 +641,7 @@
638641
639 if (!doTail())642 if (!doTail())
640 {643 {
644 doc->getRoot()->c2p *= doc->getRoot()->rotation;
641 err("Could not write footer for %s", filename_utf8);645 err("Could not write footer for %s", filename_utf8);
642 return;646 return;
643 }647 }
@@ -648,9 +652,11 @@
648 //###### WRITE TO FILE652 //###### WRITE TO FILE
649 Inkscape::IO::dump_fopen_call(filename_utf8, "L");653 Inkscape::IO::dump_fopen_call(filename_utf8, "L");
650 FILE *f = Inkscape::IO::fopen_utf8name(filename_utf8, "w");654 FILE *f = Inkscape::IO::fopen_utf8name(filename_utf8, "w");
651 if (!f)655 if (!f){
656 doc->getRoot()->c2p *= doc->getRoot()->rotation;
652 return;657 return;
653658 }
659
654 for (String::iterator iter = outbuf.begin() ; iter!=outbuf.end(); ++iter)660 for (String::iterator iter = outbuf.begin() ; iter!=outbuf.end(); ++iter)
655 {661 {
656 int ch = *iter;662 int ch = *iter;
@@ -658,6 +664,7 @@
658 }664 }
659665
660 fclose(f);666 fclose(f);
667 doc->getRoot()->c2p *= doc->getRoot()->rotation;
661}668}
662669
663670
664671
=== modified file 'src/extension/internal/wmf-inout.cpp'
--- src/extension/internal/wmf-inout.cpp 2016-06-11 17:25:23 +0000
+++ src/extension/internal/wmf-inout.cpp 2017-01-24 17:53:20 +0000
@@ -95,7 +95,7 @@
95 SPPrintContext context;95 SPPrintContext context;
96 const gchar *oldconst;96 const gchar *oldconst;
97 gchar *oldoutput;97 gchar *oldoutput;
9898 doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p;
99 doc->ensureUpToDate();99 doc->ensureUpToDate();
100100
101 mod = Inkscape::Extension::get_print(PRINT_WMF);101 mod = Inkscape::Extension::get_print(PRINT_WMF);
@@ -115,6 +115,7 @@
115 /* Print document */115 /* Print document */
116 if (mod->begin(doc)) {116 if (mod->begin(doc)) {
117 g_free(oldoutput);117 g_free(oldoutput);
118 doc->getRoot()->c2p *= doc->getRoot()->rotation;
118 throw Inkscape::Extension::Output::save_failed();119 throw Inkscape::Extension::Output::save_failed();
119 }120 }
120 mod->base->invoke_print(&context);121 mod->base->invoke_print(&context);
@@ -127,7 +128,7 @@
127128
128 mod->set_param_string("destination", oldoutput);129 mod->set_param_string("destination", oldoutput);
129 g_free(oldoutput);130 g_free(oldoutput);
130131 doc->getRoot()->c2p *= doc->getRoot()->rotation;
131 return;132 return;
132}133}
133134
@@ -135,6 +136,8 @@
135void136void
136Wmf::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filename)137Wmf::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filename)
137{138{
139 doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p;
140 doc->ensureUpToDate();
138 Inkscape::Extension::Extension * ext;141 Inkscape::Extension::Extension * ext;
139142
140 ext = Inkscape::Extension::db.get(PRINT_WMF);143 ext = Inkscape::Extension::db.get(PRINT_WMF);
141144
=== modified file 'src/file.cpp'
--- src/file.cpp 2017-01-24 00:39:06 +0000
+++ src/file.cpp 2017-01-24 17:53:20 +0000
@@ -293,10 +293,12 @@
293 bool replace_empty)293 bool replace_empty)
294{294{
295 SPDesktop *desktop = SP_ACTIVE_DESKTOP;295 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
296 Inkscape::Display::TemporaryItem *page_border_rotated = NULL;
296 if (desktop) {297 if (desktop) {
297 desktop->setWaitingCursor();298 desktop->setWaitingCursor();
299 page_border_rotated = sp_document_namedview(desktop->getDocument(), NULL)->page_border_rotated;
298 }300 }
299301
300 SPDocument *doc = NULL;302 SPDocument *doc = NULL;
301 bool cancelled = false;303 bool cancelled = false;
302 try {304 try {
@@ -315,7 +317,6 @@
315 }317 }
316318
317 if (doc) {319 if (doc) {
318
319 SPDocument *existing = desktop ? desktop->getDocument() : NULL;320 SPDocument *existing = desktop ? desktop->getDocument() : NULL;
320321
321 if (existing && existing->virgin && replace_empty) {322 if (existing && existing->virgin && replace_empty) {
@@ -323,6 +324,7 @@
323 doc->ensureUpToDate(); // TODO this will trigger broken link warnings, etc.324 doc->ensureUpToDate(); // TODO this will trigger broken link warnings, etc.
324 desktop->change_document(doc);325 desktop->change_document(doc);
325 doc->emitResizedSignal(doc->getWidth().value("px"), doc->getHeight().value("px"));326 doc->emitResizedSignal(doc->getWidth().value("px"), doc->getHeight().value("px"));
327 desktop->remove_temporary_canvasitem(page_border_rotated);
326 } else {328 } else {
327 // create a whole new desktop and window329 // create a whole new desktop and window
328 SPViewWidget *dtw = sp_desktop_widget_new(sp_document_namedview(doc, NULL)); // TODO this will trigger broken link warnings, etc.330 SPViewWidget *dtw = sp_desktop_widget_new(sp_document_namedview(doc, NULL)); // TODO this will trigger broken link warnings, etc.
329331
=== modified file 'src/print.cpp'
--- src/print.cpp 2012-02-27 23:49:20 +0000
+++ src/print.cpp 2017-01-24 17:53:20 +0000
@@ -79,6 +79,7 @@
79void79void
80sp_print_document(Gtk::Window& parentWindow, SPDocument *doc)80sp_print_document(Gtk::Window& parentWindow, SPDocument *doc)
81{81{
82 doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p;
82 doc->ensureUpToDate();83 doc->ensureUpToDate();
8384
84 // Build arena85 // Build arena
@@ -88,6 +89,7 @@
88 Inkscape::UI::Dialog::Print printop(doc,base);89 Inkscape::UI::Dialog::Print printop(doc,base);
89 Gtk::PrintOperationResult res = printop.run(Gtk::PRINT_OPERATION_ACTION_PRINT_DIALOG, parentWindow);90 Gtk::PrintOperationResult res = printop.run(Gtk::PRINT_OPERATION_ACTION_PRINT_DIALOG, parentWindow);
90 (void)res; // TODO handle this91 (void)res; // TODO handle this
92 doc->getRoot()->c2p *= doc->getRoot()->rotation;
91}93}
9294
93void sp_print_document_to_file(SPDocument *doc, gchar const *filename)95void sp_print_document_to_file(SPDocument *doc, gchar const *filename)
9496
=== modified file 'src/sp-namedview.cpp'
--- src/sp-namedview.cpp 2016-08-03 14:56:48 +0000
+++ src/sp-namedview.cpp 2017-01-24 17:53:20 +0000
@@ -19,7 +19,12 @@
19#include "event-log.h"19#include "event-log.h"
20#include <2geom/transforms.h>20#include <2geom/transforms.h>
2121
22#include "display/sp-canvas-group.h"
23#include "display/canvas-bpath.h"
24#include "display/canvas-temporary-item.h"
25#include "display/canvas-temporary-item-list.h"
22#include "display/canvas-grid.h"26#include "display/canvas-grid.h"
27#include "display/curve.h"
23#include "util/units.h"28#include "util/units.h"
24#include "svg/svg-color.h"29#include "svg/svg-color.h"
25#include "xml/repr.h"30#include "xml/repr.h"
@@ -29,12 +34,15 @@
29#include "desktop-events.h"34#include "desktop-events.h"
3035
31#include "sp-guide.h"36#include "sp-guide.h"
37#include "sp-root.h"
32#include "sp-item-group.h"38#include "sp-item-group.h"
33#include "sp-namedview.h"39#include "sp-namedview.h"
34#include "preferences.h"40#include "preferences.h"
35#include "desktop.h"41#include "desktop.h"
42#include "selection.h"
43#include "object-set.h"
44#include "inkscape.h"
36#include "conn-avoid-ref.h" // for defaultConnSpacing.45#include "conn-avoid-ref.h" // for defaultConnSpacing.
37#include "sp-root.h"
38#include <gtkmm/window.h>46#include <gtkmm/window.h>
3947
40using Inkscape::DocumentUndo;48using Inkscape::DocumentUndo;
@@ -72,6 +80,7 @@
72 this->pagecolor = 0;80 this->pagecolor = 0;
73 this->cx = 0;81 this->cx = 0;
74 this->pageshadow = 0;82 this->pageshadow = 0;
83 this->document_rotation = 0;
75 this->window_width = 0;84 this->window_width = 0;
76 this->window_height = 0;85 this->window_height = 0;
77 this->window_maximized = 0;86 this->window_maximized = 0;
@@ -92,9 +101,13 @@
92 this->default_layer_id = 0;101 this->default_layer_id = 0;
93102
94 this->connector_spacing = defaultConnSpacing;103 this->connector_spacing = defaultConnSpacing;
104 this->page_border_rotated = NULL;
95}105}
96106
97SPNamedView::~SPNamedView() {107SPNamedView::~SPNamedView() {
108 if(!this->getViewList().empty()) { // >0 Desktops
109 this->getViewList()[0]->remove_temporary_canvasitem(this->page_border_rotated);
110 }
98}111}
99112
100static void sp_namedview_generate_old_grid(SPNamedView * /*nv*/, SPDocument *document, Inkscape::XML::Node *repr) {113static void sp_namedview_generate_old_grid(SPNamedView * /*nv*/, SPDocument *document, Inkscape::XML::Node *repr) {
@@ -212,6 +225,7 @@
212 this->readAttr( "inkscape:zoom" );225 this->readAttr( "inkscape:zoom" );
213 this->readAttr( "inkscape:cx" );226 this->readAttr( "inkscape:cx" );
214 this->readAttr( "inkscape:cy" );227 this->readAttr( "inkscape:cy" );
228 this->readAttr( "inkscape:document-rotation" );
215 this->readAttr( "inkscape:window-width" );229 this->readAttr( "inkscape:window-width" );
216 this->readAttr( "inkscape:window-height" );230 this->readAttr( "inkscape:window-height" );
217 this->readAttr( "inkscape:window-x" );231 this->readAttr( "inkscape:window-x" );
@@ -409,6 +423,11 @@
409 this->cy = value ? g_ascii_strtod(value, NULL) : HUGE_VAL; // HUGE_VAL means not set423 this->cy = value ? g_ascii_strtod(value, NULL) : HUGE_VAL; // HUGE_VAL means not set
410 this->requestModified(SP_OBJECT_MODIFIED_FLAG);424 this->requestModified(SP_OBJECT_MODIFIED_FLAG);
411 break;425 break;
426 case SP_ATTR_INKSCAPE_DOCUMENT_ROTATION:
427 this->document_rotation = value ? g_ascii_strtod(value, NULL) : 0;
428 sp_namedview_set_document_rotation(this);
429 this->requestModified(SP_OBJECT_MODIFIED_FLAG);
430 break;
412 case SP_ATTR_INKSCAPE_WINDOW_WIDTH:431 case SP_ATTR_INKSCAPE_WINDOW_WIDTH:
413 this->window_width = value? atoi(value) : -1; // -1 means not set432 this->window_width = value? atoi(value) : -1; // -1 means not set
414 this->requestModified(SP_OBJECT_MODIFIED_FLAG);433 this->requestModified(SP_OBJECT_MODIFIED_FLAG);
@@ -939,6 +958,81 @@
939 }958 }
940}959}
941960
961void sp_namedview_doc_rotate_guides(SPNamedView *nv)
962{
963 bool saved = DocumentUndo::getUndoSensitive(nv->document);
964 DocumentUndo::setUndoSensitive(nv->document, false);
965 SPRoot * root = nv->document->getRoot();
966 Geom::Point page_center = root->viewBox.midpoint() * root->vbt;
967 Geom::Affine rot = Geom::identity();
968 rot *= Geom::Translate(page_center).inverse();
969 rot *= Geom::Rotate(Geom::rad_from_deg((nv->document_rotation - root->get_rotation()) * -1));
970 rot *= Geom::Translate(page_center);
971 for(std::vector<SPGuide *>::iterator it=nv->guides.begin();it!=nv->guides.end();++it ) {
972 Geom::Point const on_line = (*it)->getPoint() * rot ;
973 (*it)->moveto(on_line, true);
974 Geom::Affine rot_normal_affine = Geom::Rotate(Geom::rad_from_deg((nv->document_rotation - root->get_rotation()) * -1));
975 Geom::Point const rot_normal = (*it)->getNormal() * rot_normal_affine;
976 (*it)->set_normal(rot_normal, true);
977 }
978 DocumentUndo::setUndoSensitive(nv->document, saved);
979 nv->document->setModifiedSinceSave();
980}
981
982void sp_namedview_set_document_rotation(SPNamedView *nv)
983{
984 if ( nv->document->getRoot()->get_rotation() == nv->document_rotation) return;
985 if(!nv->getViewList().empty()) { // >0 Desktops
986 SPDesktop *desktop = nv->getViewList()[0];
987 desktop->remove_temporary_canvasitem(nv->page_border_rotated);
988 SPRoot * root = nv->document->getRoot();
989 SPCurve *c = new SPCurve();
990 c->moveto(root->viewBox.min());
991 c->lineto(Geom::Point(root->viewBox.max()[Geom::X],root->viewBox.min()[Geom::Y]));
992 c->lineto(Geom::Point(root->viewBox.max()[Geom::X],root->viewBox.max()[Geom::Y]));
993 c->lineto(Geom::Point(root->viewBox.min()[Geom::X],root->viewBox.max()[Geom::Y]));
994 c->closepath();
995 Geom::Point page_center = root->viewBox.midpoint();
996 Geom::PathVector const box = c->get_pathvector();
997 Geom::Affine rot = Geom::identity();
998 rot *= Geom::Translate(page_center).inverse();
999 rot *= Geom::Rotate(Geom::rad_from_deg(nv->document_rotation * -1));
1000 rot *= Geom::Translate(page_center);
1001 if (nv->document_rotation) {
1002 SPCanvasItem *canvas_border = sp_canvas_bpath_new(desktop->getTempGroup(), c, true);
1003 sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(canvas_border), 0xFF00009A, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
1004 sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(canvas_border), 0, SP_WIND_RULE_NONZERO);
1005 sp_canvas_item_affine_absolute(canvas_border, rot * root->vbt);
1006 nv->page_border_rotated = desktop->add_temporary_canvasitem(canvas_border, 0);
1007 }
1008 sp_namedview_doc_rotate_guides(nv);
1009 nv->document->getRoot()->set_rotation(nv->document_rotation);
1010 c->unref();
1011 }
1012 if (nv->document_rotation) {
1013 nv->showborder = FALSE;
1014 } else {
1015 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1016 nv->showborder = prefs->getBool("/template/base/showborder", 1.0);
1017 }
1018
1019 SPDesktop * desktop = SP_ACTIVE_DESKTOP;
1020 if (desktop) {
1021//TODO: Remove knots of shapes on selected items
1022// Inkscape::Selection * sel = desktop->getSelection();
1023// std::vector<SPItem*> il(sel->items().begin(), sel->items().end());
1024// for (std::vector<SPItem*>::const_iterator l = il.begin(); l != il.end(); l++){
1025// SPItem *item = *l;
1026// sel->remove(item->getRepr());
1027// sel->add(item->getRepr());
1028// }
1029 SPObject *updated = desktop->getDocument()->getRoot();
1030 if (updated) {
1031 updated->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
1032 }
1033 }
1034}
1035
942static void sp_namedview_show_single_guide(SPGuide* guide, bool show)1036static void sp_namedview_show_single_guide(SPGuide* guide, bool show)
943{1037{
944 if (show) {1038 if (show) {
@@ -953,6 +1047,8 @@
953 guide->set_locked(locked, true);1047 guide->set_locked(locked, true);
954}1048}
9551049
1050
1051
956void sp_namedview_toggle_guides(SPDocument *doc, Inkscape::XML::Node *repr)1052void sp_namedview_toggle_guides(SPDocument *doc, Inkscape::XML::Node *repr)
957{1053{
958 unsigned int v;1054 unsigned int v;
9591055
=== modified file 'src/sp-namedview.h'
--- src/sp-namedview.h 2016-06-08 08:35:36 +0000
+++ src/sp-namedview.h 2017-01-24 17:53:20 +0000
@@ -21,6 +21,7 @@
21#include "snap.h"21#include "snap.h"
22#include "document.h"22#include "document.h"
23#include "util/units.h"23#include "util/units.h"
24#include "display/sp-canvas.h"
24#include <vector>25#include <vector>
2526
26namespace Inkscape {27namespace Inkscape {
@@ -28,6 +29,9 @@
28 namespace Util {29 namespace Util {
29 class Unit;30 class Unit;
30 }31 }
32 namespace Display {
33 class TemporaryItem;
34 }
31}35}
3236
33typedef unsigned int guint32;37typedef unsigned int guint32;
@@ -38,7 +42,7 @@
38 SP_BORDER_LAYER_TOP42 SP_BORDER_LAYER_TOP
39};43};
4044
41class SPNamedView : public SPObjectGroup {45class SPNamedView : public SPObjectGroup{
42public:46public:
43 SPNamedView();47 SPNamedView();
44 virtual ~SPNamedView();48 virtual ~SPNamedView();
@@ -54,6 +58,7 @@
54 double zoom;58 double zoom;
55 double cx;59 double cx;
56 double cy;60 double cy;
61 double document_rotation;
57 int window_width;62 int window_width;
58 int window_height;63 int window_height;
59 int window_x;64 int window_x;
@@ -66,7 +71,7 @@
6671
67 Inkscape::Util::Unit const *display_units; // Units used for the UI (*not* the same as units of SVG coordinates)72 Inkscape::Util::Unit const *display_units; // Units used for the UI (*not* the same as units of SVG coordinates)
68 Inkscape::Util::Unit const *page_size_units; // Only used in "Custom size" part of Document Properties dialog 73 Inkscape::Util::Unit const *page_size_units; // Only used in "Custom size" part of Document Properties dialog
69 74 Inkscape::Display::TemporaryItem *page_border_rotated;
70 GQuark default_layer_id;75 GQuark default_layer_id;
7176
72 double connector_spacing;77 double connector_spacing;
@@ -121,7 +126,7 @@
121void sp_namedview_window_from_document(SPDesktop *desktop);126void sp_namedview_window_from_document(SPDesktop *desktop);
122void sp_namedview_document_from_window(SPDesktop *desktop);127void sp_namedview_document_from_window(SPDesktop *desktop);
123void sp_namedview_update_layers_from_document (SPDesktop *desktop);128void sp_namedview_update_layers_from_document (SPDesktop *desktop);
124129void sp_namedview_set_document_rotation(SPNamedView *nv);
125void sp_namedview_toggle_guides(SPDocument *doc, Inkscape::XML::Node *repr);130void sp_namedview_toggle_guides(SPDocument *doc, Inkscape::XML::Node *repr);
126void sp_namedview_guides_toggle_lock(SPDocument *doc, Inkscape::XML::Node *repr);131void sp_namedview_guides_toggle_lock(SPDocument *doc, Inkscape::XML::Node *repr);
127void sp_namedview_show_grids(SPNamedView *namedview, bool show, bool dirty_document);132void sp_namedview_show_grids(SPNamedView *namedview, bool show, bool dirty_document);
128133
=== modified file 'src/ui/dialog/export.cpp'
--- src/ui/dialog/export.cpp 2017-01-04 23:08:02 +0000
+++ src/ui/dialog/export.cpp 2017-01-24 17:53:20 +0000
@@ -978,7 +978,9 @@
978978
979 SPNamedView *nv = desktop->getNamedView();979 SPNamedView *nv = desktop->getNamedView();
980 SPDocument *doc = desktop->getDocument();980 SPDocument *doc = desktop->getDocument();
981981 Geom::Affine rot = doc->getRoot()->c2p;
982 doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p;
983 doc->ensureUpToDate();
982 bool exportSuccessful = false;984 bool exportSuccessful = false;
983985
984 bool hide = hide_export.get_active ();986 bool hide = hide_export.get_active ();
@@ -1003,6 +1005,7 @@
10031005
1004 if (num < 1) {1006 if (num < 1) {
1005 desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("No items selected."));1007 desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("No items selected."));
1008 doc->getRoot()->c2p *= doc->getRoot()->rotation;
1006 return;1009 return;
1007 }1010 }
10081011
@@ -1094,6 +1097,7 @@
1094 if (filename.empty()) {1097 if (filename.empty()) {
1095 desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("You have to enter a filename."));1098 desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("You have to enter a filename."));
1096 sp_ui_error_dialog(_("You have to enter a filename"));1099 sp_ui_error_dialog(_("You have to enter a filename"));
1100 doc->getRoot()->c2p *= doc->getRoot()->rotation;
1097 return;1101 return;
1098 }1102 }
10991103
@@ -1110,6 +1114,7 @@
1110 if (!((x1 > x0) && (y1 > y0) && (width > 0) && (height > 0))) {1114 if (!((x1 > x0) && (y1 > y0) && (width > 0) && (height > 0))) {
1111 desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("The chosen area to be exported is invalid."));1115 desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("The chosen area to be exported is invalid."));
1112 sp_ui_error_dialog(_("The chosen area to be exported is invalid"));1116 sp_ui_error_dialog(_("The chosen area to be exported is invalid"));
1117 doc->getRoot()->c2p *= doc->getRoot()->rotation;
1113 return;1118 return;
1114 }1119 }
11151120
@@ -1132,6 +1137,7 @@
11321137
1133 g_free(safeDir);1138 g_free(safeDir);
1134 g_free(error);1139 g_free(error);
1140 doc->getRoot()->c2p *= doc->getRoot()->rotation;
1135 return;1141 return;
1136 }1142 }
11371143
@@ -1281,6 +1287,7 @@
1281 }1287 }
1282 }1288 }
1283 }1289 }
1290 doc->getRoot()->c2p *= doc->getRoot()->rotation;
1284} // end of sp_export_export_clicked()1291} // end of sp_export_export_clicked()
12851292
1286/// Called when Browse button is clicked1293/// Called when Browse button is clicked
12871294
=== modified file 'src/ui/tools/tool-base.cpp'
--- src/ui/tools/tool-base.cpp 2016-08-09 09:33:34 +0000
+++ src/ui/tools/tool-base.cpp 2017-01-24 17:53:20 +0000
@@ -94,6 +94,7 @@
94 , _grdrag(NULL)94 , _grdrag(NULL)
95 , shape_editor(NULL)95 , shape_editor(NULL)
96 , space_panning(false)96 , space_panning(false)
97 , rotating_mode(false)
97 , _delayed_snap_event(NULL)98 , _delayed_snap_event(NULL)
98 , _dse_callback_in_process(false)99 , _dse_callback_in_process(false)
99 , desktop(NULL)100 , desktop(NULL)
@@ -327,99 +328,130 @@
327 static unsigned int panning = 0;328 static unsigned int panning = 0;
328 static unsigned int panning_cursor = 0;329 static unsigned int panning_cursor = 0;
329 static unsigned int zoom_rb = 0;330 static unsigned int zoom_rb = 0;
331 static double angle = 0;
330332
331 Inkscape::Preferences *prefs = Inkscape::Preferences::get();333 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
332334
333 /// @todo REmove redundant /value in preference keys335 /// @todo REmove redundant /value in preference keys
334 tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100);336 tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100);
335 bool allow_panning = prefs->getBool("/options/spacebarpans/value");337 bool allow_panning = prefs->getBool("/options/spacebarpans/value");
338 int rotation_snap = 180.0/prefs->getInt("/options/rotationsnapsperpi/value", 12);
336 gint ret = FALSE;339 gint ret = FALSE;
337340
338 switch (event->type) {341 switch (event->type) {
339 case GDK_2BUTTON_PRESS:342 case GDK_2BUTTON_PRESS:
340 if (panning) {343 if (panning) {
341 panning = 0;344 panning = 0;
342 sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time);345 sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time);
343 ret = TRUE;346 ret = TRUE;
344 } else {347 } else {
345 /* sp_desktop_dialog(); */348 /* sp_desktop_dialog(); */
346 }349 }
347 break;350 break;
348351
349 case GDK_BUTTON_PRESS:352 case GDK_BUTTON_PRESS:
350 // save drag origin353 // save drag origin
351 xp = (gint) event->button.x;354 xp = (gint) event->button.x;
352 yp = (gint) event->button.y;355 yp = (gint) event->button.y;
353 within_tolerance = true;356 within_tolerance = true;
354357
355 button_w = Geom::Point(event->button.x, event->button.y);358 button_w = Geom::Point(event->button.x, event->button.y);
356359 switch (event->button.button) {
357 switch (event->button.button) {360 case 1:
358 case 1:361 if (this->space_panning) {
359 if (this->space_panning) {362 // When starting panning, make sure there are no snap events pending because these might disable the panning again
360 // When starting panning, make sure there are no snap events pending because these might disable the panning again363 if (_uses_snap) {
361 if (_uses_snap) {364 sp_event_context_discard_delayed_snap_event(this);
362 sp_event_context_discard_delayed_snap_event(this);365 }
363 }366 panning = 1;
364 panning = 1;367
365368 sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate),
366 sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate),369 GDK_KEY_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK
367 GDK_KEY_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK370 | GDK_POINTER_MOTION_MASK
368 | GDK_POINTER_MOTION_MASK371 | GDK_POINTER_MOTION_HINT_MASK, NULL,
369 | GDK_POINTER_MOTION_HINT_MASK, NULL,372 event->button.time - 1);
370 event->button.time - 1);373
371374 ret = TRUE;
372 ret = TRUE;375 }
373 }376 desktop->canvas->clearRotateTo();
374 break;377 this->rotating_mode = false;
375378 break;
376 case 2:379
377 if (event->button.state & GDK_SHIFT_MASK) {380 case 2:
378 zoom_rb = 2;381 if (event->button.state & GDK_CONTROL_MASK) {
379 } else {382 sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time);
380 // When starting panning, make sure there are no snap events pending because these might disable the panning again383 desktop->canvas->startRotateTo(desktop->namedview->document_rotation);
381 if (_uses_snap) {384 this->rotating_mode = true;
382 sp_event_context_discard_delayed_snap_event(this);385 this->message_context->set(Inkscape::INFORMATION_MESSAGE,
383 }386 _("<b>MMB + mouse move</b> to rotate canvas, use modifiers on screen to change snaps"));
384 panning = 2;387 } else {
385388 if (event->button.state & GDK_SHIFT_MASK) {
386 sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate),389 zoom_rb = 2;
387 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK390 } else {
388 | GDK_POINTER_MOTION_HINT_MASK, NULL,391 // When starting panning, make sure there are no snap events pending because these might disable the panning again
389 event->button.time - 1);392 if (_uses_snap) {
390393 sp_event_context_discard_delayed_snap_event(this);
391 }394 }
392395 panning = 2;
393 ret = TRUE;396
394 break;397 sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate),
395398 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK
396 case 3:399 | GDK_POINTER_MOTION_HINT_MASK, NULL,
397 if ((event->button.state & GDK_SHIFT_MASK) || (event->button.state & GDK_CONTROL_MASK)) {400 event->button.time - 1);
398 // When starting panning, make sure there are no snap events pending because these might disable the panning again401 }
399 if (_uses_snap) {402 ret = TRUE;
400 sp_event_context_discard_delayed_snap_event(this);403 }
401 }404 ret = TRUE;
402 panning = 3;405 break;
403406
404 sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate),407 case 3:
405 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK408 if ((event->button.state & GDK_SHIFT_MASK) || (event->button.state & GDK_CONTROL_MASK)) {
406 | GDK_POINTER_MOTION_HINT_MASK, NULL,409 // When starting panning, make sure there are no snap events pending because these might disable the panning again
407 event->button.time);410 if (_uses_snap) {
408411 sp_event_context_discard_delayed_snap_event(this);
409 ret = TRUE;412 }
410 } else {413 panning = 3;
411 sp_event_root_menu_popup(desktop, NULL, event);414
412 }415 sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate),
413 break;416 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK
414417 | GDK_POINTER_MOTION_HINT_MASK, NULL,
415 default:418 event->button.time);
416 break;419
417 }420 ret = TRUE;
418 break;421 } else if( !this->space_panning) {
419422 sp_event_root_menu_popup(desktop, NULL, event);
420 case GDK_MOTION_NOTIFY:423 }
421 if (panning) {424 ret = TRUE;
422 if (panning == 4 && !xp && !yp ) {425 desktop->canvas->clearRotateTo();
426 this->rotating_mode = false;
427 break;
428
429 default:
430 break;
431 }
432 break;
433
434 case GDK_MOTION_NOTIFY:
435 if (this->rotating_mode) {
436 button_w = Geom::Point(event->motion.x, event->motion.y);
437 Geom::Point const motion_dt(desktop->doc2dt(desktop->w2d(button_w)));
438 Geom::Rect view = desktop->get_display_area();
439 Geom::Point view_center = desktop->doc2dt(view.midpoint());
440 Geom::Ray center_ray(motion_dt, view_center);
441 angle = Geom::deg_from_rad(center_ray.angle()) - 90;
442 if (event->motion.state & GDK_SHIFT_MASK && event->motion.state & GDK_CONTROL_MASK) {
443 angle = 0;
444 } else if(event->motion.state & GDK_CONTROL_MASK) {
445 angle = floor(angle/rotation_snap) * rotation_snap;
446 } else if (event->motion.state & GDK_SHIFT_MASK) {
447 angle = desktop->namedview->document_rotation;
448 } else if (event->motion.state & GDK_MOD1_MASK) {
449 //Decimal raw angle
450 } else {
451 angle = floor(angle);
452 }
453 desktop->canvas->rotateTo(angle);
454 } else if (panning == 4 && !xp && !yp ) {
423 // <Space> + mouse panning started, save location and grab canvas455 // <Space> + mouse panning started, save location and grab canvas
424 xp = event->motion.x;456 xp = event->motion.x;
425 yp = event->motion.y;457 yp = event->motion.y;
@@ -431,401 +463,465 @@
431 | GDK_POINTER_MOTION_HINT_MASK, NULL,463 | GDK_POINTER_MOTION_HINT_MASK, NULL,
432 event->motion.time - 1);464 event->motion.time - 1);
433 }465 }
434466 if (panning && !this->rotating_mode) {
435 if ((panning == 2 && !(event->motion.state & GDK_BUTTON2_MASK))467 if ((panning == 2 && !(event->motion.state & GDK_BUTTON2_MASK))
436 || (panning == 1 && !(event->motion.state & GDK_BUTTON1_MASK))468 || (panning == 1 && !(event->motion.state & GDK_BUTTON1_MASK))
437 || (panning == 3 && !(event->motion.state & GDK_BUTTON3_MASK))) {469 || (panning == 3 && !(event->motion.state & GDK_BUTTON3_MASK))) {
438 /* Gdk seems to lose button release for us sometimes :-( */470 /* Gdk seems to lose button release for us sometimes :-( */
439 panning = 0;471 panning = 0;
440 sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time);472 sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time);
441 ret = TRUE;473 ret = TRUE;
442 } else {474 } else {
475 if (within_tolerance && (abs((gint) event->motion.x - xp)
476 < tolerance) && (abs((gint) event->motion.y - yp)
477 < tolerance)) {
478 // do not drag if we're within tolerance from origin
479 break;
480 }
481
482 // Once the user has moved farther than tolerance from
483 // the original location (indicating they intend to move
484 // the object, not click), then always process the motion
485 // notify coordinates as given (no snapping back to origin)
486 within_tolerance = false;
487
488 // gobble subsequent motion events to prevent "sticking"
489 // when scrolling is slow
490 gobble_motion_events(panning == 2 ? GDK_BUTTON2_MASK : (panning
491 == 1 ? GDK_BUTTON1_MASK : GDK_BUTTON3_MASK));
492
493 if (panning_cursor == 0) {
494 panning_cursor = 1;
495 this->sp_event_context_set_cursor(GDK_FLEUR);
496 }
497
498 Geom::Point const motion_w(event->motion.x, event->motion.y);
499 Geom::Point const moved_w(motion_w - button_w);
500 this->desktop->scroll_world(moved_w, true); // we're still scrolling, do not redraw
501 ret = TRUE;
502 }
503 } else if (zoom_rb) {
504 Geom::Point const motion_w(event->motion.x, event->motion.y);
505 Geom::Point const motion_dt(desktop->w2d(motion_w));
506
443 if (within_tolerance && (abs((gint) event->motion.x - xp)507 if (within_tolerance && (abs((gint) event->motion.x - xp)
444 < tolerance) && (abs((gint) event->motion.y - yp)508 < tolerance) && (abs((gint) event->motion.y - yp)
445 < tolerance)) {509 < tolerance)) {
446 // do not drag if we're within tolerance from origin510 break; // do not drag if we're within tolerance from origin
447 break;
448 }511 }
449512
450 // Once the user has moved farther than tolerance from513 // Once the user has moved farther than tolerance from the original location
451 // the original location (indicating they intend to move514 // (indicating they intend to move the object, not click), then always process the
452 // the object, not click), then always process the motion515 // motion notify coordinates as given (no snapping back to origin)
453 // notify coordinates as given (no snapping back to origin)
454 within_tolerance = false;516 within_tolerance = false;
455517
456 // gobble subsequent motion events to prevent "sticking"518 if (Inkscape::Rubberband::get(desktop)->is_started()) {
457 // when scrolling is slow519 Inkscape::Rubberband::get(desktop)->move(motion_dt);
458 gobble_motion_events(panning == 2 ? GDK_BUTTON2_MASK : (panning520 } else {
459 == 1 ? GDK_BUTTON1_MASK : GDK_BUTTON3_MASK));521 Inkscape::Rubberband::get(desktop)->start(desktop, motion_dt);
460522 }
461 if (panning_cursor == 0) {523
462 panning_cursor = 1;524 if (zoom_rb == 2) {
463 this->sp_event_context_set_cursor(GDK_FLEUR);525 gobble_motion_events(GDK_BUTTON2_MASK);
464 }526 }
465527 }
466 Geom::Point const motion_w(event->motion.x, event->motion.y);528 break;
467 Geom::Point const moved_w(motion_w - button_w);529
468 this->desktop->scroll_world(moved_w, true); // we're still scrolling, do not redraw530 case GDK_BUTTON_RELEASE:
531 if (this->rotating_mode && event->button.button == 2) {
532 desktop->canvas->clearRotateTo();
533 this->rotating_mode = false;
469 ret = TRUE;534 ret = TRUE;
470 }535 if (desktop->canvas->endRotateTo()) {
471 } else if (zoom_rb) {536 sp_repr_set_svg_double(desktop->namedview->getRepr(), "inkscape:document-rotation", angle);
472 Geom::Point const motion_w(event->motion.x, event->motion.y);537 }
473 Geom::Point const motion_dt(desktop->w2d(motion_w));
474
475 if (within_tolerance && (abs((gint) event->motion.x - xp)
476 < tolerance) && (abs((gint) event->motion.y - yp)
477 < tolerance)) {
478 break; // do not drag if we're within tolerance from origin
479 }
480
481 // Once the user has moved farther than tolerance from the original location
482 // (indicating they intend to move the object, not click), then always process the
483 // motion notify coordinates as given (no snapping back to origin)
484 within_tolerance = false;
485
486 if (Inkscape::Rubberband::get(desktop)->is_started()) {
487 Inkscape::Rubberband::get(desktop)->move(motion_dt);
488 } else {538 } else {
489 Inkscape::Rubberband::get(desktop)->start(desktop, motion_dt);539 xp = yp = 0;
490 }540 if (panning_cursor == 1) {
491541 panning_cursor = 0;
492 if (zoom_rb == 2) {542 GtkWidget *w = GTK_WIDGET(this->desktop->getCanvas());
493 gobble_motion_events(GDK_BUTTON2_MASK);543 gdk_window_set_cursor(gtk_widget_get_window (w), this->cursor);
494 }544 }
495 }545
496 break;546 if (within_tolerance && (panning || zoom_rb)) {
497547 zoom_rb = 0;
498 case GDK_BUTTON_RELEASE:548
499 xp = yp = 0;549 if (panning) {
500550 panning = 0;
501 if (panning_cursor == 1) {551 sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate),
502 panning_cursor = 0;552 event->button.time);
503 GtkWidget *w = GTK_WIDGET(this->desktop->getCanvas());553 }
504 gdk_window_set_cursor(gtk_widget_get_window (w), this->cursor);554
505 }555 Geom::Point const event_w(event->button.x, event->button.y);
506556 Geom::Point const event_dt(desktop->w2d(event_w));
507 if (within_tolerance && (panning || zoom_rb)) {557
508 zoom_rb = 0;558 double const zoom_inc = prefs->getDoubleLimited(
559 "/options/zoomincrement/value", M_SQRT2, 1.01, 10);
560
561 desktop->zoom_relative_keep_point(event_dt, (event->button.state
562 & GDK_SHIFT_MASK) ? 1 / zoom_inc : zoom_inc);
563
564 desktop->updateNow();
565 ret = TRUE;
566 } else if (panning == event->button.button) {
567 panning = 0;
568 sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate),
569 event->button.time);
570
571 // in slow complex drawings, some of the motion events are lost;
572 // to make up for this, we scroll it once again to the button-up event coordinates
573 // (i.e. canvas will always get scrolled all the way to the mouse release point,
574 // even if few intermediate steps were visible)
575 Geom::Point const motion_w(event->button.x, event->button.y);
576 Geom::Point const moved_w(motion_w - button_w);
577
578 this->desktop->scroll_world(moved_w);
579 desktop->updateNow();
580 ret = TRUE;
581 } else if (zoom_rb == event->button.button) {
582 zoom_rb = 0;
583
584 Geom::OptRect const b = Inkscape::Rubberband::get(desktop)->getRectangle();
585 Inkscape::Rubberband::get(desktop)->stop();
586
587 if (b && !within_tolerance) {
588 desktop->set_display_area(*b, 10);
589 }
590
591 ret = TRUE;
592 }
593 if (this->rotating_mode && event->button.button != 3) {
594 desktop->canvas->clearRotateTo();
595 this->rotating_mode = false;
596 ret = TRUE;
597 desktop->canvas->endRotateTo();
598 }
599 }
600 break;
601
602 case GDK_KEY_PRESS: {
603 double const acceleration = prefs->getDoubleLimited(
604 "/options/scrollingacceleration/value", 0, 0, 6);
605 int const key_scroll = prefs->getIntLimited("/options/keyscroll/value",
606 10, 0, 1000);
607
608 if (this->rotating_mode &&
609 get_group0_keyval(&event->key) != GDK_KEY_space &&
610 get_group0_keyval(&event->key) != GDK_KEY_Shift_L &&
611 get_group0_keyval(&event->key) != GDK_KEY_Shift_R &&
612 get_group0_keyval(&event->key) != GDK_KEY_Control_L &&
613 get_group0_keyval(&event->key) != GDK_KEY_Control_R &&
614 get_group0_keyval(&event->key) != GDK_KEY_Alt_L &&
615 get_group0_keyval(&event->key) != GDK_KEY_Alt_R )
616 {
617 desktop->canvas->clearRotateTo();
618 this->rotating_mode = false;
619 ret = TRUE;
620 desktop->canvas->endRotateTo();
621 break;
622 }
623
624 switch (get_group0_keyval(&event->key)) {
625 // GDK insists on stealing these keys (F1 for no idea what, tab for cycling widgets
626 // in the editing window). So we resteal them back and run our regular shortcut
627 // invoker on them.
628 unsigned int shortcut;
629 case GDK_KEY_Tab:
630 case GDK_KEY_ISO_Left_Tab:
631 case GDK_KEY_F1:
632 shortcut = get_group0_keyval(&event->key);
633
634 if (event->key.state & GDK_SHIFT_MASK) {
635 shortcut |= SP_SHORTCUT_SHIFT_MASK;
636 }
637
638 if (event->key.state & GDK_CONTROL_MASK) {
639 shortcut |= SP_SHORTCUT_CONTROL_MASK;
640 }
641
642 if (event->key.state & GDK_MOD1_MASK) {
643 shortcut |= SP_SHORTCUT_ALT_MASK;
644 }
645
646 ret = sp_shortcut_invoke(shortcut, desktop);
647 break;
648
649 case GDK_KEY_Q:
650 case GDK_KEY_q:
651 if (desktop->quick_zoomed()) {
652 ret = TRUE;
653 }
654 if (!MOD__SHIFT(event) && !MOD__CTRL(event) && !MOD__ALT(event)) {
655 desktop->zoom_quick(true);
656 ret = TRUE;
657 }
658 break;
659
660 case GDK_KEY_W:
661 case GDK_KEY_w:
662 case GDK_KEY_F4:
663 /* Close view */
664 if (MOD__CTRL_ONLY(event)) {
665 sp_ui_close_view(NULL);
666 ret = TRUE;
667 }
668 break;
669
670 case GDK_KEY_Left: // Ctrl Left
671 case GDK_KEY_KP_Left:
672 case GDK_KEY_KP_4:
673 if (MOD__CTRL_ONLY(event)) {
674 int i = (int) floor(key_scroll * accelerate_scroll(event,
675 acceleration, desktop->getCanvas()));
676
677 gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK);
678 this->desktop->scroll_world(i, 0);
679 ret = TRUE;
680 }
681 break;
682
683 case GDK_KEY_Up: // Ctrl Up
684 case GDK_KEY_KP_Up:
685 case GDK_KEY_KP_8:
686 if (MOD__CTRL_ONLY(event)) {
687 int i = (int) floor(key_scroll * accelerate_scroll(event,
688 acceleration, desktop->getCanvas()));
689
690 gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK);
691 this->desktop->scroll_world(0, i);
692 ret = TRUE;
693 }
694 break;
695
696 case GDK_KEY_Right: // Ctrl Right
697 case GDK_KEY_KP_Right:
698 case GDK_KEY_KP_6:
699 if (MOD__CTRL_ONLY(event)) {
700 int i = (int) floor(key_scroll * accelerate_scroll(event,
701 acceleration, desktop->getCanvas()));
702
703 gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK);
704 this->desktop->scroll_world(-i, 0);
705 ret = TRUE;
706 }
707 break;
708
709 case GDK_KEY_Down: // Ctrl Down
710 case GDK_KEY_KP_Down:
711 case GDK_KEY_KP_2:
712 if (MOD__CTRL_ONLY(event)) {
713 int i = (int) floor(key_scroll * accelerate_scroll(event,
714 acceleration, desktop->getCanvas()));
715
716 gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK);
717 this->desktop->scroll_world(0, -i);
718 ret = TRUE;
719 }
720 break;
721
722 case GDK_KEY_Menu:
723 sp_event_root_menu_popup(desktop, NULL, event);
724 ret = TRUE;
725 break;
726
727 case GDK_KEY_F10:
728 if (MOD__SHIFT_ONLY(event)) {
729 sp_event_root_menu_popup(desktop, NULL, event);
730 ret = TRUE;
731 }
732 break;
733
734 case GDK_KEY_space:
735 if (event->key.state & GDK_CONTROL_MASK) {
736 sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time);
737 desktop->canvas->startRotateTo(desktop->namedview->document_rotation);
738 this->rotating_mode = true;
739 this->message_context->set(Inkscape::INFORMATION_MESSAGE,
740 _("<b>Space+mouse move</b> to rotate canvas, use modifiers on screen to change snaps"));
741 } else {
742 within_tolerance = true;
743 xp = yp = 0;
744 if (!allow_panning) break;
745 panning = 4;
746 this->space_panning = true;
747 this->message_context->set(Inkscape::INFORMATION_MESSAGE,
748 _("<b>Space+mouse move</b> to pan canvas"));
749 }
750 ret = TRUE;
751 break;
752
753 case GDK_KEY_z:
754 case GDK_KEY_Z:
755 if (MOD__ALT_ONLY(event)) {
756 desktop->zoom_grab_focus();
757 ret = TRUE;
758 }
759 break;
760
761 default:
762 break;
763 }
764 }
765 break;
766
767 case GDK_KEY_RELEASE:
768 if (this->rotating_mode &&
769 get_group0_keyval(&event->key) != GDK_KEY_space &&
770 get_group0_keyval(&event->key) != GDK_KEY_Shift_L &&
771 get_group0_keyval(&event->key) != GDK_KEY_Shift_R &&
772 get_group0_keyval(&event->key) != GDK_KEY_Control_L &&
773 get_group0_keyval(&event->key) != GDK_KEY_Control_R &&
774 get_group0_keyval(&event->key) != GDK_KEY_Alt_L &&
775 get_group0_keyval(&event->key) != GDK_KEY_Alt_R )
776 {
777 desktop->canvas->clearRotateTo();
778 this->rotating_mode = false;
779 ret = TRUE;
780 desktop->canvas->endRotateTo();
781 break;
782 }
783
784 // Stop panning on any key release
785 if (this->space_panning) {
786 this->space_panning = false;
787 this->message_context->clear();
788 }
509789
510 if (panning) {790 if (panning) {
511 panning = 0;791 panning = 0;
792 xp = yp = 0;
793
512 sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate),794 sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate),
513 event->button.time);795 event->key.time);
514 }796
515797 desktop->updateNow();
516 Geom::Point const event_w(event->button.x, event->button.y);798 }
517 Geom::Point const event_dt(desktop->w2d(event_w));799
518800 if (panning_cursor == 1) {
519 double const zoom_inc = prefs->getDoubleLimited(801 panning_cursor = 0;
520 "/options/zoomincrement/value", M_SQRT2, 1.01, 10);802 GtkWidget *w = GTK_WIDGET(this->desktop->getCanvas());
521803 gdk_window_set_cursor(gtk_widget_get_window (w), this->cursor);
522 desktop->zoom_relative_keep_point(event_dt, (event->button.state804 }
523 & GDK_SHIFT_MASK) ? 1 / zoom_inc : zoom_inc);805
524806 switch (get_group0_keyval(&event->key)) {
525 desktop->updateNow();807 case GDK_KEY_space:
526 ret = TRUE;808 if (this->rotating_mode) {
527 } else if (panning == event->button.button) {809 desktop->canvas->clearRotateTo();
528 panning = 0;810 this->rotating_mode = false;
529 sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate),811 ret = TRUE;
530 event->button.time);812 if (desktop->canvas->endRotateTo()) {
531813 sp_repr_set_svg_double(desktop->namedview->getRepr(), "inkscape:document-rotation", angle);
532 // in slow complex drawings, some of the motion events are lost;814 }
533 // to make up for this, we scroll it once again to the button-up event coordinates815 }
534 // (i.e. canvas will always get scrolled all the way to the mouse release point,816 if (within_tolerance) {
535 // even if few intermediate steps were visible)817 // Space was pressed, but not panned
536 Geom::Point const motion_w(event->button.x, event->button.y);818 sp_toggle_selector(desktop);
537 Geom::Point const moved_w(motion_w - button_w);819
538820 // Be careful, sp_toggle_selector will delete ourselves.
539 this->desktop->scroll_world(moved_w);821 // Thus, make sure we return immediately.
540 desktop->updateNow();822 return true;
541 ret = TRUE;823 }
542 } else if (zoom_rb == event->button.button) {824 break;
543 zoom_rb = 0;825
544826 case GDK_KEY_Q:
545 Geom::OptRect const b = Inkscape::Rubberband::get(desktop)->getRectangle();827 case GDK_KEY_q:
546 Inkscape::Rubberband::get(desktop)->stop();828 if (desktop->quick_zoomed()) {
547829 desktop->zoom_quick(false);
548 if (b && !within_tolerance) {830 ret = TRUE;
549 desktop->set_display_area(*b, 10);831 }
550 }832 break;
551833
552 ret = TRUE;834 default:
553 }835 break;
554 break;836 }
555837 break;
556 case GDK_KEY_PRESS: {838
557 double const acceleration = prefs->getDoubleLimited(839 case GDK_SCROLL: {
558 "/options/scrollingacceleration/value", 0, 0, 6);840 if (this->rotating_mode) {
559 int const key_scroll = prefs->getIntLimited("/options/keyscroll/value",841 desktop->canvas->clearRotateTo();
560 10, 0, 1000);842 this->rotating_mode = false;
561843 desktop->canvas->endRotateTo();
562 switch (get_group0_keyval(&event->key)) {844 }
563 // GDK insists on stealing these keys (F1 for no idea what, tab for cycling widgets845 bool ctrl = (event->scroll.state & GDK_CONTROL_MASK);
564 // in the editing window). So we resteal them back and run our regular shortcut846 bool wheelzooms = prefs->getBool("/options/wheelzooms/value");
565 // invoker on them.847
566 unsigned int shortcut;848 int const wheel_scroll = prefs->getIntLimited(
567 case GDK_KEY_Tab:849 "/options/wheelscroll/value", 40, 0, 1000);
568 case GDK_KEY_ISO_Left_Tab:850
569 case GDK_KEY_F1:851 // Size of smooth-scrolls (only used in GTK+ 3)
570 shortcut = get_group0_keyval(&event->key);852 gdouble delta_x = 0;
571853 gdouble delta_y = 0;
572 if (event->key.state & GDK_SHIFT_MASK) {854
573 shortcut |= SP_SHORTCUT_SHIFT_MASK;855 /* shift + wheel, pan left--right */
574 }856 if (event->scroll.state & GDK_SHIFT_MASK) {
575857 switch (event->scroll.direction) {
576 if (event->key.state & GDK_CONTROL_MASK) {858 case GDK_SCROLL_UP:
577 shortcut |= SP_SHORTCUT_CONTROL_MASK;859 desktop->scroll_world(wheel_scroll, 0);
578 }860 break;
579861
580 if (event->key.state & GDK_MOD1_MASK) {862 case GDK_SCROLL_DOWN:
581 shortcut |= SP_SHORTCUT_ALT_MASK;863 desktop->scroll_world(-wheel_scroll, 0);
582 }864 break;
583865
584 ret = sp_shortcut_invoke(shortcut, desktop);866 default:
585 break;867 break;
586868 }
587 case GDK_KEY_Q:869
588 case GDK_KEY_q:870 /* ctrl + wheel, zoom in--out */
589 if (desktop->quick_zoomed()) {871 } else if ((ctrl && !wheelzooms) || (!ctrl && wheelzooms)) {
590 ret = TRUE;872 double rel_zoom;
591 }873 double const zoom_inc = prefs->getDoubleLimited(
592 if (!MOD__SHIFT(event) && !MOD__CTRL(event) && !MOD__ALT(event)) {874 "/options/zoomincrement/value", M_SQRT2, 1.01, 10);
593 desktop->zoom_quick(true);875
594 ret = TRUE;876 switch (event->scroll.direction) {
595 }877 case GDK_SCROLL_UP:
596 break;878 rel_zoom = zoom_inc;
597879 break;
598 case GDK_KEY_W:880
599 case GDK_KEY_w:881 case GDK_SCROLL_DOWN:
600 case GDK_KEY_F4:882 rel_zoom = 1 / zoom_inc;
601 /* Close view */883 break;
602 if (MOD__CTRL_ONLY(event)) {884
603 sp_ui_close_view(NULL);885 default:
604 ret = TRUE;886 rel_zoom = 0.0;
605 }887 break;
606 break;888 }
607889
608 case GDK_KEY_Left: // Ctrl Left890 if (rel_zoom != 0.0) {
609 case GDK_KEY_KP_Left:891 Geom::Point const scroll_dt = desktop->point();
610 case GDK_KEY_KP_4:892 desktop->zoom_relative_keep_point(scroll_dt, rel_zoom);
611 if (MOD__CTRL_ONLY(event)) {893 }
612 int i = (int) floor(key_scroll * accelerate_scroll(event,894
613 acceleration, desktop->getCanvas()));895 /* no modifier, pan up--down (left--right on multiwheel mice?) */
614896 } else {
615 gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK);897 switch (event->scroll.direction) {
616 this->desktop->scroll_world(i, 0);898 case GDK_SCROLL_UP:
617 ret = TRUE;899 desktop->scroll_world(0, wheel_scroll);
618 }900 break;
619 break;901
620902 case GDK_SCROLL_DOWN:
621 case GDK_KEY_Up: // Ctrl Up903 desktop->scroll_world(0, -wheel_scroll);
622 case GDK_KEY_KP_Up:904 break;
623 case GDK_KEY_KP_8:905
624 if (MOD__CTRL_ONLY(event)) {906 case GDK_SCROLL_LEFT:
625 int i = (int) floor(key_scroll * accelerate_scroll(event,907 desktop->scroll_world(wheel_scroll, 0);
626 acceleration, desktop->getCanvas()));908 break;
627909
628 gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK);910 case GDK_SCROLL_RIGHT:
629 this->desktop->scroll_world(0, i);911 desktop->scroll_world(-wheel_scroll, 0);
630 ret = TRUE;912 break;
631 }913
632 break;914 case GDK_SCROLL_SMOOTH:
633915 gdk_event_get_scroll_deltas(event, &delta_x, &delta_y);
634 case GDK_KEY_Right: // Ctrl Right916 desktop->scroll_world(delta_x, delta_y);
635 case GDK_KEY_KP_Right:917 break;
636 case GDK_KEY_KP_6:918 }
637 if (MOD__CTRL_ONLY(event)) {919 }
638 int i = (int) floor(key_scroll * accelerate_scroll(event,920 break;
639 acceleration, desktop->getCanvas()));921 }
640922 default:
641 gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK);923 break;
642 this->desktop->scroll_world(-i, 0);924 }
643 ret = TRUE;
644 }
645 break;
646
647 case GDK_KEY_Down: // Ctrl Down
648 case GDK_KEY_KP_Down:
649 case GDK_KEY_KP_2:
650 if (MOD__CTRL_ONLY(event)) {
651 int i = (int) floor(key_scroll * accelerate_scroll(event,
652 acceleration, desktop->getCanvas()));
653
654 gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK);
655 this->desktop->scroll_world(0, -i);
656 ret = TRUE;
657 }
658 break;
659
660 case GDK_KEY_Menu:
661 sp_event_root_menu_popup(desktop, NULL, event);
662 ret = TRUE;
663 break;
664
665 case GDK_KEY_F10:
666 if (MOD__SHIFT_ONLY(event)) {
667 sp_event_root_menu_popup(desktop, NULL, event);
668 ret = TRUE;
669 }
670 break;
671
672 case GDK_KEY_space:
673 within_tolerance = true;
674 xp = yp = 0;
675 if (!allow_panning) break;
676 panning = 4;
677 this->space_panning = true;
678 this->message_context->set(Inkscape::INFORMATION_MESSAGE,
679 _("<b>Space+mouse move</b> to pan canvas"));
680
681 ret = TRUE;
682 break;
683
684 case GDK_KEY_z:
685 case GDK_KEY_Z:
686 if (MOD__ALT_ONLY(event)) {
687 desktop->zoom_grab_focus();
688 ret = TRUE;
689 }
690 break;
691
692 default:
693 break;
694 }
695 }
696 break;
697
698 case GDK_KEY_RELEASE:
699 // Stop panning on any key release
700 if (this->space_panning) {
701 this->space_panning = false;
702 this->message_context->clear();
703 }
704
705 if (panning) {
706 panning = 0;
707 xp = yp = 0;
708
709 sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate),
710 event->key.time);
711
712 desktop->updateNow();
713 }
714
715 if (panning_cursor == 1) {
716 panning_cursor = 0;
717 GtkWidget *w = GTK_WIDGET(this->desktop->getCanvas());
718 gdk_window_set_cursor(gtk_widget_get_window (w), this->cursor);
719 }
720
721 switch (get_group0_keyval(&event->key)) {
722 case GDK_KEY_space:
723 if (within_tolerance) {
724 // Space was pressed, but not panned
725 sp_toggle_selector(desktop);
726
727 // Be careful, sp_toggle_selector will delete ourselves.
728 // Thus, make sure we return immediately.
729 return true;
730 }
731
732 break;
733
734 case GDK_KEY_Q:
735 case GDK_KEY_q:
736 if (desktop->quick_zoomed()) {
737 desktop->zoom_quick(false);
738 ret = TRUE;
739 }
740 break;
741
742 default:
743 break;
744 }
745 break;
746
747 case GDK_SCROLL: {
748 bool ctrl = (event->scroll.state & GDK_CONTROL_MASK);
749 bool wheelzooms = prefs->getBool("/options/wheelzooms/value");
750
751 int const wheel_scroll = prefs->getIntLimited(
752 "/options/wheelscroll/value", 40, 0, 1000);
753
754 // Size of smooth-scrolls (only used in GTK+ 3)
755 gdouble delta_x = 0;
756 gdouble delta_y = 0;
757
758 /* shift + wheel, pan left--right */
759 if (event->scroll.state & GDK_SHIFT_MASK) {
760 switch (event->scroll.direction) {
761 case GDK_SCROLL_UP:
762 desktop->scroll_world(wheel_scroll, 0);
763 break;
764
765 case GDK_SCROLL_DOWN:
766 desktop->scroll_world(-wheel_scroll, 0);
767 break;
768
769 default:
770 break;
771 }
772
773 /* ctrl + wheel, zoom in--out */
774 } else if ((ctrl && !wheelzooms) || (!ctrl && wheelzooms)) {
775 double rel_zoom;
776 double const zoom_inc = prefs->getDoubleLimited(
777 "/options/zoomincrement/value", M_SQRT2, 1.01, 10);
778
779 switch (event->scroll.direction) {
780 case GDK_SCROLL_UP:
781 rel_zoom = zoom_inc;
782 break;
783
784 case GDK_SCROLL_DOWN:
785 rel_zoom = 1 / zoom_inc;
786 break;
787
788 default:
789 rel_zoom = 0.0;
790 break;
791 }
792
793 if (rel_zoom != 0.0) {
794 Geom::Point const scroll_dt = desktop->point();
795 desktop->zoom_relative_keep_point(scroll_dt, rel_zoom);
796 }
797
798 /* no modifier, pan up--down (left--right on multiwheel mice?) */
799 } else {
800 switch (event->scroll.direction) {
801 case GDK_SCROLL_UP:
802 desktop->scroll_world(0, wheel_scroll);
803 break;
804
805 case GDK_SCROLL_DOWN:
806 desktop->scroll_world(0, -wheel_scroll);
807 break;
808
809 case GDK_SCROLL_LEFT:
810 desktop->scroll_world(wheel_scroll, 0);
811 break;
812
813 case GDK_SCROLL_RIGHT:
814 desktop->scroll_world(-wheel_scroll, 0);
815 break;
816
817 case GDK_SCROLL_SMOOTH:
818 gdk_event_get_scroll_deltas(event, &delta_x, &delta_y);
819 desktop->scroll_world(delta_x, delta_y);
820 break;
821 }
822 }
823 break;
824 }
825 default:
826 break;
827 }
828
829 return ret;925 return ret;
830}926}
831927
832928
=== modified file 'src/ui/tools/tool-base.h'
--- src/ui/tools/tool-base.h 2015-07-24 19:38:06 +0000
+++ src/ui/tools/tool-base.h 2017-01-24 17:53:20 +0000
@@ -176,6 +176,7 @@
176 ShapeEditor* shape_editor;176 ShapeEditor* shape_editor;
177177
178 bool space_panning;178 bool space_panning;
179 bool rotating_mode;
179180
180 DelayedSnapEvent *_delayed_snap_event;181 DelayedSnapEvent *_delayed_snap_event;
181 bool _dse_callback_in_process;182 bool _dse_callback_in_process;
182183
=== modified file 'src/viewbox.cpp'
--- src/viewbox.cpp 2016-08-03 13:29:38 +0000
+++ src/viewbox.cpp 2017-01-24 17:53:20 +0000
@@ -17,6 +17,8 @@
17#include "viewbox.h"17#include "viewbox.h"
18#include "enums.h"18#include "enums.h"
19#include "sp-item.h"19#include "sp-item.h"
20#include "inkscape.h"
21#include "desktop.h"
2022
21SPViewBox::SPViewBox()23SPViewBox::SPViewBox()
22 : viewBox_set(false)24 : viewBox_set(false)
@@ -25,6 +27,11 @@
25 , aspect_align(SP_ASPECT_XMID_YMID) // Default per spec27 , aspect_align(SP_ASPECT_XMID_YMID) // Default per spec
26 , aspect_clip(SP_ASPECT_MEET)28 , aspect_clip(SP_ASPECT_MEET)
27 , c2p(Geom::identity())29 , c2p(Geom::identity())
30 , vbt(Geom::identity())
31 , rotation(Geom::identity())
32 , angle(0)
33 , previous_angle(0)
34 , rotated(false)
28{35{
29}36}
3037
@@ -159,6 +166,16 @@
159 }166 }
160}167}
161168
169double SPViewBox::get_rotation() {
170 return this->angle;
171}
172
173void SPViewBox::set_rotation(double angle_val) {
174 this->previous_angle = this->angle;
175 this->angle = angle_val;
176 this->rotated = true;
177}
178
162// Apply scaling from viewbox179// Apply scaling from viewbox
163void SPViewBox::apply_viewbox(const Geom::Rect& in, double scale_none) {180void SPViewBox::apply_viewbox(const Geom::Rect& in, double scale_none) {
164181
@@ -222,22 +239,41 @@
222 break;239 break;
223 }240 }
224 }241 }
225
226 /* Viewbox transform from scale and position */242 /* Viewbox transform from scale and position */
227 Geom::Affine q;243 vbt = Geom::identity();
228 q[0] = scale_x;244 vbt[0] = scale_x;
229 q[1] = 0.0;245 vbt[1] = 0.0;
230 q[2] = 0.0;246 vbt[2] = 0.0;
231 q[3] = scale_y;247 vbt[3] = scale_y;
232 q[4] = x - scale_x * this->viewBox.left();248 vbt[4] = x - scale_x * this->viewBox.left();
233 q[5] = y - scale_y * this->viewBox.top();249 vbt[5] = y - scale_y * this->viewBox.top();
234250 /* Append viewbox and turn transformation */
235 // std::cout << " q\n" << q << std::endl;251 Geom::Point page_center = this->viewBox.midpoint();
236252 SPDesktop * desktop = SP_ACTIVE_DESKTOP;
237 /* Append viewbox transformation */253 if (this->angle > 0.0 || this->angle < 0.0 ) { //!0
238 this->c2p = q * this->c2p;254 if (desktop) {
255 rotation = Geom::Translate(page_center).inverse() * Geom::Rotate(Geom::rad_from_deg(angle)) * Geom::Translate(page_center);
256 this->c2p = rotation * vbt * this->c2p;
257 } else {
258 this->c2p = vbt * this->c2p;
259 }
260 } else {
261 this->c2p = vbt * this->c2p;
262 }
263 if (desktop && this->rotated) {
264 Geom::Rect view = desktop->get_display_area();
265 Geom::Point view_center = desktop->doc2dt(view.midpoint());
266 Geom::Affine center_rotation = Geom::identity();
267 center_rotation *= Geom::Translate(page_center * vbt).inverse();
268 center_rotation *= Geom::Rotate(Geom::rad_from_deg(this->angle - this->previous_angle));
269 center_rotation *= Geom::Translate(page_center * vbt);
270 view_center = desktop->dt2doc(view_center * center_rotation);
271 desktop->zoom_relative(view_center[Geom::X], view_center[Geom::Y], 1.0);
272 this->rotated = false;
273 }
239}274}
240275
276
241SPItemCtx SPViewBox::get_rctx(const SPItemCtx* ictx, double scale_none) {277SPItemCtx SPViewBox::get_rctx(const SPItemCtx* ictx, double scale_none) {
242278
243 /* Create copy of item context */279 /* Create copy of item context */
244280
=== modified file 'src/viewbox.h'
--- src/viewbox.h 2015-02-12 16:17:54 +0000
+++ src/viewbox.h 2017-01-24 17:53:20 +0000
@@ -36,7 +36,14 @@
3636
37 /* Child to parent additional transform */37 /* Child to parent additional transform */
38 Geom::Affine c2p;38 Geom::Affine c2p;
39 Geom::Affine vbt;
40 Geom::Affine rotation;
41 double angle;
42 double previous_angle;
43 bool rotated;
3944
45 double get_rotation();
46 void set_rotation(double angle_val);
40 void set_viewBox(const gchar* value);47 void set_viewBox(const gchar* value);
41 void set_preserveAspectRatio(const gchar* value);48 void set_preserveAspectRatio(const gchar* value);
4249
4350
=== modified file 'src/widgets/desktop-widget.cpp'
--- src/widgets/desktop-widget.cpp 2016-11-11 20:04:49 +0000
+++ src/widgets/desktop-widget.cpp 2017-01-24 17:53:20 +0000
@@ -54,7 +54,7 @@
54#include "ui/uxmanager.h"54#include "ui/uxmanager.h"
55#include "util/ege-appear-time-tracker.h"55#include "util/ege-appear-time-tracker.h"
56#include "sp-root.h"56#include "sp-root.h"
5757#include "attributes.h"
58// We're in the "widgets" directory, so no need to explicitly prefix these:58// We're in the "widgets" directory, so no need to explicitly prefix these:
59#include "button.h"59#include "button.h"
60#include "gimp/ruler.h"60#include "gimp/ruler.h"
@@ -62,11 +62,11 @@
62#include "spw-utilities.h"62#include "spw-utilities.h"
63#include "toolbox.h"63#include "toolbox.h"
64#include "widget-sizes.h"64#include "widget-sizes.h"
65
66#include "verbs.h"65#include "verbs.h"
67#include <gtkmm/cssprovider.h>66#include <gtkmm/cssprovider.h>
68#include <gtkmm/paned.h>67#include <gtkmm/paned.h>
69#include <gtkmm/messagedialog.h>68#include <gtkmm/messagedialog.h>
69#include <iomanip>
7070
71#if defined (SOLARIS) && (SOLARIS == 8)71#if defined (SOLARIS) && (SOLARIS == 8)
72#include "round.h"72#include "round.h"
@@ -105,8 +105,20 @@
105static void cms_adjust_toggled( GtkWidget *button, gpointer data );105static void cms_adjust_toggled( GtkWidget *button, gpointer data );
106#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)106#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
107static void cms_adjust_set_sensitive( SPDesktopWidget *dtw, bool enabled );107static void cms_adjust_set_sensitive( SPDesktopWidget *dtw, bool enabled );
108static void sp_desktop_widget_rotate_document(GtkSpinButton *spin, SPDesktopWidget *dtw);
108static void sp_desktop_widget_adjustment_value_changed (GtkAdjustment *adj, SPDesktopWidget *dtw);109static void sp_desktop_widget_adjustment_value_changed (GtkAdjustment *adj, SPDesktopWidget *dtw);
109110
111static gint sp_dtw_rotation_input (GtkSpinButton *spin, gdouble *new_val, gpointer data);
112static bool sp_dtw_rotation_output (GtkSpinButton *spin, gpointer data);
113static void sp_dtw_rotation_populate_popup (GtkEntry *entry, GtkMenu *menu, gpointer data);
114static void sp_dtw_rotate_minus_180 (GtkMenuItem *item, SPDesktopWidget * data);
115static void sp_dtw_rotate_minus_135 (GtkMenuItem *item, SPDesktopWidget * data);
116static void sp_dtw_rotate_minus_90 (GtkMenuItem *item, SPDesktopWidget * data);
117static void sp_dtw_rotate_minus_45 (GtkMenuItem *item, SPDesktopWidget * data);
118static void sp_dtw_rotate_0 (GtkMenuItem *item, SPDesktopWidget * data);
119static void sp_dtw_rotate_45 (GtkMenuItem *item, SPDesktopWidget * data);
120static void sp_dtw_rotate_90 (GtkMenuItem *item, SPDesktopWidget * data);
121static void sp_dtw_rotate_135 (GtkMenuItem *item, SPDesktopWidget * data);
110static gdouble sp_dtw_zoom_value_to_display (gdouble value);122static gdouble sp_dtw_zoom_value_to_display (gdouble value);
111static gdouble sp_dtw_zoom_display_to_value (gdouble value);123static gdouble sp_dtw_zoom_display_to_value (gdouble value);
112static gint sp_dtw_zoom_input (GtkSpinButton *spin, gdouble *new_val, gpointer data);124static gint sp_dtw_zoom_input (GtkSpinButton *spin, gdouble *new_val, gpointer data);
@@ -593,6 +605,34 @@
593 g_signal_connect (G_OBJECT (dtw->zoom_status), "key-press-event", G_CALLBACK (spinbutton_keypress), dtw->zoom_status);605 g_signal_connect (G_OBJECT (dtw->zoom_status), "key-press-event", G_CALLBACK (spinbutton_keypress), dtw->zoom_status);
594 dtw->zoom_update = g_signal_connect (G_OBJECT (dtw->zoom_status), "value_changed", G_CALLBACK (sp_dtw_zoom_value_changed), dtw);606 dtw->zoom_update = g_signal_connect (G_OBJECT (dtw->zoom_status), "value_changed", G_CALLBACK (sp_dtw_zoom_value_changed), dtw);
595 dtw->zoom_update = g_signal_connect (G_OBJECT (dtw->zoom_status), "populate_popup", G_CALLBACK (sp_dtw_zoom_populate_popup), dtw);607 dtw->zoom_update = g_signal_connect (G_OBJECT (dtw->zoom_status), "populate_popup", G_CALLBACK (sp_dtw_zoom_populate_popup), dtw);
608 auto css_provider_spinbutton = Gtk::CssProvider::create();
609 css_provider_spinbutton->load_from_data("* { padding-left: 2; padding-right: 2; padding-top: 0; padding-bottom: 0;}");
610 auto zoomstat = Glib::wrap(dtw->zoom_status);
611 zoomstat->set_name("ZoomStatus");
612 auto context_zoom = zoomstat->get_style_context();
613 context_zoom->add_provider(css_provider_spinbutton, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
614
615 // Rotate status spinbutton
616 dtw->rotation_status = gtk_spin_button_new_with_range (-360.0,360.0, 1.0);
617 gtk_widget_set_tooltip_text (dtw->rotation_status, _("Rotation"));
618 gtk_widget_set_size_request (dtw->rotation_status, STATUS_ROTATION_WIDTH, -1);
619 gtk_entry_set_width_chars (GTK_ENTRY (dtw->rotation_status), 7);
620 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (dtw->rotation_status), FALSE);
621 gtk_spin_button_set_digits (GTK_SPIN_BUTTON (dtw->rotation_status), 2);
622 gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (dtw->rotation_status), GTK_UPDATE_ALWAYS);
623 g_signal_connect (G_OBJECT (dtw->rotation_status), "input", G_CALLBACK (sp_dtw_rotation_input), dtw);
624 g_signal_connect (G_OBJECT (dtw->rotation_status), "output", G_CALLBACK (sp_dtw_rotation_output), dtw);
625 g_object_set_data (G_OBJECT (dtw->rotation_status), "dtw", dtw->canvas);
626 g_signal_connect (G_OBJECT (dtw->rotation_status), "focus-in-event", G_CALLBACK (spinbutton_focus_in), dtw->rotation_status);
627 g_signal_connect (G_OBJECT (dtw->rotation_status), "key-press-event", G_CALLBACK (spinbutton_keypress), dtw->rotation_status);
628 dtw->rotation_update = g_signal_connect (G_OBJECT (dtw->rotation_status), "value_changed", G_CALLBACK (sp_desktop_widget_rotate_document), dtw);
629 dtw->rotation_update = g_signal_connect (G_OBJECT (dtw->rotation_status), "populate_popup", G_CALLBACK (sp_dtw_rotation_populate_popup), dtw);
630
631 auto rotstat = Glib::wrap(dtw->rotation_status);
632 rotstat->set_name("RotationStatus");
633 auto context_rotation = rotstat->get_style_context();
634 context_rotation->add_provider(css_provider_spinbutton, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
635
596636
597 // Cursor coordinates637 // Cursor coordinates
598 dtw->coord_status = gtk_grid_new();638 dtw->coord_status = gtk_grid_new();
@@ -619,12 +659,16 @@
619659
620 auto label_z = gtk_label_new(_("Z:"));660 auto label_z = gtk_label_new(_("Z:"));
621 gtk_widget_set_name(label_z, "ZLabel");661 gtk_widget_set_name(label_z, "ZLabel");
662 auto label_r = gtk_label_new(_("R:"));
663 gtk_widget_set_name(label_r, "RLabel");
622 gtk_widget_set_halign(dtw->coord_status_x, GTK_ALIGN_END);664 gtk_widget_set_halign(dtw->coord_status_x, GTK_ALIGN_END);
623 gtk_widget_set_halign(dtw->coord_status_y, GTK_ALIGN_END);665 gtk_widget_set_halign(dtw->coord_status_y, GTK_ALIGN_END);
624 gtk_grid_attach(GTK_GRID(dtw->coord_status), dtw->coord_status_x, 2, 0, 1, 1);666 gtk_grid_attach(GTK_GRID(dtw->coord_status), dtw->coord_status_x, 2, 0, 1, 1);
625 gtk_grid_attach(GTK_GRID(dtw->coord_status), dtw->coord_status_y, 2, 1, 1, 1);667 gtk_grid_attach(GTK_GRID(dtw->coord_status), dtw->coord_status_y, 2, 1, 1, 1);
626 gtk_grid_attach(GTK_GRID(dtw->coord_status), label_z, 3, 0, 1, 2);668 gtk_grid_attach(GTK_GRID(dtw->coord_status), label_z, 3, 0, 1, 2);
669 gtk_grid_attach(GTK_GRID(dtw->coord_status), label_r, 5, 0, 1, 2);
627 gtk_grid_attach(GTK_GRID(dtw->coord_status), dtw->zoom_status, 4, 0, 1, 2);670 gtk_grid_attach(GTK_GRID(dtw->coord_status), dtw->zoom_status, 4, 0, 1, 2);
671 gtk_grid_attach(GTK_GRID(dtw->coord_status), dtw->rotation_status, 6, 0, 1, 2);
628672
629 sp_set_font_size_smaller (dtw->coord_status);673 sp_set_font_size_smaller (dtw->coord_status);
630674
@@ -692,6 +736,11 @@
692 g_signal_handlers_disconnect_matched (G_OBJECT (dtw->zoom_status), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, dtw->zoom_status);736 g_signal_handlers_disconnect_matched (G_OBJECT (dtw->zoom_status), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, dtw->zoom_status);
693 g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->zoom_status), (gpointer) G_CALLBACK (sp_dtw_zoom_value_changed), dtw);737 g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->zoom_status), (gpointer) G_CALLBACK (sp_dtw_zoom_value_changed), dtw);
694 g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->zoom_status), (gpointer) G_CALLBACK (sp_dtw_zoom_populate_popup), dtw);738 g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->zoom_status), (gpointer) G_CALLBACK (sp_dtw_zoom_populate_popup), dtw);
739 g_signal_handlers_disconnect_by_func(G_OBJECT (dtw->rotation_status), (gpointer) G_CALLBACK(sp_dtw_rotation_input), dtw);
740 g_signal_handlers_disconnect_by_func(G_OBJECT (dtw->rotation_status), (gpointer) G_CALLBACK(sp_dtw_rotation_output), dtw);
741 g_signal_handlers_disconnect_matched (G_OBJECT (dtw->rotation_status), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, dtw->rotation_status);
742 g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->rotation_status), (gpointer) G_CALLBACK (sp_desktop_widget_rotate_document), dtw);
743 g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->rotation_status), (gpointer) G_CALLBACK (sp_dtw_rotation_populate_popup), dtw);
695 g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->canvas), (gpointer) G_CALLBACK (sp_desktop_widget_event), dtw);744 g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->canvas), (gpointer) G_CALLBACK (sp_desktop_widget_event), dtw);
696 g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->canvas_tbl), (gpointer) G_CALLBACK (canvas_tbl_size_allocate), dtw);745 g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->canvas_tbl), (gpointer) G_CALLBACK (canvas_tbl_size_allocate), dtw);
697746
@@ -1423,7 +1472,7 @@
1423 } else {1472 } else {
1424 gtk_widget_show_all (dtw->menubar);1473 gtk_widget_show_all (dtw->menubar);
1425 }1474 }
14261475
1427 if (!prefs->getBool(pref_root + "commands/state", true)) {1476 if (!prefs->getBool(pref_root + "commands/state", true)) {
1428 gtk_widget_hide (dtw->commands_toolbox);1477 gtk_widget_hide (dtw->commands_toolbox);
1429 } else {1478 } else {
@@ -1629,10 +1678,11 @@
1629 dtw->menubar = sp_ui_main_menubar (dtw->desktop);1678 dtw->menubar = sp_ui_main_menubar (dtw->desktop);
1630 gtk_widget_set_name(dtw->menubar, "MenuBar");1679 gtk_widget_set_name(dtw->menubar, "MenuBar");
1631 gtk_widget_show_all (dtw->menubar);1680 gtk_widget_show_all (dtw->menubar);
1632 gtk_box_pack_start (GTK_BOX (dtw->vbox), dtw->menubar, FALSE, FALSE, 0);1681 SPNamedView *nv = dtw->desktop->namedview;
16331682 gtk_box_pack_start (GTK_BOX (dtw->vbox), dtw->menubar, TRUE, TRUE, 0);
1634 dtw->layoutWidgets();1683 dtw->layoutWidgets();
16351684 gtk_spin_button_set_value(GTK_SPIN_BUTTON (dtw->rotation_status), namedview->document_rotation);
1685 sp_namedview_set_document_rotation(namedview);
1636 std::vector<GtkWidget *> toolboxes;1686 std::vector<GtkWidget *> toolboxes;
1637 toolboxes.push_back(dtw->tool_toolbox);1687 toolboxes.push_back(dtw->tool_toolbox);
1638 toolboxes.push_back(dtw->aux_toolbox);1688 toolboxes.push_back(dtw->aux_toolbox);
@@ -1672,6 +1722,8 @@
1672void SPDesktopWidget::namedviewModified(SPObject *obj, guint flags)1722void SPDesktopWidget::namedviewModified(SPObject *obj, guint flags)
1673{1723{
1674 SPNamedView *nv=SP_NAMEDVIEW(obj);1724 SPNamedView *nv=SP_NAMEDVIEW(obj);
1725 gtk_spin_button_set_value(GTK_SPIN_BUTTON(this->rotation_status), desktop->namedview->document_rotation);
1726 sp_namedview_set_document_rotation(nv);
16751727
1676 if (flags & SP_OBJECT_MODIFIED_FLAG) {1728 if (flags & SP_OBJECT_MODIFIED_FLAG) {
1677 this->dt2r = 1. / nv->display_units->factor;1729 this->dt2r = 1. / nv->display_units->factor;
@@ -1723,6 +1775,18 @@
1723}1775}
17241776
1725static void1777static void
1778sp_desktop_widget_rotate_document(GtkSpinButton *spin, SPDesktopWidget *dtw)
1779{
1780 SPNamedView *nv = dtw->desktop->namedview;
1781 double value = gtk_spin_button_get_value (spin);
1782 if (!dtw->desktop->getDocument()->getRoot()->rotated && value != nv->document_rotation) {
1783 sp_repr_set_svg_double(nv->getRepr(), "inkscape:document-rotation", value);
1784 }
1785 spinbutton_defocus (GTK_WIDGET(spin));
1786}
1787
1788
1789static void
1726sp_desktop_widget_adjustment_value_changed (GtkAdjustment */*adj*/, SPDesktopWidget *dtw)1790sp_desktop_widget_adjustment_value_changed (GtkAdjustment */*adj*/, SPDesktopWidget *dtw)
1727{1791{
1728 if (dtw->update)1792 if (dtw->update)
@@ -1802,6 +1866,34 @@
1802 return TRUE;1866 return TRUE;
1803}1867}
18041868
1869static gint
1870sp_dtw_rotation_input (GtkSpinButton *spin, gdouble *new_val, gpointer /*data*/)
1871{
1872 gdouble new_scrolled = gtk_spin_button_get_value (spin);
1873 const gchar *b = gtk_entry_get_text (GTK_ENTRY (spin));
1874 gdouble new_typed = atof (b);
1875
1876 if (new_scrolled == new_typed) { // the new value is set by scrolling
1877 *new_val = new_scrolled;
1878 } else { // the new value is typed in
1879 *new_val = new_typed;
1880 }
1881
1882 return TRUE;
1883}
1884
1885static bool
1886sp_dtw_rotation_output (GtkSpinButton *spin, gpointer /*data*/)
1887{
1888 gchar b[64];
1889 double val = gtk_spin_button_get_value (spin);
1890 std::ostringstream s;
1891 s.imbue(std::locale(""));;
1892 s << std::fixed << std::setprecision(2) << val << "º";
1893 gtk_entry_set_text (GTK_ENTRY (spin), s.str().c_str());
1894 return TRUE;
1895}
1896
1805static void1897static void
1806sp_dtw_zoom_value_changed (GtkSpinButton *spin, gpointer data)1898sp_dtw_zoom_value_changed (GtkSpinButton *spin, gpointer data)
1807{1899{
@@ -1940,6 +2032,110 @@
1940 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);2032 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1941}2033}
19422034
2035
2036static void
2037sp_dtw_rotation_populate_popup (GtkEntry */*entry*/, GtkMenu *menu, gpointer data)
2038{
2039 GList *children, *iter;
2040 GtkWidget *item;
2041 SPDesktopWidget *dtw = static_cast<SPDesktopWidget*>(data);
2042 children = gtk_container_get_children (GTK_CONTAINER (menu));
2043 for ( iter = children ; iter ; iter = g_list_next (iter)) {
2044 gtk_container_remove (GTK_CONTAINER (menu), GTK_WIDGET (iter->data));
2045 }
2046 g_list_free (children);
2047
2048 item = gtk_menu_item_new_with_label ("-180º");
2049 g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_minus_180), dtw);
2050 gtk_widget_show (item);
2051 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2052
2053 item = gtk_menu_item_new_with_label ("-135º");
2054 g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_minus_135), dtw);
2055 gtk_widget_show (item);
2056 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2057
2058 item = gtk_menu_item_new_with_label ("-90º");
2059 g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_minus_90), dtw);
2060 gtk_widget_show (item);
2061 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2062
2063 item = gtk_menu_item_new_with_label ("-45º");
2064 g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_minus_45), dtw);
2065 gtk_widget_show (item);
2066 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2067
2068 item = gtk_menu_item_new_with_label ("0º");
2069 g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_0), dtw);
2070 gtk_widget_show (item);
2071 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2072
2073 item = gtk_menu_item_new_with_label ("45º");
2074 g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_45), dtw);
2075 gtk_widget_show (item);
2076 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2077
2078
2079 item = gtk_menu_item_new_with_label ("90º");
2080 g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_90), dtw);
2081 gtk_widget_show (item);
2082 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2083
2084
2085 item = gtk_menu_item_new_with_label ("135º");
2086 g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_135), dtw);
2087 gtk_widget_show (item);
2088 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2089}
2090
2091static void
2092sp_dtw_rotate_minus_180 (GtkMenuItem */*item*/, SPDesktopWidget * data)
2093{
2094 gtk_spin_button_set_value (GTK_SPIN_BUTTON((data)->rotation_status),-180);
2095}
2096
2097static void
2098sp_dtw_rotate_minus_135 (GtkMenuItem */*item*/, SPDesktopWidget * data)
2099{
2100 gtk_spin_button_set_value (GTK_SPIN_BUTTON((data)->rotation_status), -135);
2101}
2102
2103static void
2104sp_dtw_rotate_minus_90 (GtkMenuItem */*item*/, SPDesktopWidget * data)
2105{
2106 gtk_spin_button_set_value (GTK_SPIN_BUTTON((data)->rotation_status), -90);
2107}
2108
2109static void
2110sp_dtw_rotate_minus_45 (GtkMenuItem */*item*/, SPDesktopWidget * data)
2111{
2112 gtk_spin_button_set_value (GTK_SPIN_BUTTON((data)->rotation_status), -45);
2113}
2114
2115static void
2116sp_dtw_rotate_0 (GtkMenuItem */*item*/,SPDesktopWidget * data)
2117{
2118 gtk_spin_button_set_value (GTK_SPIN_BUTTON((data)->rotation_status), 0);
2119}
2120
2121static void
2122sp_dtw_rotate_45 (GtkMenuItem */*item*/, SPDesktopWidget * data)
2123{
2124 gtk_spin_button_set_value (GTK_SPIN_BUTTON((data)->rotation_status), 45);
2125}
2126
2127static void
2128sp_dtw_rotate_90 (GtkMenuItem */*item*/, SPDesktopWidget * data)
2129{
2130 gtk_spin_button_set_value (GTK_SPIN_BUTTON((data)->rotation_status), 90);
2131}
2132
2133static void
2134sp_dtw_rotate_135 (GtkMenuItem */*item*/, SPDesktopWidget * data)
2135{
2136 gtk_spin_button_set_value (GTK_SPIN_BUTTON((data)->rotation_status), 135);
2137}
2138
1943static void2139static void
1944sp_dtw_zoom_menu_handler (SPDesktop *dt, gdouble factor)2140sp_dtw_zoom_menu_handler (SPDesktop *dt, gdouble factor)
1945{2141{
19462142
=== modified file 'src/widgets/desktop-widget.h'
--- src/widgets/desktop-widget.h 2015-12-09 15:13:54 +0000
+++ src/widgets/desktop-widget.h 2017-01-24 17:53:20 +0000
@@ -78,7 +78,7 @@
7878
79 GtkWidget *hbox;79 GtkWidget *hbox;
8080
81 GtkWidget *menubar, *statusbar;81 GtkWidget *menubar, *statusbar, *rotatebar;
8282
83 Inkscape::UI::Dialogs::SwatchesPanel *panels;83 Inkscape::UI::Dialogs::SwatchesPanel *panels;
8484
@@ -97,7 +97,9 @@
97 GtkWidget *select_status;97 GtkWidget *select_status;
98 GtkWidget *select_status_eventbox;98 GtkWidget *select_status_eventbox;
99 GtkWidget *zoom_status;99 GtkWidget *zoom_status;
100 GtkWidget *rotation_status;
100 gulong zoom_update;101 gulong zoom_update;
102 gulong rotation_update;
101103
102 Inkscape::UI::Widget::Dock *dock;104 Inkscape::UI::Widget::Dock *dock;
103105
104106
=== modified file 'src/widgets/widget-sizes.h'
--- src/widgets/widget-sizes.h 2014-03-27 01:33:44 +0000
+++ src/widgets/widget-sizes.h 2017-01-24 17:53:20 +0000
@@ -28,6 +28,7 @@
28#define STATUS_BAR_FONT_SIZE 1000028#define STATUS_BAR_FONT_SIZE 10000
2929
30#define STATUS_ZOOM_WIDTH 5730#define STATUS_ZOOM_WIDTH 57
31#define STATUS_ROTATION_WIDTH 57
3132
32#define SELECTED_STYLE_SB_WIDTH 4833#define SELECTED_STYLE_SB_WIDTH 48
33#define SELECTED_STYLE_WIDTH 19034#define SELECTED_STYLE_WIDTH 190