summaryrefslogtreecommitdiffstats
path: root/src/display
diff options
context:
space:
mode:
Diffstat (limited to 'src/display')
-rw-r--r--src/display/CMakeLists.txt4
-rw-r--r--src/display/canvas-debug.cpp100
-rw-r--r--src/display/canvas-debug.h41
-rw-r--r--src/display/canvas-grid.cpp254
-rw-r--r--src/display/canvas-grid.h2
-rw-r--r--src/display/canvas-rotate.cpp288
-rw-r--r--src/display/canvas-rotate.h50
-rw-r--r--src/display/canvas-temporary-item-list.h1
-rw-r--r--src/display/gnome-canvas-acetate.cpp8
-rw-r--r--src/display/sodipodi-ctrlrect.cpp262
-rw-r--r--src/display/sodipodi-ctrlrect.h11
-rw-r--r--src/display/sp-canvas.cpp308
-rw-r--r--src/display/sp-canvas.h11
13 files changed, 788 insertions, 552 deletions
diff --git a/src/display/CMakeLists.txt b/src/display/CMakeLists.txt
index 0bf1d6e45..8eaaee99a 100644
--- a/src/display/CMakeLists.txt
+++ b/src/display/CMakeLists.txt
@@ -4,7 +4,9 @@ set(display_SRC
canvas-arena.cpp
canvas-axonomgrid.cpp
canvas-bpath.cpp
+ canvas-debug.cpp
canvas-grid.cpp
+ canvas-rotate.cpp
canvas-temporary-item-list.cpp
canvas-temporary-item.cpp
canvas-text.cpp
@@ -64,7 +66,9 @@ set(display_SRC
canvas-arena.h
canvas-axonomgrid.h
canvas-bpath.h
+ canvas-debug.h
canvas-grid.h
+ canvas-rotate.h
canvas-temporary-item-list.h
canvas-temporary-item.h
canvas-text.h
diff --git a/src/display/canvas-debug.cpp b/src/display/canvas-debug.cpp
new file mode 100644
index 000000000..1748029e9
--- /dev/null
+++ b/src/display/canvas-debug.cpp
@@ -0,0 +1,100 @@
+/*
+ * A simple surface for debugging the canvas. Shows how tiles are drawn.
+ *
+ * Author:
+ * Tavmjong Bah <tavmjong@free.fr>
+ *
+ * Copyright (C) 2017 Tavmjong Bah
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "inkscape.h"
+#include "desktop.h"
+
+#include "canvas-debug.h"
+#include "sp-canvas.h"
+#include "cairo-utils.h"
+#include "ui/event-debug.h"
+
+namespace {
+
+static void sp_canvas_debug_destroy(SPCanvasItem *item);
+static void sp_canvas_debug_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags);
+static void sp_canvas_debug_render (SPCanvasItem *item, SPCanvasBuf *buf);
+static int sp_canvas_debug_event (SPCanvasItem *item, GdkEvent *event);
+
+} // namespace
+
+G_DEFINE_TYPE(SPCanvasDebug, sp_canvas_debug, SP_TYPE_CANVAS_ITEM);
+
+static void sp_canvas_debug_class_init (SPCanvasDebugClass *klass)
+{
+ klass->destroy = sp_canvas_debug_destroy;
+ klass->update = sp_canvas_debug_update;
+ klass->render = sp_canvas_debug_render;
+ klass->event = sp_canvas_debug_event;
+}
+
+static void sp_canvas_debug_init (SPCanvasDebug *debug)
+{
+ debug->pickable = true; // So we can receive events.
+}
+
+namespace {
+static void sp_canvas_debug_destroy (SPCanvasItem *object)
+{
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (SP_IS_CANVAS_DEBUG (object));
+
+ if (SP_CANVAS_ITEM_CLASS(sp_canvas_debug_parent_class)->destroy) {
+ SP_CANVAS_ITEM_CLASS(sp_canvas_debug_parent_class)->destroy(object);
+ }
+}
+
+static void sp_canvas_debug_update( SPCanvasItem *item, Geom::Affine const &/*affine*/, unsigned int /*flags*/ )
+{
+ // We cover the entire canvas
+ item->x1 = -G_MAXINT;
+ item->y1 = -G_MAXINT;
+ item->x2 = G_MAXINT;
+ item->y2 = G_MAXINT;
+}
+
+static void sp_canvas_debug_render( SPCanvasItem *item, SPCanvasBuf *buf)
+{
+ if (!buf->ct) {
+ return;
+ }
+
+ cairo_set_line_width (buf->ct, 2);
+
+ // Draw box around buffer (for debugging)
+ cairo_new_path (buf->ct);
+ cairo_move_to (buf->ct, 0, 0);
+ cairo_line_to (buf->ct, buf->rect.width(), 0);
+ cairo_line_to (buf->ct, buf->rect.width(), buf->rect.height());
+ cairo_line_to (buf->ct, 0, buf->rect.height());
+ cairo_close_path (buf->ct);
+ ink_cairo_set_source_rgba32 (buf->ct, 0xff7f7f7f);
+ cairo_stroke (buf->ct);
+}
+
+static int sp_canvas_debug_event (SPCanvasItem *item, GdkEvent *event)
+{
+ ui_dump_event (event, Glib::ustring("sp_canvas_debug_event"));
+ return false; // We don't use any events...
+}
+
+} // namespace
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/canvas-debug.h b/src/display/canvas-debug.h
new file mode 100644
index 000000000..d5a166da9
--- /dev/null
+++ b/src/display/canvas-debug.h
@@ -0,0 +1,41 @@
+#ifndef SEEN_SP_CANVAS_DEBUG_H
+#define SEEN_SP_CANVAS_DEBUG_H
+
+/*
+ * A simple surface for debugging the canvas. Shows how tiles are drawn.
+ *
+ * Author:
+ * Tavmjong Bah <tavmjong@free.fr>
+ *
+ * Copyright (C) 2017 Tavmjong Bah
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "sp-canvas-item.h"
+
+class SPItem;
+
+#define SP_TYPE_CANVAS_DEBUG (sp_canvas_debug_get_type ())
+#define SP_CANVAS_DEBUG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_CANVAS_DEBUG, SPCanvasDebug))
+#define SP_IS_CANVAS_DEBUG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_CANVAS_DEBUG))
+
+struct SPCanvasDebug : public SPCanvasItem {
+};
+
+GType sp_canvas_debug_get_type (void);
+
+struct SPCanvasDebugClass : public SPCanvasItemClass{};
+
+#endif // SEEN_SP_CANVAS_DEBUG_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/display/canvas-grid.cpp b/src/display/canvas-grid.cpp
index 2dadde336..4243d3365 100644
--- a/src/display/canvas-grid.cpp
+++ b/src/display/canvas-grid.cpp
@@ -5,6 +5,7 @@
* Copyright (C) Lauris Kaplinski 2000
* Abhishek Sharma
* Jon A. Cruz <jon@joncruz.org>
+ * Copyright (C) Tavmong Bah 2017 <tavmjong@free.fr>
*/
/* As a general comment, I am not exactly proud of how things are done.
@@ -841,21 +842,19 @@ void
CanvasXYGrid::Update (Geom::Affine const &affine, unsigned int /*flags*/)
{
ow = origin * affine;
- // Temp hack to insure grid doesn't collapse with rotation.
- sw[0] = spacing[0] * sqrt(affine[0]*affine[0] + affine[1]*affine[1]);
- sw[1] = spacing[1] * sqrt(affine[2]*affine[2] + affine[3]*affine[3]);
- sw -= Geom::Point(affine[4], affine[5]);
+ sw[0] = Geom::Point(spacing[0], 0) * affine.withoutTranslation();
+ sw[1] = Geom::Point(0, spacing[1]) * affine.withoutTranslation();
+ // Find suitable grid spacing for display
for(int dim = 0; dim < 2; dim++) {
gint scaling_factor = empspacing;
if (scaling_factor <= 1)
scaling_factor = 5;
- scaled[dim] = FALSE;
- sw[dim] = fabs (sw[dim]);
- while (sw[dim] < 8.0) {
- scaled[dim] = TRUE;
+ scaled[dim] = false;
+ while (fabs(sw[dim].length()) < 8.0) {
+ scaled[dim] = true;
sw[dim] *= scaling_factor;
/* First pass, go up to the major line spacing, then
keep increasing by two. */
@@ -865,49 +864,45 @@ CanvasXYGrid::Update (Geom::Affine const &affine, unsigned int /*flags*/)
}
-static void
-grid_hline (SPCanvasBuf *buf, gint y, gint xs, gint xe, guint32 rgba)
+// Find intersections of line with rectangle. There should be zero or two.
+// If line is degenerate with rectangle side, two corner points are returned.
+static std::vector<Geom::Point>
+intersect_line_rectangle( Geom::Line const &line, Geom::Rect const &rect )
{
- if ((y < buf->rect.top()) || (y >= buf->rect.bottom()))
- return;
-
- cairo_move_to(buf->ct, 0.5 + xs, 0.5 + y);
- cairo_line_to(buf->ct, 0.5 + xe, 0.5 + y);
- ink_cairo_set_source_rgba32(buf->ct, rgba);
- cairo_stroke(buf->ct);
-}
-
-static void
-grid_vline (SPCanvasBuf *buf, gint x, gint ys, gint ye, guint32 rgba)
-{
- if ((x < buf->rect.left()) || (x >= buf->rect.right()))
- return;
-
- cairo_move_to(buf->ct, 0.5 + x, 0.5 + ys);
- cairo_line_to(buf->ct, 0.5 + x, 0.5 + ye);
- ink_cairo_set_source_rgba32(buf->ct, rgba);
- cairo_stroke(buf->ct);
+ std::vector<Geom::Point> intersections;
+ for (unsigned i = 0; i < 4; ++i) {
+ Geom::LineSegment side( rect.corner(i), rect.corner((i+1)%4) );
+ try {
+ Geom::OptCrossing oc = Geom::intersection(line, side);
+ if (oc) {
+ intersections.push_back( line.pointAt((*oc).ta));
+ }
+ } catch (Geom::InfiniteSolutions) {
+ intersections.clear();
+ intersections.push_back( side.pointAt(0) );
+ intersections.push_back( side.pointAt(1) );
+ return intersections;
+ }
+ }
+ return intersections;
}
-static void
-grid_dot (SPCanvasBuf *buf, gint x, gint y, guint32 rgba)
-{
- if ( (y < buf->rect.top()) || (y >= buf->rect.bottom())
- || (x < buf->rect.left()) || (x >= buf->rect.right()) )
- return;
-
- cairo_rectangle(buf->ct, x, y, 1, 1);
- ink_cairo_set_source_rgba32(buf->ct, rgba);
- cairo_fill(buf->ct);
+// Find the signed distance of a point to a line. The distance is negative if
+// the point lies to the left of the line considering the line's versor.
+static double
+signed_distance( Geom::Point const &point, Geom::Line const &line ) {
+ Geom::Coord t = line.nearestTime( point );
+ Geom::Point p = line.pointAt(t);
+ double distance = Geom::distance( p, point );
+ if ( Geom::cross( Geom::Line( p, point ).versor(), line.versor() ) < 0.0 ) {
+ distance = -distance;
+ }
+ return distance;
}
void
CanvasXYGrid::Render (SPCanvasBuf *buf)
{
- gdouble const sxg = floor ((buf->rect.left() - ow[Geom::X]) / sw[Geom::X]) * sw[Geom::X] + ow[Geom::X];
- gint const xlinestart = round((sxg - ow[Geom::X]) / sw[Geom::X]);
- gdouble const syg = floor ((buf->rect.top() - ow[Geom::Y]) / sw[Geom::Y]) * sw[Geom::Y] + ow[Geom::Y];
- gint const ylinestart = round((syg - ow[Geom::Y]) / sw[Geom::Y]);
// no_emphasize_when_zoomedout determines color (minor or major) when only major grid lines/dots shown.
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
@@ -924,75 +919,128 @@ CanvasXYGrid::Render (SPCanvasBuf *buf)
cairo_set_line_width(buf->ct, 1.0);
cairo_set_line_cap(buf->ct, CAIRO_LINE_CAP_SQUARE);
- if (!render_dotted) {
- // Line grid
- gint ylinenum;
- gdouble y;
- for (y = syg, ylinenum = ylinestart; y < buf->rect.bottom(); y += sw[Geom::Y], ylinenum++) {
- gint const y0 = round(y);
- if (!scaled[Geom::Y] && (ylinenum % empspacing) != 0) {
- grid_hline (buf, y0, buf->rect.left(), buf->rect.right() - 1, color);
- } else {
- grid_hline (buf, y0, buf->rect.left(), buf->rect.right() - 1, _empcolor);
- }
- }
+ for (unsigned dim = 0; dim < 2; ++dim) {
- gint xlinenum;
- gdouble x;
- for (x = sxg, xlinenum = xlinestart; x < buf->rect.right(); x += sw[Geom::X], xlinenum++) {
- gint const ix = round(x);
- if (!scaled[Geom::X] && (xlinenum % empspacing) != 0) {
- grid_vline (buf, ix, buf->rect.top(), buf->rect.bottom(), color);
- } else {
- grid_vline (buf, ix, buf->rect.top(), buf->rect.bottom(), _empcolor);
+ // std::cout << "\n " << (dim==0?"Horizontal":"Vertical") << " ------------" << std::endl;
+
+ // Construct an axis line through origin with direction normal to grid spacing.
+ Geom::Line axis = Geom::Line::from_origin_and_vector( ow, sw[dim] );
+ Geom::Line orth = Geom::Line::from_origin_and_vector( ow, sw[(dim+1)%2] );
+
+ double spacing = sw[(dim+1)%2].length(); // Spacing between grid lines.
+ double dash = sw[dim].length(); // Total length of dash pattern.
+
+ // std::cout << " axis: " << axis.origin() << ", " << axis.vector() << std::endl;
+ // std::cout << " spacing: " << spacing << std::endl;
+ // std::cout << " dash period: " << dash << std::endl;
+
+ // Find the minimum and maximum distances of the buffer corners from axis.
+ double min = 1000000;
+ double max = -1000000;
+ for (unsigned c = 0; c < 4; ++c) {
+
+ // We need signed distance... lib2geom offers only positive distance.
+ double distance = signed_distance( buf->rect.corner(c), axis );
+
+ // Correct it for coordinate flips (inverts handedness).
+ if (Geom::cross( axis.vector(), orth.vector() ) > 0 ) {
+ distance = -distance;
}
+
+ if (distance < min)
+ min = distance;
+ if (distance > max)
+ max = distance;
}
- } else {
- // Dotted grid
- gint ylinenum;
- gdouble y;
-
- // alpha needs to be larger than in the line case to maintain a similar visual impact but
- // setting it to the maximal value makes the dots dominant in some cases. Solution,
- // increase the alpha by a factor of 4. This then allows some user adjustment.
- guint32 _empdot = (_empcolor & 0xff) << 2;
- if (_empdot > 0xff)
- _empdot = 0xff;
- _empdot += (_empcolor & 0xffffff00);
-
- guint32 _colordot = (color & 0xff) << 2;
- if (_colordot > 0xff)
- _colordot = 0xff;
- _colordot += (color & 0xffffff00);
-
- for (y = syg, ylinenum = ylinestart; y < buf->rect.bottom(); y += sw[Geom::Y], ylinenum++) {
- gint const iy = round(y);
-
- gint xlinenum;
- gdouble x;
- for (x = sxg, xlinenum = xlinestart; x < buf->rect.right(); x += sw[Geom::X], xlinenum++) {
- gint const ix = round(x);
- if ( (!scaled[Geom::X] && (xlinenum % empspacing) != 0)
- || (!scaled[Geom::Y] && (ylinenum % empspacing) != 0)
- || ((scaled[Geom::X] || scaled[Geom::Y]) && no_emp_when_zoomed_out) )
- {
- // Minor point: dot only
- grid_dot (buf, ix, iy, _colordot); // | (guint32)0x000000FF); // put alpha to max value
+ int start = floor( min/spacing );
+ int stop = floor( max/spacing );
+
+ // std::cout << " rect: " << buf->rect << std::endl;
+ // std::cout << " min: " << min << " max: " << max << std::endl;
+ // std::cout << " start: " << start << " stop: " << stop << std::endl;
+
+ // Loop over grid lines that intersected buf rectangle.
+ for (int j = start+1; j <= stop; ++j) {
+
+ Geom::Line grid_line = Geom::make_parallel_line( ow + j * sw[(dim+1)%2], axis );
+
+ std::vector<Geom::Point> x = intersect_line_rectangle( grid_line, buf->rect );
+
+ // If we have two intersections, grid line intersects buffer rectangle.
+ if (x.size() == 2 ) {
+
+ // Make sure lines are always drawn in the same direction (or dashes misplaced).
+ Geom::Line vector( x[0], x[1]);
+ if (Geom::dot( vector.vector(), axis.vector() ) < 0.0) {
+ std::swap(x[0], x[1]);
+ }
+
+ // Set up line.
+ cairo_move_to(buf->ct, x[0][Geom::X] + 0.5, x[0][Geom::Y] + 0.5);
+ cairo_line_to(buf->ct, x[1][Geom::X] + 0.5, x[1][Geom::Y] + 0.5);
+
+ // Set dash pattern and color.
+ if (render_dotted) {
+
+ // alpha needs to be larger than in the line case to maintain a similar
+ // visual impact but setting it to the maximal value makes the dots
+ // dominant in some cases. Solution, increase the alpha by a factor of
+ // 4. This then allows some user adjustment.
+ guint32 _empdot = (_empcolor & 0xff) << 2;
+ if (_empdot > 0xff)
+ _empdot = 0xff;
+ _empdot += (_empcolor & 0xffffff00);
+
+ guint32 _colordot = (color & 0xff) << 2;
+ if (_colordot > 0xff)
+ _colordot = 0xff;
+ _colordot += (color & 0xffffff00);
+
+ // Dash pattern must use spacing from orthogonal direction.
+ // Offset is to center dash on orthogonal lines.
+ double offset = fmod( signed_distance( x[0], orth ), sw[dim].length());
+ if (Geom::cross( axis.vector(), orth.vector() ) > 0 ) {
+ offset = -offset;
+ }
+
+ double dashes[2];
+ if (!scaled[dim] && (j % empspacing) != 0) {
+ // Minor lines
+ dashes[0] = 1;
+ dashes[1] = dash -1;
+ offset -= 0.5;
+ ink_cairo_set_source_rgba32(buf->ct, _colordot);
+ } else {
+ // Major lines
+ dashes[0] = 3;
+ dashes[1] = dash - 3;
+ offset -= 1.5; // Center dash on intersection.
+ ink_cairo_set_source_rgba32(buf->ct, _empdot);
+ }
+
+ cairo_set_line_cap(buf->ct, CAIRO_LINE_CAP_BUTT);
+ cairo_set_dash(buf->ct, dashes, 2, -offset);
+
} else {
- // Major point: small cross
- gint const pitch = 1;
- grid_dot (buf, ix-pitch, iy, _empcolor);
- grid_dot (buf, ix+pitch, iy, _empcolor);
- grid_dot (buf, ix, iy, _empdot ); // | (guint32)0x000000FF); // put alpha to max value
+ // Solid lines
- grid_dot (buf, ix, iy-pitch, _empcolor);
- grid_dot (buf, ix, iy+pitch, _empcolor);
+ // Set color
+ if (!scaled[dim] && (j % empspacing) != 0) {
+ ink_cairo_set_source_rgba32(buf->ct, color );
+ } else {
+ ink_cairo_set_source_rgba32(buf->ct, _empcolor );
+ }
}
- }
+ cairo_stroke(buf->ct);
+
+ } else {
+ std::cerr << "CanvasXYGrid::render: Grid line doesn't intersect!" << std::endl;
+ }
}
}
+
cairo_restore(buf->ct);
}
@@ -1031,7 +1079,7 @@ CanvasXYGridSnapper::_getSnapLines(Geom::Point const &p) const
if (getSnapVisibleOnly()) {
// Only snapping to visible grid lines
- spacing = grid->sw[i]; // this is the spacing of the visible grid lines measured in screen pixels
+ spacing = grid->sw[i].length(); // this is the spacing of the visible grid lines measured in screen pixels
// convert screen pixels to px
// FIXME: after we switch to snapping dist in screen pixels, this will be unnecessary
SPDesktop const *dt = _snapmanager->getDesktop();
diff --git a/src/display/canvas-grid.h b/src/display/canvas-grid.h
index bf520467a..91fa43e69 100644
--- a/src/display/canvas-grid.h
+++ b/src/display/canvas-grid.h
@@ -148,7 +148,7 @@ public:
be different in the X or Y direction, hence two
variables */
Geom::Point ow; /**< Transformed origin by the affine for the zoom */
- Geom::Point sw; /**< Transformed spacing by the affine for the zoom */
+ Geom::Point sw[2]; /**< Transformed spacing by the affine for the zoom */
protected:
virtual Gtk::Widget * newSpecificWidget();
diff --git a/src/display/canvas-rotate.cpp b/src/display/canvas-rotate.cpp
new file mode 100644
index 000000000..aaf6b962c
--- /dev/null
+++ b/src/display/canvas-rotate.cpp
@@ -0,0 +1,288 @@
+/*
+ * Temporary surface for previewing rotated canvas.
+ *
+ * Author:
+ * Tavmjong Bah <tavmjong@free.fr>
+ *
+ * Copyright (C) 2017 Tavmjong Bah
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "inkscape.h"
+#include "desktop.h"
+
+#include "canvas-rotate.h"
+#include "sp-canvas.h"
+#include "cairo-utils.h"
+#include "ui/event-debug.h"
+
+#include "2geom/point.h"
+#include "2geom/rect.h"
+
+#include <gtk/gtk.h>
+
+namespace {
+
+static void sp_canvas_rotate_destroy(SPCanvasItem *item);
+static void sp_canvas_rotate_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags);
+static void sp_canvas_rotate_render (SPCanvasItem *item, SPCanvasBuf *buf);
+static int sp_canvas_rotate_event (SPCanvasItem *item, GdkEvent *event);
+
+} // namespace
+
+void sp_canvas_rotate_paint (SPCanvasRotate *canvas_rotate, cairo_surface_t *background);
+
+G_DEFINE_TYPE(SPCanvasRotate, sp_canvas_rotate, SP_TYPE_CANVAS_ITEM);
+
+static void sp_canvas_rotate_class_init (SPCanvasRotateClass *klass)
+{
+ klass->destroy = sp_canvas_rotate_destroy;
+ //klass->update = sp_canvas_rotate_update;
+ //klass->render = sp_canvas_rotate_render;
+ klass->event = sp_canvas_rotate_event;
+}
+
+static void sp_canvas_rotate_init (SPCanvasRotate *rotate)
+{
+ rotate->pickable = true; // So we can receive events.
+ rotate->angle = 0.0;
+ rotate->start_angle = -1000;
+ rotate->surface_copy = NULL;
+ rotate->surface_rotated = NULL;
+}
+
+namespace {
+static void sp_canvas_rotate_destroy (SPCanvasItem *object)
+{
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (SP_IS_CANVAS_ROTATE (object));
+
+ if (SP_CANVAS_ITEM_CLASS(sp_canvas_rotate_parent_class)->destroy) {
+ SP_CANVAS_ITEM_CLASS(sp_canvas_rotate_parent_class)->destroy(object);
+ }
+}
+
+// NOT USED... TOO SLOW
+static void sp_canvas_rotate_update( SPCanvasItem *item, Geom::Affine const &/*affine*/, unsigned int /*flags*/ )
+{
+ SPCanvasRotate *cr = SP_CANVAS_ROTATE(item);
+
+ if (cr->surface_copy == NULL) {
+ // std::cout << "sp_canvas_rotate_update: surface_copy is NULL" << std::endl;
+ return;
+ }
+
+ // Destroy surface_rotated if it already exists.
+ if (cr->surface_rotated != NULL) {
+ cairo_surface_destroy (cr->surface_rotated);
+ cr->surface_rotated = NULL;
+ }
+
+ // Create rotated surface
+ cr->surface_rotated = ink_cairo_surface_create_identical(cr->surface_copy);
+ double width = cairo_image_surface_get_width (cr->surface_rotated);
+ double height = cairo_image_surface_get_height (cr->surface_rotated);
+ cairo_t *context = cairo_create( cr->surface_rotated );
+ cairo_set_operator( context, CAIRO_OPERATOR_SOURCE );
+ cairo_translate( context, width/2.0, height/2.0 );
+ cairo_rotate( context, Geom::rad_from_deg(-cr->angle) );
+ cairo_translate( context, -width/2.0, -height/2.0 );
+ cairo_set_source_surface( context, cr->surface_copy, 0, 0 );
+ cairo_paint( context );
+ cairo_destroy( context);
+
+ // We cover the entire canvas
+ item->x1 = -G_MAXINT;
+ item->y1 = -G_MAXINT;
+ item->x2 = G_MAXINT;
+ item->y2 = G_MAXINT;
+
+ item->canvas->requestRedraw(item->x1, item->y1, item->x2, item->y2);
+}
+
+// NOT USED... TOO SLOW
+static void sp_canvas_rotate_render( SPCanvasItem *item, SPCanvasBuf *buf)
+{
+ // std::cout << "sp_canvas_rotate_render:" << std::endl;
+ // std::cout << " buf->rect: " << buf->rect << std::endl;
+ // std::cout << " buf->canvas_rect: " << buf->canvas_rect << std::endl;
+ SPCanvasRotate *cr = SP_CANVAS_ROTATE(item);
+
+ if (!buf->ct) {
+ return;
+ }
+
+ if (cr->surface_rotated == NULL ) {
+ // std::cout << " surface_rotated is NULL" << std::endl;
+ return;
+ }
+
+ // Draw rotated canvas
+ cairo_save (buf->ct);
+ cairo_translate (buf->ct,
+ buf->canvas_rect.left() - buf->rect.left(),
+ buf->canvas_rect.top() - buf->rect.top() );
+ cairo_set_operator (buf->ct, CAIRO_OPERATOR_SOURCE );
+ cairo_set_source_surface (buf->ct, cr->surface_rotated, 0, 0 );
+ cairo_paint (buf->ct);
+ cairo_restore (buf->ct);
+
+
+ // Draw line from center to cursor
+ cairo_save (buf->ct);
+ cairo_translate (buf->ct, -buf->rect.left(), -buf->rect.top());
+ cairo_new_path (buf->ct);
+ cairo_move_to (buf->ct, cr->center[Geom::X], cr->center[Geom::Y]);
+ cairo_rel_line_to (buf->ct, cr->cursor[Geom::X], cr->cursor[Geom::Y]);
+ cairo_set_line_width (buf->ct, 2);
+ ink_cairo_set_source_rgba32 (buf->ct, 0xff00007f);
+ cairo_stroke (buf->ct);
+ cairo_restore (buf->ct);
+
+}
+
+static int sp_canvas_rotate_event (SPCanvasItem *item, GdkEvent *event)
+{
+ SPCanvasRotate *cr = SP_CANVAS_ROTATE(item);
+
+// ui_dump_event (event, Glib::ustring("sp_canvas_rotate_event"));
+
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ Geom::Rect viewbox = desktop->canvas->getViewbox(); // Not SVG viewbox!
+ cr->center = viewbox.midpoint();
+
+ switch (event->type) {
+ case GDK_MOTION_NOTIFY:
+ {
+ Geom::Point cursor( event->motion.x, event->motion.y );
+
+ // Both cursor and center are in window coordinates
+ Geom::Point rcursor( cursor - cr->center );
+ double angle = Geom::deg_from_rad( Geom::atan2(rcursor) );
+
+ // Set start angle
+ if (cr->start_angle < -360) {
+ cr->start_angle = angle;
+ }
+
+ double rotation_snap = 15;
+
+ double delta_angle = cr->start_angle - angle;
+
+ if (event->motion.state & GDK_SHIFT_MASK &&
+ event->motion.state & GDK_CONTROL_MASK) {
+ delta_angle = 0;
+ } else if (event->motion.state & GDK_SHIFT_MASK) {
+ delta_angle = round(delta_angle/rotation_snap) * rotation_snap;
+ } else if (event->motion.state & GDK_CONTROL_MASK) {
+ // ?
+ } else if (event->motion.state & GDK_MOD1_MASK) {
+ // Decimal raw angle
+ } else {
+ delta_angle = floor(delta_angle);
+ }
+
+ cr->angle = delta_angle;
+
+ // Correct line for snapping of angle
+ double distance = rcursor.length();
+ cr->cursor = Geom::Point::polar( Geom::rad_from_deg(angle), distance );
+
+ // Update screen
+ // sp_canvas_item_request_update( item );
+ sp_canvas_rotate_paint (cr, cr->canvas->_backing_store);
+ break;
+ }
+ case GDK_BUTTON_RELEASE:
+
+ // Rotate the actual canvas
+ desktop->rotate_relative_center_point (desktop->w2d(cr->center),
+ Geom::rad_from_deg(cr->angle) );
+
+ // We're done
+ sp_canvas_item_ungrab (item, event->button.time);
+ sp_canvas_item_hide (item);
+
+ cr->start_angle = -1000;
+ if (cr->surface_copy != NULL) {
+ cairo_surface_destroy( cr->surface_copy );
+ cr->surface_copy = NULL;
+ }
+ if (cr->surface_rotated != NULL) {
+ cairo_surface_destroy( cr->surface_rotated );
+ cr->surface_rotated = NULL;
+ }
+ // sp_canvas_item_show (desktop->drawing);
+
+ break;
+ case GDK_KEY_PRESS:
+ // std::cout << " Key press: " << std::endl;
+ break;
+ case GDK_KEY_RELEASE:
+ // std::cout << " Key release: " << std::endl;
+ break;
+ default:
+ // ui_dump_event (event, "sp_canvas_rotate_event: unwanted event: ");
+ break;
+ }
+
+ if (event->type == GDK_KEY_PRESS) return false;
+
+ return true;
+}
+
+} // namespace
+
+void sp_canvas_rotate_start (SPCanvasRotate *canvas_rotate, cairo_surface_t *background)
+{
+ if (background == NULL) {
+ std::cerr << "sp_canvas_rotate_start: background is NULL!" << std::endl;
+ return;
+ }
+
+ canvas_rotate->angle = 0.0;
+
+ // Copy current background
+ canvas_rotate->surface_copy = ink_cairo_surface_copy( background );
+
+ // Paint canvas with background... since we are hiding drawing.
+ sp_canvas_item_request_update( canvas_rotate );
+}
+
+// Paint the canvas ourselves for speed....
+void sp_canvas_rotate_paint (SPCanvasRotate *canvas_rotate, cairo_surface_t *background)
+{
+ if (background == NULL) {
+ std::cerr << "sp_canvas_rotate_paint: background is NULL!" << std::endl;
+ return;
+ }
+
+ double width = cairo_image_surface_get_width (background);
+ double height = cairo_image_surface_get_height (background);
+
+ // Draw rotated canvas
+ cairo_t *context = cairo_create( background );
+
+ cairo_save (context);
+ cairo_set_operator( context, CAIRO_OPERATOR_SOURCE );
+ cairo_translate( context, width/2.0, height/2.0 );
+ cairo_rotate( context, Geom::rad_from_deg(-canvas_rotate->angle) );
+ cairo_translate( context, -width/2.0, -height/2.0 );
+ cairo_set_source_surface( context, canvas_rotate->surface_copy, 0, 0 );
+ cairo_paint( context );
+ cairo_restore( context );
+ cairo_destroy( context );
+
+ gtk_widget_queue_draw (GTK_WIDGET (canvas_rotate->canvas));
+}
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/canvas-rotate.h b/src/display/canvas-rotate.h
new file mode 100644
index 000000000..8620dcced
--- /dev/null
+++ b/src/display/canvas-rotate.h
@@ -0,0 +1,50 @@
+#ifndef SEEN_SP_CANVAS_ROTATE_H
+#define SEEN_SP_CANVAS_ROTATE_H
+
+/*
+ * Temporary surface for previewing rotated canvas.
+ *
+ * Author:
+ * Tavmjong Bah <tavmjong@free.fr>
+ *
+ * Copyright (C) 2017 Tavmjong Bah
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "sp-canvas-item.h"
+#include "2geom/line.h"
+
+class SPItem;
+
+#define SP_TYPE_CANVAS_ROTATE (sp_canvas_rotate_get_type ())
+#define SP_CANVAS_ROTATE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_CANVAS_ROTATE, SPCanvasRotate))
+#define SP_IS_CANVAS_ROTATE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_CANVAS_ROTATE))
+
+struct SPCanvasRotate : public SPCanvasItem {
+ Geom::Point center; // Center of screen
+ Geom::Point cursor; // Position of cursor relative to center (after angle snapping)
+ double angle; // Rotation angle in degrees
+ double start_angle; // Starting angle of cursor
+ cairo_surface_t *surface_copy; // Copy of original surface
+ cairo_surface_t *surface_rotated; // Copy of original surface, rotated
+};
+
+void sp_canvas_rotate_start( SPCanvasRotate *canvas_rotate, cairo_surface_t *background );
+
+GType sp_canvas_rotate_get_type (void);
+
+struct SPCanvasRotateClass : public SPCanvasItemClass{};
+
+#endif // SEEN_SP_CANVAS_ROTATE_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/display/canvas-temporary-item-list.h b/src/display/canvas-temporary-item-list.h
index 6b0e5796b..471bb99b9 100644
--- a/src/display/canvas-temporary-item-list.h
+++ b/src/display/canvas-temporary-item-list.h
@@ -14,7 +14,6 @@
struct SPCanvasItem;
class SPDesktop;
-class SPViewBox;
namespace Inkscape {
namespace Display {
diff --git a/src/display/gnome-canvas-acetate.cpp b/src/display/gnome-canvas-acetate.cpp
index 9147a1bbf..297d69068 100644
--- a/src/display/gnome-canvas-acetate.cpp
+++ b/src/display/gnome-canvas-acetate.cpp
@@ -14,11 +14,13 @@
*/
#include "gnome-canvas-acetate.h"
+#include "ui/event-debug.h"
static void sp_canvas_acetate_destroy(SPCanvasItem *object);
static void sp_canvas_acetate_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags);
static double sp_canvas_acetate_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item);
+static int sp_canvas_acetate_event( SPCanvasItem *item, GdkEvent *event);
G_DEFINE_TYPE(SPCanvasAcetate, sp_canvas_acetate, SP_TYPE_CANVAS_ITEM);
@@ -29,6 +31,7 @@ static void sp_canvas_acetate_class_init (SPCanvasAcetateClass *klass)
item_class->destroy = sp_canvas_acetate_destroy;
item_class->update = sp_canvas_acetate_update;
item_class->point = sp_canvas_acetate_point;
+ // item_class->event = sp_canvas_acetate_event;
}
static void sp_canvas_acetate_init (SPCanvasAcetate */*acetate*/)
@@ -60,3 +63,8 @@ static double sp_canvas_acetate_point( SPCanvasItem *item, Geom::Point /*p*/, SP
return 0.0;
}
+// static int sp_canvas_acetate_event( SPCanvasItem *item, GdkEvent *event)
+// {
+// ui_dump_event (event, "sp_canvas_acetate_event");
+// return 0; // ?
+// }
diff --git a/src/display/sodipodi-ctrlrect.cpp b/src/display/sodipodi-ctrlrect.cpp
index ecc952c48..075e04e6d 100644
--- a/src/display/sodipodi-ctrlrect.cpp
+++ b/src/display/sodipodi-ctrlrect.cpp
@@ -6,9 +6,11 @@
* bulia byak <buliabyak@users.sf.net>
* Carl Hetherington <inkscape@carlh.net>
* Jon A. Cruz <jon@joncruz.org>
+ * Tavmjong Bah <tavmjong@free.fr>
*
* Copyright (C) 1999-2001 Lauris Kaplinski
* Copyright (C) 2000-2001 Ximian, Inc.
+ * Copyright (C) 2017 Tavmjong Bah
*
* Released under GNU GPL
*
@@ -18,6 +20,7 @@
#include "sp-canvas-util.h"
#include "display/cairo-utils.h"
#include "display/sp-canvas.h"
+#include <2geom/transforms.h>
/*
* Currently we do not have point method, as it should always be painted
@@ -76,14 +79,12 @@ void CtrlRect::init()
_dashed = false;
_checkerboard = false;
- _shadow = 0;
+ _shadow_width = 0;
_area = Geom::OptIntRect();
_rect = Geom::Rect(Geom::Point(0,0),Geom::Point(0,0));
- _shadow_size = 0;
-
_border_color = 0x000000ff;
_fill_color = 0xffffffff;
_shadow_color = 0x000000ff;
@@ -98,52 +99,120 @@ void CtrlRect::render(SPCanvasBuf *buf)
if (!_area) {
return;
}
- Geom::IntRect area = *_area;
- Geom::IntRect area_w_shadow (area[X].min(), area[Y].min(),
- area[X].max() + _shadow_size, area[Y].max() + _shadow_size);
- if ( area_w_shadow.intersects(buf->rect) )
+
+ Geom::IntRect area = *_area; // _area already includes space for shadow.
+ if ( area.intersects(buf->rect) )
{
- static double const dashes[2] = {4.0, 4.0};
+
cairo_save(buf->ct);
cairo_translate(buf->ct, -buf->rect.left(), -buf->rect.top());
- cairo_set_line_width(buf->ct, 1);
- if (_dashed) cairo_set_dash(buf->ct, dashes, 2, 0);
- cairo_rectangle(buf->ct, 0.5 + area[X].min(), 0.5 + area[Y].min(),
- area[X].max() - area[X].min(), area[Y].max() - area[Y].min());
+
+ // Get canvas rotation (scale is isotropic).
+ double rotation = atan2( _affine[1], _affine[0] );
+
+ // Are we axis aligned?
+ double mod_rot = fmod(rotation * M_2_PI, 1);
+ bool axis_aligned = Geom::are_near( mod_rot, 0 ) || Geom::are_near( mod_rot, 1.0 );
+
+ // Get the points we need transformed to window coordinates.
+ Geom::Point rect_transformed[4];
+ for (unsigned i = 0; i < 4; ++i) {
+ rect_transformed[i] = _rect.corner(i) * _affine;
+ }
+
+ // Draw shadow first. Shadow extends under rectangle to reduce aliasing effects.
+ if (_shadow_width > 0 && !_dashed) {
+
+ // Offset by half stroke width (_shadow_width is in window coordinates).
+ // Need to handle change in handedness with flips.
+ Geom::Point shadow( _shadow_width/2.0, (_affine.det()>0?-1:1)*_shadow_width/2.0 );
+ shadow *= Geom::Rotate( rotation );
+
+ if (axis_aligned) {
+ // Snap to pixel grid (add 0.5 to center on pixel).
+ cairo_move_to( buf->ct,
+ floor(rect_transformed[0][X]+shadow[X]+0.5) + 0.5,
+ floor(rect_transformed[0][Y]+shadow[Y]+0.5) + 0.5 );
+ cairo_line_to( buf->ct,
+ floor(rect_transformed[1][X]+shadow[X]+0.5) + 0.5,
+ floor(rect_transformed[1][Y]+shadow[Y]+0.5) + 0.5 );
+ cairo_line_to( buf->ct,
+ floor(rect_transformed[2][X]+shadow[X]+0.5) + 0.5,
+ floor(rect_transformed[2][Y]+shadow[Y]+0.5) + 0.5 );
+ } else {
+ cairo_move_to( buf->ct,
+ rect_transformed[0][X]+shadow[X],
+ rect_transformed[0][Y]+shadow[Y] );
+ cairo_line_to( buf->ct,
+ rect_transformed[1][X]+shadow[X],
+ rect_transformed[1][Y]+shadow[Y] );
+ cairo_line_to( buf->ct,
+ rect_transformed[2][X]+shadow[X],
+ rect_transformed[2][Y]+shadow[Y] );
+ }
+
+ ink_cairo_set_source_rgba32( buf->ct, _shadow_color );
+ cairo_set_line_width( buf->ct, _shadow_width + 1 );
+ cairo_stroke( buf->ct );
+ }
+
+ // Setup rectangle path
+ if (axis_aligned) {
+
+ // Snap to pixel grid
+ Geom::Rect outline( _rect.min() * _affine, _rect.max() * _affine);
+ // Check if there is a simpler way to go from 'outline' to 'int_rect'.
+ Geom::IntRect int_rect ( (int) floor(outline.min()[X] + 0.5),
+ (int) floor(outline.min()[Y] + 0.5),
+ (int) floor(outline.max()[X] + 0.5),
+ (int) floor(outline.max()[Y] + 0.5) );
+ cairo_rectangle (buf->ct,
+ 0.5 + int_rect[X].min(),
+ 0.5 + int_rect[Y].min(),
+ int_rect[X].max() - int_rect[X].min(),
+ int_rect[Y].max() - int_rect[Y].min() );
+ } else {
+
+ // Angled
+ cairo_move_to( buf->ct, rect_transformed[0][X], rect_transformed[0][Y] );
+ cairo_line_to( buf->ct, rect_transformed[1][X], rect_transformed[1][Y] );
+ cairo_line_to( buf->ct, rect_transformed[2][X], rect_transformed[2][Y] );
+ cairo_line_to( buf->ct, rect_transformed[3][X], rect_transformed[3][Y] );
+ cairo_close_path( buf->ct );
+ }
+
+ // This doesn't seem to be used anywhere. If it is, then we should
+ // probably rotate the coordinate system and fill using a cairo_rectangle().
if (_checkerboard) {
cairo_pattern_t *cb = ink_cairo_pattern_create_checkerboard();
cairo_set_source(buf->ct, cb);
cairo_pattern_destroy(cb);
cairo_fill_preserve(buf->ct);
}
+
if (_has_fill) {
ink_cairo_set_source_rgba32(buf->ct, _fill_color);
cairo_fill_preserve(buf->ct);
}
+ // Set up stroke.
ink_cairo_set_source_rgba32(buf->ct, _border_color);
- cairo_stroke(buf->ct);
+ cairo_set_line_width(buf->ct, 1);
+ static double const dashes[2] = {4.0, 4.0};
+ if (_dashed) cairo_set_dash(buf->ct, dashes, 2, 0);
- if (_shadow_size == 1) { // highlight the border by drawing it in _shadow_color
- if (_dashed) {
- cairo_set_dash(buf->ct, dashes, 2, 4);
- cairo_rectangle(buf->ct, 0.5 + area[X].min(), 0.5 + area[Y].min(),
- area[X].max() - area[X].min(), area[Y].max() - area[Y].min());
- } else {
- cairo_rectangle(buf->ct, -0.5 + area[X].min(), -0.5 + area[Y].min(),
- area[X].max() - area[X].min(), area[Y].max() - area[Y].min());
- }
- ink_cairo_set_source_rgba32(buf->ct, _shadow_color);
- cairo_stroke(buf->ct);
- } else if (_shadow_size > 1) { // fill the shadow
+ // Stroke rectangle.
+ cairo_stroke_preserve(buf->ct);
+
+ // Highlight the border by drawing it in _shadow_color.
+ if (_shadow_width == 1 && _dashed) {
ink_cairo_set_source_rgba32(buf->ct, _shadow_color);
- cairo_rectangle(buf->ct, 1 + area[X].max(), area[Y].min() + _shadow_size,
- _shadow_size, area[Y].max() - area[Y].min() + 1); // right shadow
- cairo_rectangle(buf->ct, area[X].min() + _shadow_size, 1 + area[Y].max(),
- area[X].max() - area[X].min() - _shadow_size + 1, _shadow_size);
- cairo_fill(buf->ct);
+ cairo_set_dash(buf->ct, dashes, 2, 4); // Dash offset by dash length.
+ cairo_stroke_preserve(buf->ct);
}
+
+ cairo_new_path( buf->ct ); // Clear path or get wierd artifacts.
cairo_restore(buf->ct);
}
}
@@ -158,124 +227,33 @@ void CtrlRect::update(Geom::Affine const &affine, unsigned int flags)
(SP_CANVAS_ITEM_CLASS(sp_ctrlrect_parent_class))->update(this, affine, flags);
}
- sp_canvas_item_reset_bounds(this);
+ // Note: There is no harm if 'area' is too large other than a possible small slow down in
+ // rendering speed.
- Geom::Rect bbox(_rect.min() * affine, _rect.max() * affine);
+ // Calculate an axis-aligned bounding box that include all of transformed _rect.
+ Geom::Rect bbox = _rect;
+ bbox *= affine;
- Geom::OptIntRect _area_old = _area;
- Geom::IntRect area ( (int) floor(bbox.min()[Geom::X] + 0.5),
- (int) floor(bbox.min()[Geom::Y] + 0.5),
- (int) floor(bbox.max()[Geom::X] + 0.5),
- (int) floor(bbox.max()[Geom::Y] + 0.5) );
- _area = area;
- Geom::IntRect area_old(0,0,0,0);
- if (_area_old) { // this weird construction is because the code below assumes _area_old to be 'valid'
- area_old = *_area_old;
- }
+ // Enlarge bbox by twice shadow size (to allow for shadow on any side with a 45deg rotation).
+ bbox.expandBy( 2.0 *_shadow_width );
- gint _shadow_size_old = _shadow_size;
- _shadow_size = _shadow;
-
- // FIXME: we don't process a possible change in _has_fill
- if (_has_fill) {
- if (_area_old) {
- canvas->requestRedraw(area_old[X].min() - 1, area_old[Y].min() - 1,
- area_old[X].max() + _shadow_size + 1, area_old[Y].max() + _shadow_size + 1);
- }
- if (_area) {
- canvas->requestRedraw(area[X].min() - 1, area[Y].min() - 1,
- area[X].max() + _shadow_size + 1, area[Y].max() + _shadow_size + 1);
- }
- } else { // clear box, be smart about what part of the frame to redraw
-
- /* Top */
- if (area[Y].min() != area_old[Y].min()) { // different level, redraw fully old and new
- if (area_old[X].min() != area_old[X].max())
- canvas->requestRedraw(area_old[X].min() - 1, area_old[Y].min() - 1,
- area_old[X].max() + 1, area_old[Y].min() + 1);
-
- if (area[X].min() != area[X].max())
- canvas->requestRedraw(area[X].min() - 1, area[Y].min() - 1,
- area[X].max() + 1, area[Y].min() + 1);
- } else { // same level, redraw only the ends
- if (area[X].min() != area_old[X].min()) {
- canvas->requestRedraw(MIN(area_old[X].min(),area[X].min()) - 1, area[Y].min() - 1,
- MAX(area_old[X].min(),area[X].min()) + 1, area[Y].min() + 1);
- }
- if (area[X].max() != area_old[X].max()) {
- canvas->requestRedraw(MIN(area_old[X].max(),area[X].max()) - 1, area[Y].min() - 1,
- MAX(area_old[X].max(),area[X].max()) + 1, area[Y].min() + 1);
- }
- }
-
- /* Left */
- if (area[X].min() != area_old[X].min()) { // different level, redraw fully old and new
- if (area_old[Y].min() != area_old[Y].max())
- canvas->requestRedraw(area_old[X].min() - 1, area_old[Y].min() - 1,
- area_old[X].min() + 1, area_old[Y].max() + 1);
-
- if (area[Y].min() != area[Y].max())
- canvas->requestRedraw(area[X].min() - 1, area[Y].min() - 1,
- area[X].min() + 1, area[Y].max() + 1);
- } else { // same level, redraw only the ends
- if (area[Y].min() != area_old[Y].min()) {
- canvas->requestRedraw(area[X].min() - 1, MIN(area_old[Y].min(),area[Y].min()) - 1,
- area[X].min() + 1, MAX(area_old[Y].min(),area[Y].min()) + 1);
- }
- if (area[Y].max() != area_old[Y].max()) {
- canvas->requestRedraw(area[X].min() - 1, MIN(area_old[Y].max(),area[Y].max()) - 1,
- area[X].min() + 1, MAX(area_old[Y].max(),area[Y].max()) + 1);
- }
- }
-
- /* Right */
- if (area[X].max() != area_old[X].max() || _shadow_size_old != _shadow_size) {
- if (area_old[Y].min() != area_old[Y].max())
- canvas->requestRedraw(area_old[X].max() - 1, area_old[Y].min() - 1,
- area_old[X].max() + _shadow_size + 1, area_old[Y].max() + _shadow_size + 1);
-
- if (area[Y].min() != area[Y].max())
- canvas->requestRedraw(area[X].max() - 1, area[Y].min() - 1,
- area[X].max() + _shadow_size + 1, area[Y].max() + _shadow_size + 1);
- } else { // same level, redraw only the ends
- if (area[Y].min() != area_old[Y].min()) {
- canvas->requestRedraw(area[X].max() - 1, MIN(area_old[Y].min(),area[Y].min()) - 1,
- area[X].max() + _shadow_size + 1, MAX(area_old[Y].min(),area[Y].min()) + _shadow_size + 1);
- }
- if (area[Y].max() != area_old[Y].max()) {
- canvas->requestRedraw(area[X].max() - 1, MIN(area_old[Y].max(),area[Y].max()) - 1,
- area[X].max() + _shadow_size + 1, MAX(area_old[Y].max(),area[Y].max()) + _shadow_size + 1);
- }
- }
+ // Generate an integer rectangle that includes bbox.
+ Geom::OptIntRect _area_old = _area;
+ _area = bbox.roundOutwards();
- /* Bottom */
- if (area[Y].max() != area_old[Y].max() || _shadow_size_old != _shadow_size) {
- if (area_old[X].min() != area_old[X].max())
- canvas->requestRedraw(area_old[X].min() - 1, area_old[Y].max() - 1,
- area_old[X].max() + _shadow_size + 1, area_old[Y].max() + _shadow_size + 1);
-
- if (area[X].min() != area[X].max())
- canvas->requestRedraw(area[X].min() - 1, area[Y].max() - 1,
- area[X].max() + _shadow_size + 1, area[Y].max() + _shadow_size + 1);
- } else { // same level, redraw only the ends
- if (area[X].min() != area_old[X].min()) {
- canvas->requestRedraw(MIN(area_old[X].min(),area[X].min()) - 1, area[Y].max() - 1,
- MAX(area_old[X].min(),area[X].min()) + _shadow_size + 1, area[Y].max() + _shadow_size + 1);
- }
- if (area[X].max() != area_old[X].max()) {
- canvas->requestRedraw(MIN(area_old[X].max(),area[X].max()) - 1, area[Y].max() - 1,
- MAX(area_old[X].max(),area[X].max()) + _shadow_size + 1, area[Y].max() + _shadow_size + 1);
- }
- }
- }
+ // std::cout << " _rect: " << _rect << std::endl;
+ // std::cout << " bbox: " << bbox << std::endl;
+ // std::cout << " area: " << *_area << std::endl;
- // update SPCanvasItem box
if (_area) {
- x1 = area[X].min() - 1;
- y1 = area[Y].min() - 1;
- x2 = area[X].max() + _shadow_size + 1;
- y2 = area[Y].max() + _shadow_size + 1;
+ Geom::IntRect area = *_area;
+ sp_canvas_update_bbox( this, area[X].min(), area[Y].min(), area[X].max(), area[Y].max() );
+ } else {
+ std::cerr << "CtrlRect::update: No area!!" << std::endl;
}
+
+ // At rendering stage, we need to know affine:
+ _affine = affine;
}
@@ -289,7 +267,7 @@ void CtrlRect::setColor(guint32 b, bool h, guint f)
void CtrlRect::setShadow(int s, guint c)
{
- _shadow = s;
+ _shadow_width = s;
_shadow_color = c;
_requestUpdate();
}
diff --git a/src/display/sodipodi-ctrlrect.h b/src/display/sodipodi-ctrlrect.h
index 08a085649..02fc85647 100644
--- a/src/display/sodipodi-ctrlrect.h
+++ b/src/display/sodipodi-ctrlrect.h
@@ -4,14 +4,17 @@
/**
* @file
* Simple non-transformed rectangle, usable for rubberband.
+ * Modified to work with rotated canvas.
*/
/*
* Authors:
* Lauris Kaplinski <lauris@ximian.com>
* Carl Hetherington <inkscape@carlh.net>
+ * Tavmjong Bah <tavjong@free.fr>
*
* Copyright (C) 1999-2001 Lauris Kaplinski
* Copyright (C) 2000-2001 Ximian, Inc.
+ * Copyright (C) 2017 Tavmjong Bah
*
* Released under GNU GPL
*
@@ -21,6 +24,7 @@
#include "sp-canvas-item.h"
#include <2geom/rect.h>
#include <2geom/int-rect.h>
+#include <2geom/transforms.h>
struct SPCanvasBuf;
@@ -48,23 +52,24 @@ private:
void _requestUpdate();
Geom::Rect _rect;
+ Geom::Affine _affine;
+
bool _has_fill;
bool _dashed;
bool _checkerboard;
Geom::OptIntRect _area;
- gint _shadow_size;
+ gint _shadow_width;
guint32 _border_color;
guint32 _fill_color;
guint32 _shadow_color;
- int _shadow;
};
struct CtrlRectClass : public SPCanvasItemClass {};
GType sp_ctrlrect_get_type();
-#endif // SEEN_RUBBERBAND_H
+#endif // SEEN_CTRLRECT_H
/*
Local Variables:
diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp
index 61602e880..d04c81ecb 100644
--- a/src/display/sp-canvas.cpp
+++ b/src/display/sp-canvas.cpp
@@ -33,11 +33,6 @@
#include "display/sp-canvas-group.h"
#include "display/rendermode.h"
#include "display/cairo-utils.h"
-#include "display/cairo-templates.h"
-#include "display/drawing-context.h"
-#include "display/drawing-item.h"
-#include "display/nr-filter-colormatrix.h"
-#include "display/canvas-arena.h"
#include "preferences.h"
#include "inkscape.h"
#include "sodipodi-ctrlrect.h"
@@ -45,8 +40,6 @@
#include "debug/gdk-event-latency-tracker.h"
#include "desktop.h"
#include "color.h"
-#include <iomanip>
-#include <glibmm/i18n.h>
#if GTK_CHECK_VERSION(3,20,0)
# include <gdkmm/seat.h>
@@ -1514,7 +1507,7 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect
buf.buf = NULL;
buf.buf_rowstride = 0;
buf.rect = paint_rect;
- buf.visible_rect = canvas_rect;
+ buf.canvas_rect = canvas_rect;
buf.is_empty = true;
// create temporary surface
@@ -1578,7 +1571,7 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect
}
struct PaintRectSetup {
- Geom::IntRect big_rect;
+ Geom::IntRect canvas_rect;
GTimeVal start_time;
int max_pixels;
Geom::Point mouse_loc;
@@ -1637,7 +1630,7 @@ int SPCanvas::paintRectInternal(PaintRectSetup const *setup, Geom::IntRect const
gdk_window_begin_paint_rect(window, &r);
*/
- paintSingleBuffer(this_rect, setup->big_rect, bw);
+ paintSingleBuffer(this_rect, setup->canvas_rect, bw);
//gdk_window_end_paint(window);
return 1;
}
@@ -1702,6 +1695,7 @@ bool SPCanvas::paintRect(int xx0, int yy0, int xx1, int yy1)
gtk_widget_get_allocation(GTK_WIDGET(this), &allocation);
+ // Find window rectangle in 'world coordinates'.
Geom::IntRect canvas_rect = Geom::IntRect::from_xywh(_x0, _y0,
allocation.width, allocation.height);
Geom::IntRect paint_rect(xx0, yy0, xx1, yy1);
@@ -1712,7 +1706,7 @@ bool SPCanvas::paintRect(int xx0, int yy0, int xx1, int yy1)
paint_rect = *area;
PaintRectSetup setup;
- setup.big_rect = paint_rect;
+ setup.canvas_rect = canvas_rect;
// Save the mouse location
gint x, y;
@@ -1733,10 +1727,16 @@ bool SPCanvas::paintRect(int xx0, int yy0, int xx1, int yy1)
setup.mouse_loc = sp_canvas_window_to_world(this, Geom::Point(x,y));
+ static unsigned tile_multiplier = 0;
+ if (tile_multiplier == 0) {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ tile_multiplier = prefs->getIntLimited("/options/rendering/tile-multiplier", 1, 1, 64);
+ }
+
if (_rendermode != Inkscape::RENDERMODE_OUTLINE) {
// use 256K as a compromise to not slow down gradients
// 256K is the cached buffer and we need 4 channels
- setup.max_pixels = 65536; // 256K/4
+ setup.max_pixels = 65536 * tile_multiplier; // 256K/4
} else {
// paths only, so 1M works faster
// 1M is the cached buffer and we need 4 channels
@@ -1924,19 +1924,6 @@ SPCanvasGroup *SPCanvas::getRoot()
return SP_CANVAS_GROUP(_root);
}
-gdouble grayscale_value_matrix[20] = {
- 0.21, 0.72, 0.072, 0, 0,
- 0.21, 0.72, 0.072, 0, 0,
- 0.21, 0.72, 0.072, 0, 0,
- 0 , 0 , 0 , 1, 0
- };
-cairo_surface_t *surface_rotated;
-cairo_surface_t *surface_origin;
-cairo_surface_t *surface_measure;
-double start_angle = 0;
-bool started = false;
-bool rotated = false;
-
/**
* Scroll screen to point 'c'. 'c' is measured in screen pixels.
*/
@@ -1965,14 +1952,10 @@ void SPCanvas::scrollTo( Geom::Point const &c, unsigned int clear, bool is_scrol
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
// Paint the background
cairo_translate(cr, -ix, -iy);
- if (rotated) {
- cairo_translate(cr, dx, dy);
- rotated = false;
- }
cairo_set_source(cr, _background);
cairo_paint(cr);
+
// Copy the old backing store contents
-
cairo_set_source_surface(cr, _backing_store, _x0, _y0);
cairo_rectangle(cr, _x0, _y0, allocation.width, allocation.height);
cairo_clip(cr);
@@ -2009,271 +1992,6 @@ void SPCanvas::scrollTo( Geom::Point const &c, unsigned int clear, bool is_scrol
addIdle();
}
-void SPCanvas::startRotateTo(double angle)
-{
- if (!_backing_store || started) {
- return;
- }
- start_angle = angle;
- started = true;
- GtkAllocation allocation;
- gtk_widget_get_allocation(&_widget, &allocation);
- int half_w = allocation.width/2;
- int half_h = allocation.height/2;
- int half_min = std::min(half_w,half_h);
-
- cairo_surface_t *new_backing_store = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height);
- cairo_t *cr = cairo_create(new_backing_store);
- cairo_arc(cr, half_w, half_h, half_min-15, 0, 2*M_PI);
- cairo_fill(cr);
- cairo_set_operator(cr, CAIRO_OPERATOR_IN);
- cairo_set_source_surface(cr, _backing_store, 0, 0);
- cairo_paint(cr);
- cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
- cairo_arc(cr, half_w, half_h, half_min-16, 0, 2*M_PI);
- cairo_set_source_rgba (cr, 1, 1, 1, 0.5);
- cairo_stroke(cr);
- cairo_destroy(cr);
- surface_rotated = new_backing_store;
-
- cairo_surface_t *new_backing_store_measure = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height);
- cr = cairo_create(new_backing_store_measure);
- cairo_arc(cr, half_w, half_h, half_min-15, 0, 2*M_PI);
- cairo_set_source_rgba (cr, 1, 1, 1, 0.2);
- cairo_fill(cr);
- cairo_translate(cr, half_w, half_h);
- cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
- cairo_set_font_size(cr, 10.0);
- for (gint x = 0; x < 360 ; x++){
- gint ang = 360 - x ;//+ 90;
- if (ang > 180) {
- ang -= 360;
- }
- double rot = (-180.0 + x)*(M_PI/180.);
- double dist = half_min-9;
- gint inverse = 1;
- if((x) < 91 || (x) > 270) {
- inverse = -1;
- }
- if(x%10 == 0) {
- cairo_rotate(cr, -rot);
- cairo_text_extents_t extents;
- std::string s = std::to_string(ang) + "º";
- cairo_text_extents(cr, s.c_str(), &extents);
- //std::cout << extents.width/2 << "extents.x_bearing\n";
- cairo_translate(cr, (extents.width/2) * inverse * -1, (dist + ((extents.height/2)* inverse)));
- if((x) < 91 || (x) > 270) {
- cairo_rotate(cr, 180*(M_PI/180.0));
- }
- cairo_text_path(cr, s.c_str());
- if((x) < 91 || (x) > 270) {
- cairo_rotate(cr, -180*(M_PI/180.0));
- }
- cairo_translate(cr, (extents.width/2) * inverse , (dist + ((extents.height/2)* inverse)) * -1);
- cairo_set_source_rgba (cr, 1, 1, 1, 1);
- cairo_fill(cr);
- cairo_rotate(cr, rot);
- }
- cairo_rotate(cr, x*(M_PI/180.));
- if(x%5 == 0) {
- cairo_move_to(cr, 0, half_min-30);
- cairo_line_to(cr, 0, half_min-17);
- } else {
- cairo_move_to(cr, 0, half_min-20);
- cairo_line_to(cr, 0, half_min-15);
- }
- cairo_line_to(cr, 0, half_min-15);
- cairo_set_source_rgba (cr, 0, 0, 0, 0.4);
- cairo_set_line_width (cr,1);
- cairo_stroke(cr);
- cairo_rotate(cr, -x*(M_PI/180.));
- }
- cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
- cairo_translate(cr, -half_w, -half_h);
- cairo_arc(cr, half_w, half_h, half_min-30, 0, 2*M_PI);
- cairo_set_source_rgba (cr, 1, 1, 1, 1);
- cairo_fill(cr);
- cairo_translate(cr, half_w, half_h);
- cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
- cairo_rotate(cr, start_angle*(M_PI/180.));
- cairo_move_to(cr, 0, 0);
- cairo_line_to(cr, 0, (half_min-17) * -1);
- cairo_set_source_rgba (cr, 1, 1, 1, 0.25);
- cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
- cairo_set_line_width (cr,5);
- cairo_stroke(cr);
- cairo_move_to(cr, 0, 0);
- cairo_line_to(cr, 0, (half_min-17) * -1);
- cairo_set_source_rgba (cr, 1, 0, 0, 0.9);
- cairo_set_line_width (cr,1);
- cairo_stroke(cr);
- cairo_rotate(cr, -start_angle*(M_PI/180.));
- cairo_destroy(cr);
- surface_measure = new_backing_store_measure;
-
- cairo_surface_t *new_backing_store_grey = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height);
- cr = cairo_create(new_backing_store_grey);
- cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
- cairo_set_source_surface(cr, _backing_store, 0, 0);
- cairo_paint(cr);
- Inkscape::Filters::FilterColorMatrix::ColorMatrixMatrix _grayscale_colormatrix = std::vector<gdouble> (grayscale_value_matrix, grayscale_value_matrix + 20);
- cairo_surface_t *out = ink_cairo_surface_create_identical(new_backing_store_grey);
- ink_cairo_surface_filter(new_backing_store_grey, out, _grayscale_colormatrix);
- cairo_set_source_surface(cr, out, 0, 0);
- cairo_surface_destroy(out);
- cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
- cairo_paint(cr);
- cairo_destroy(cr);
- surface_origin = new_backing_store_grey;
-}
-
-bool SPCanvas::endRotateTo()
-{
- if (!_backing_store || !started) {
- return false;
- }
- started = false;
- surface_rotated = NULL;
- surface_origin = NULL;
- gtk_widget_queue_draw(GTK_WIDGET(this));
- dirtyAll();
- addIdle();
- rotated = true;
- return true;
-}
-
-void SPCanvas::clearRotateTo()
-{
- if (!started) {
- return;
- }
- gtk_widget_queue_draw(GTK_WIDGET(this));
- dirtyAll();
- addIdle();
-}
-
-void SPCanvas::rotateTo(double angle)
-{
- if (!_backing_store || !started) {
- return;
- }
- GtkAllocation allocation;
- gtk_widget_get_allocation(&_widget, &allocation);
- int half_w = allocation.width/2;
- int half_h = allocation.height/2;
- int half_min = std::min(half_w,half_h);
- cairo_surface_t *new_backing_store = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height);
- cairo_t *cr = cairo_create(new_backing_store);
- cairo_set_source_surface(cr, surface_origin, 0, 0);
- cairo_paint(cr);
- cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
- cairo_paint(cr);
- cairo_pattern_t *source_pattern;
- cairo_matrix_t matrix;
- source_pattern = cairo_pattern_create_for_surface (surface_rotated);
- cairo_matrix_init_identity (&matrix);
- cairo_matrix_translate (&matrix, allocation.width/2.0, allocation.height/2.0);
- cairo_matrix_rotate (&matrix, Geom::rad_from_deg(angle - start_angle) * -1);
- cairo_matrix_translate (&matrix, -allocation.width/2.0, -allocation.height/2.0);
- cairo_pattern_set_matrix (source_pattern, &matrix);
- cairo_set_source(cr, source_pattern);
- cairo_paint(cr);
- cairo_set_source_surface(cr, surface_measure, 0, 0);
- cairo_paint(cr);
- cairo_translate(cr, half_w, half_h);
- cairo_rotate(cr, angle*(M_PI/180.));
- cairo_move_to(cr, 0, 0);
- cairo_line_to(cr, 0, (half_min-17) * -1);
- cairo_set_source_rgba (cr, 1, 1, 1, 0.25);
- cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
- cairo_set_line_width (cr,5);
- cairo_stroke(cr);
- cairo_move_to(cr, 0, 0);
- cairo_line_to(cr, 0, (half_min-17) * -1);
- cairo_set_source_rgba (cr, 1, 1, 1, 0.9);
- cairo_set_line_width (cr,1);
- cairo_stroke(cr);
- cairo_move_to(cr, 0, 0);
- cairo_line_to(cr, 0, (half_min-17) * -1);
- cairo_set_source_rgba (cr, 1, 0, 0, 0.9);
- const double dashed[] = {6.0, 3.0};
- int len = sizeof(dashed) / sizeof(dashed[0]);
- cairo_set_dash(cr, dashed, len, 1);
- cairo_stroke(cr);
- cairo_translate(cr, -half_w, -half_h);
- cairo_set_source_rgba (cr, 1, 1, 1, 0.25);
- cairo_arc(cr, half_w, half_h, 7, 0, 2*M_PI);
- cairo_fill(cr);
- cairo_set_source_rgba (cr, 1, 0, 0, 0.7);
- cairo_arc(cr, half_w, half_h, 5, 0, 2*M_PI);
- cairo_fill(cr);
- cairo_translate(cr, half_w, half_h);
- cairo_rotate(cr, -angle*(M_PI/180.));
- cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
- cairo_set_font_size(cr, 15.0);
- cairo_text_extents_t extents;
- std::ostringstream s;
- s << _("Original angle ") << std::fixed << std::setprecision(2) << start_angle << "º";
- cairo_text_extents(cr, s.str().c_str(), &extents);
- cairo_translate(cr, half_w - extents.width -15 ,-half_h + 25);
- cairo_set_source_rgba (cr, 1, 1, 1, 1);
- cairo_text_path(cr, s.str().c_str());
- cairo_fill(cr);
- cairo_translate(cr, (half_w - extents.width -15) *-1 ,(-half_h + 25) *-1);
- s.str("");
- s << _("New angle ") << std::fixed << std::setprecision(2) << angle << "º";
- cairo_text_extents(cr, s.str().c_str(), &extents);
- cairo_translate(cr, half_w - extents.width -15 ,-half_h + 45);
- cairo_text_path(cr, s.str().c_str());
- cairo_fill(cr);
- cairo_translate(cr, (half_w - extents.width -15) *-1 ,(-half_h + 45) *-1);
- s.str("");
- s << _("Gap ") << std::fixed << std::setprecision(2) << std::abs(start_angle-angle) << "º";
- cairo_text_extents(cr, s.str().c_str(), &extents);
- cairo_translate(cr, half_w - extents.width -15 ,-half_h + 65);
- cairo_text_path(cr, s.str().c_str());
- cairo_fill(cr);
- cairo_translate(cr, (half_w - extents.width -15) *-1 ,(-half_h + 65) *-1);
- cairo_translate(cr, -half_w + 10 ,-half_h + 25);
- s.str("");
- cairo_set_font_size(cr, 12.0);
- s << _("Normal mode, 1º round step");
- cairo_text_path(cr, s.str().c_str());
- cairo_fill(cr);
- cairo_translate(cr, (-half_w +10) * -1 ,(-half_h + 25) * -1);
- cairo_translate(cr, -half_w + 10 ,-half_h + 40);
- s.str("");
- s << _("+ALT, Fractional degrees");
- cairo_text_path(cr, s.str().c_str());
- cairo_fill(cr);
- cairo_translate(cr, (-half_w + 10) * -1 ,(-half_h + 40) * -1);
- cairo_translate(cr, -half_w + 10 ,-half_h + 55);
- s.str("");
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- s << _("+CTRL, ") << 180.0/prefs->getInt("/options/rotationsnapsperpi/value", 12) << _("º round step");
- cairo_text_path(cr, s.str().c_str());
- cairo_fill(cr);
- cairo_translate(cr, (-half_w + 10) * -1 ,(-half_h + 55) * -1);
- cairo_translate(cr, -half_w + 10 ,-half_h + 70);
- s.str("");
- s << _("+SHIFT, Reset");
- cairo_text_path(cr, s.str().c_str());
- cairo_fill(cr);
- cairo_translate(cr, (-half_w + 10) * -1 ,(-half_h + 70) * -1);
- cairo_translate(cr, -half_w + 10 ,-half_h + 85);
- s.str("");
- s << _("+CTRL+SHIFT, 0º");
- cairo_text_path(cr, s.str().c_str());
- cairo_fill(cr);
- //cairo_translate(cr, (-half_w + 10) * -1 ,(-half_h + 60) * -1);
- cairo_destroy(cr);
- cairo_surface_destroy(_backing_store);
- _backing_store = new_backing_store;
- cairo_pattern_destroy (source_pattern);
- gtk_widget_queue_draw(GTK_WIDGET(this));
- addIdle();
-}
-
void SPCanvas::updateNow()
{
if (_need_update) {
diff --git a/src/display/sp-canvas.h b/src/display/sp-canvas.h
index 708653bdf..a2cbe0b27 100644
--- a/src/display/sp-canvas.h
+++ b/src/display/sp-canvas.h
@@ -51,7 +51,7 @@ enum {
struct SPCanvasBuf {
cairo_t *ct;
Geom::IntRect rect;
- Geom::IntRect visible_rect;
+ Geom::IntRect canvas_rect; // visible window in world coordinates (i.e. offset by _x0, _y0)
unsigned char *buf;
int buf_rowstride;
@@ -72,10 +72,7 @@ GType sp_canvas_get_type() G_GNUC_CONST;
struct SPCanvas {
/// Scrolls canvas to specific position (c is measured in screen pixels).
void scrollTo(Geom::Point const &c, unsigned int clear, bool is_scrolling = false);
- void startRotateTo(double angle);
- void rotateTo(double angle);
- bool endRotateTo();
- void clearRotateTo();
+
/// Synchronously updates the canvas if necessary.
void updateNow();
@@ -177,8 +174,8 @@ public:
bool _is_dragging;
double _dx0;
double _dy0;
- int _x0; ///< World coordinate of the leftmost pixels
- int _y0; ///< World coordinate of the topmost pixels
+ int _x0; ///< World coordinate of the leftmost pixels of window
+ int _y0; ///< World coordinate of the topmost pixels of window
/// Image surface storing the contents of the widget
cairo_surface_t *_backing_store;