From 35a96bde514a8897f6f0fcc41c5833bf63df2e2a Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 18:29:01 +0200 Subject: Adding upstream version 1.0.2. Signed-off-by: Daniel Baumann --- src/display/canvas-rotate.cpp | 291 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 src/display/canvas-rotate.cpp (limited to 'src/display/canvas-rotate.cpp') diff --git a/src/display/canvas-rotate.cpp b/src/display/canvas-rotate.cpp new file mode 100644 index 0000000..0a5fcb5 --- /dev/null +++ b/src/display/canvas-rotate.cpp @@ -0,0 +1,291 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Temporary surface for previewing rotated canvas. + * + * Author: + * Tavmjong Bah + * + * Copyright (C) 2017 Tavmjong Bah + * + * Released under GNU GPL v2+, 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 + +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 = nullptr; + rotate->surface_rotated = nullptr; +} + +namespace { +static void sp_canvas_rotate_destroy (SPCanvasItem *object) +{ + g_return_if_fail (object != nullptr); + 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 == nullptr) { + // std::cout << "sp_canvas_rotate_update: surface_copy is NULL" << std::endl; + return; + } + + // Destroy surface_rotated if it already exists. + if (cr->surface_rotated != nullptr) { + cairo_surface_destroy (cr->surface_rotated); + cr->surface_rotated = nullptr; + } + + // 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); + auto ct = buf->ct; + + if (!ct) { + return; + } + + if (cr->surface_rotated == nullptr ) { + // std::cout << " surface_rotated is NULL" << std::endl; + return; + } + + // Draw rotated canvas + cairo_save (ct); + cairo_translate (ct, + buf->canvas_rect.left() - buf->rect.left(), + buf->canvas_rect.top() - buf->rect.top() ); + cairo_set_operator (ct, CAIRO_OPERATOR_SOURCE ); + cairo_set_source_surface (ct, cr->surface_rotated, 0, 0 ); + cairo_paint (ct); + cairo_restore (ct); + + + // Draw line from center to cursor + cairo_save (ct); + cairo_translate (ct, -buf->rect.left(), -buf->rect.top()); + cairo_new_path (ct); + cairo_move_to (ct, cr->center[Geom::X], cr->center[Geom::Y]); + cairo_rel_line_to (ct, cr->cursor[Geom::X], cr->cursor[Geom::Y]); + cairo_set_line_width (ct, 2); + ink_cairo_set_source_rgba32 (ct, 0xff00007f); + cairo_stroke (ct); + cairo_restore (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), + (desktop->w2d().det() > 0 ? -1 : 1) * + Geom::rad_from_deg(cr->angle) ); + + // We're done + sp_canvas_item_ungrab (item); + sp_canvas_item_hide (item); + + cr->start_angle = -1000; + if (cr->surface_copy != nullptr) { + cairo_surface_destroy( cr->surface_copy ); + cr->surface_copy = nullptr; + } + if (cr->surface_rotated != nullptr) { + cairo_surface_destroy( cr->surface_rotated ); + cr->surface_rotated = nullptr; + } + // 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 == nullptr) { + 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 == nullptr) { + 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 : -- cgit v1.2.3