summaryrefslogtreecommitdiffstats
path: root/src/display/control/canvas-item-drawing.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/display/control/canvas-item-drawing.cpp')
-rw-r--r--src/display/control/canvas-item-drawing.cpp220
1 files changed, 220 insertions, 0 deletions
diff --git a/src/display/control/canvas-item-drawing.cpp b/src/display/control/canvas-item-drawing.cpp
new file mode 100644
index 0000000..cfa527a
--- /dev/null
+++ b/src/display/control/canvas-item-drawing.cpp
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/**
+ * A class to render the SVG drawing.
+ */
+
+/*
+ * Author:
+ * Tavmjong Bah
+ *
+ * Copyright (C) 2020 Tavmjong Bah
+ *
+ * Rewrite of _SPCanvasArena.
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "canvas-item-drawing.h"
+
+#include "desktop.h"
+
+#include "display/drawing.h"
+#include "display/drawing-context.h"
+#include "display/drawing-item.h"
+#include "display/drawing-group.h"
+
+#include "helper/geom.h"
+#include "ui/widget/canvas.h"
+#include "ui/modifiers.h"
+
+namespace Inkscape {
+
+/**
+ * Create the drawing. One per window!
+ */
+CanvasItemDrawing::CanvasItemDrawing(CanvasItemGroup *group)
+ : CanvasItem(group)
+{
+ _name = "CanvasItemDrawing";
+ _pickable = true;
+
+ _drawing = std::make_unique<Drawing>(this);
+ auto root = new DrawingGroup(*_drawing);
+ root->setPickChildren(true);
+ _drawing->setRoot(root);
+}
+
+/**
+ * Returns true if point p (in canvas units) is inside some object in drawing.
+ */
+bool CanvasItemDrawing::contains(Geom::Point const &p, double tolerance)
+{
+ if (tolerance != 0) {
+ std::cerr << "CanvasItemDrawing::contains: Non-zero tolerance not implemented!" << std::endl;
+ }
+
+ _picked_item = _drawing->pick(p, _drawing->cursorTolerance(), _sticky * DrawingItem::PICK_STICKY | _pick_outline * DrawingItem::PICK_OUTLINE);
+
+ if (_picked_item) {
+ // This will trigger a signal that is handled by our event handler. Seems a bit of a
+ // round-about way of doing things but it matches what other pickable canvas-item classes do.
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Update and redraw drawing.
+ */
+void CanvasItemDrawing::_update(bool)
+{
+ // Undo y-axis flip. This should not be here!!!!
+ auto new_drawing_affine = affine();
+ if (auto desktop = get_canvas()->get_desktop()) {
+ new_drawing_affine = desktop->doc2dt() * new_drawing_affine;
+ }
+
+ bool affine_changed = _drawing_affine != new_drawing_affine;
+ if (affine_changed) {
+ _drawing_affine = new_drawing_affine;
+ }
+
+ _drawing->update(Geom::IntRect::infinite(), _drawing_affine, DrawingItem::STATE_ALL, affine_changed * DrawingItem::STATE_ALL);
+
+ _bounds = expandedBy(_drawing->root()->drawbox(), 1); // Avoid aliasing artifacts
+
+ // Todo: This should be managed elsewhere.
+ if (_cursor) {
+ /* Mess with enter/leave notifiers */
+ DrawingItem *new_drawing_item = _drawing->pick(_c, _delta, _sticky * DrawingItem::PICK_STICKY | _pick_outline * DrawingItem::PICK_OUTLINE);
+ if (_active_item != new_drawing_item) {
+
+ GdkEventCrossing ec;
+ ec.window = get_canvas()->get_window()->gobj();
+ ec.send_event = true;
+ ec.subwindow = ec.window;
+ ec.time = GDK_CURRENT_TIME;
+ ec.x = _c.x();
+ ec.y = _c.y();
+
+ /* fixme: Why? */
+ if (_active_item) {
+ ec.type = GDK_LEAVE_NOTIFY;
+ _drawing_event_signal.emit((GdkEvent *) &ec, _active_item);
+ }
+
+ _active_item = new_drawing_item;
+
+ if (_active_item) {
+ ec.type = GDK_ENTER_NOTIFY;
+ _drawing_event_signal.emit((GdkEvent *) &ec, _active_item);
+ }
+ }
+ }
+}
+
+/**
+ * Render drawing to screen via Cairo.
+ */
+void CanvasItemDrawing::_render(Inkscape::CanvasItemBuffer &buf) const
+{
+ auto dc = Inkscape::DrawingContext(buf.cr->cobj(), buf.rect.min());
+ _drawing->render(dc, buf.rect, buf.outline_pass * DrawingItem::RENDER_OUTLINE);
+}
+
+/**
+ * Handle events directed at the drawing. We first attempt to handle them here.
+ */
+bool CanvasItemDrawing::handle_event(GdkEvent *event)
+{
+ bool retval = false;
+
+ switch (event->type) {
+ case GDK_ENTER_NOTIFY:
+ if (!_cursor) {
+ if (_active_item) {
+ std::cerr << "CanvasItemDrawing::event_handler: cursor entered drawing with an active item!" << std::endl;
+ }
+ _cursor = true;
+
+ /* TODO ... event -> arena transform? */
+ _c = Geom::Point(event->crossing.x, event->crossing.y);
+
+ _active_item = _drawing->pick(_c, _drawing->cursorTolerance(), _sticky * DrawingItem::PICK_STICKY | _pick_outline * DrawingItem::PICK_OUTLINE);
+ retval = _drawing_event_signal.emit(event, _active_item);
+ }
+ break;
+
+ case GDK_LEAVE_NOTIFY:
+ if (_cursor) {
+ retval = _drawing_event_signal.emit(event, _active_item);
+ _active_item = nullptr;
+ _cursor = false;
+ }
+ break;
+
+ case GDK_MOTION_NOTIFY:
+ {
+ /* TODO ... event -> arena transform? */
+ _c = Geom::Point(event->motion.x, event->motion.y);
+
+ auto new_drawing_item = _drawing->pick(_c, _drawing->cursorTolerance(), _sticky * DrawingItem::PICK_STICKY | _pick_outline * DrawingItem::PICK_OUTLINE);
+ if (_active_item != new_drawing_item) {
+
+ GdkEventCrossing ec;
+ ec.window = event->motion.window;
+ ec.send_event = event->motion.send_event;
+ ec.subwindow = event->motion.window;
+ ec.time = event->motion.time;
+ ec.x = event->motion.x;
+ ec.y = event->motion.y;
+
+ /* fixme: What is wrong? */
+ if (_active_item) {
+ ec.type = GDK_LEAVE_NOTIFY;
+ retval = _drawing_event_signal.emit((GdkEvent *) &ec, _active_item);
+ }
+
+ _active_item = new_drawing_item;
+
+ if (_active_item) {
+ ec.type = GDK_ENTER_NOTIFY;
+ retval = _drawing_event_signal.emit((GdkEvent *) &ec, _active_item);
+ }
+ }
+ retval = retval || _drawing_event_signal.emit(event, _active_item);
+ break;
+ }
+
+ case GDK_SCROLL:
+ {
+ if (Modifiers::Modifier::get(Modifiers::Type::CANVAS_ZOOM)->active(event->scroll.state)) {
+ /* Zoom is emitted by the canvas as well, ignore here */
+ return false;
+ }
+ retval = _drawing_event_signal.emit(event, _active_item);
+ break;
+ }
+
+ default:
+ /* Just send event */
+ retval = _drawing_event_signal.emit(event, _active_item);
+ break;
+ }
+
+ return retval;
+}
+
+} // namespace Inkscape
+
+/*
+ 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 :