summaryrefslogtreecommitdiffstats
path: root/src/display/control/canvas-item-quad.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/display/control/canvas-item-quad.cpp')
-rw-r--r--src/display/control/canvas-item-quad.cpp207
1 files changed, 207 insertions, 0 deletions
diff --git a/src/display/control/canvas-item-quad.cpp b/src/display/control/canvas-item-quad.cpp
new file mode 100644
index 0000000..ccc7b2b
--- /dev/null
+++ b/src/display/control/canvas-item-quad.cpp
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/**
+ * A class to represent a control quadrilateral. Used to highlight selected text.
+ */
+
+/*
+ * Author:
+ * Tavmjong Bah
+ *
+ * Copyright (C) 2020 Tavmjong Bah
+ *
+ * Rewrite of SPCtrlQuadr
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "canvas-item-quad.h"
+
+#include "color.h" // SP_RGBA_x_F
+
+#include "ui/widget/canvas.h"
+
+namespace Inkscape {
+
+/**
+ * Create an null control quad.
+ */
+CanvasItemQuad::CanvasItemQuad(CanvasItemGroup *group)
+ : CanvasItem(group)
+{
+ _name = "CanvasItemQuad:Null";
+ _pickable = false; // For now, nobody gets events from this class!
+}
+
+/**
+ * Create a control quad. Point are in document coordinates.
+ */
+CanvasItemQuad::CanvasItemQuad(CanvasItemGroup *group,
+ Geom::Point const &p0, Geom::Point const &p1,
+ Geom::Point const &p2, Geom::Point const &p3)
+ : CanvasItem(group)
+ , _p0(p0)
+ , _p1(p1)
+ , _p2(p2)
+ , _p3(p3)
+{
+ _name = "CanvasItemQuad";
+ _pickable = false; // For now, nobody gets events from this class!
+
+ request_update();
+}
+
+/**
+ * Set a control quad. Points are in document coordinates.
+ */
+void CanvasItemQuad::set_coords(Geom::Point const &p0, Geom::Point const &p1, Geom::Point const &p2, Geom::Point const &p3)
+{
+ std::cout << "Canvas_ItemQuad::set_cords: " << p0 << ", " << p1 << ", " << p2 << ", " << p3 << std::endl;
+ _p0 = p0;
+ _p1 = p1;
+ _p2 = p2;
+ _p3 = p3;
+
+ request_update();
+}
+
+/**
+ * Returns distance between point in canvas units and nearest point on quad.
+ */
+double CanvasItemQuad::closest_distance_to(Geom::Point const &p)
+{
+ double d = Geom::infinity();
+ std::cerr << "CanvasItemQuad::closest_distance_to: Not implemented!" << std::endl;
+ return d;
+}
+
+/**
+ * Returns true if point p (in canvas units) is within tolerance (canvas units) distance of quad.
+ */
+bool CanvasItemQuad::contains(Geom::Point const &p, double tolerance)
+{
+ if (tolerance != 0) {
+ std::cerr << "CanvasItemQuad::contains: Non-zero tolerance not implemented!" << std::endl;
+ }
+
+ Geom::Point p0 = _p0 * _affine;
+ Geom::Point p1 = _p1 * _affine;
+ Geom::Point p2 = _p2 * _affine;
+ Geom::Point p3 = _p3 * _affine;
+
+ // From 2geom rotated-rect.cpp
+ return
+ Geom::cross(p1 - p0, p - p0) >= 0 &&
+ Geom::cross(p2 - p1, p - p1) >= 0 &&
+ Geom::cross(p3 - p2, p - p2) >= 0 &&
+ Geom::cross(p0 - p3, p - p3) >= 0;
+}
+
+/**
+ * Update and redraw control quad.
+ */
+void CanvasItemQuad::update(Geom::Affine const &affine)
+{
+ if (_affine == affine && !_need_update) {
+ // Nothing to do.
+ return;
+ }
+
+ if (_p0 == _p1 ||
+ _p1 == _p2 ||
+ _p2 == _p3 ||
+ _p3 == _p0) {
+ return; // Not quad or not initialized.
+ }
+
+ // Queue redraw of old area (erase previous content).
+ request_redraw(); // This is actually never useful as quads are always deleted
+ // and recreated when a node is moved! But keep it in case we
+ // change that. CHECK
+ // Get new bounds
+ _affine = affine;
+
+ Geom::Rect bounds;
+ bounds.expandTo(_p0);
+ bounds.expandTo(_p1);
+ bounds.expandTo(_p2);
+ bounds.expandTo(_p3);
+ bounds *= _affine; // Document to canvas.
+ bounds.expandBy(2); // Room for anti-aliasing effects.
+ _bounds = bounds;
+
+ // Queue redraw of new area
+ request_redraw();
+
+ _need_update = false;
+}
+
+/**
+ * Render quad to screen via Cairo.
+ */
+void CanvasItemQuad::render(Inkscape::CanvasItemBuffer *buf)
+{
+ if (!buf) {
+ std::cerr << "CanvasItemQuad::Render: No buffer!" << std::endl;
+ return;
+ }
+
+ if (_p0 == _p1 ||
+ _p1 == _p2 ||
+ _p2 == _p3 ||
+ _p3 == _p0) {
+ return; // Not quad or not initialized.
+ }
+
+ if (!_visible) {
+ // Hidden
+ return;
+ }
+
+ // Document to canvas
+ Geom::Point p0 = _p0 * _affine;
+ Geom::Point p1 = _p1 * _affine;
+ Geom::Point p2 = _p2 * _affine;
+ Geom::Point p3 = _p3 * _affine;
+
+ // Canvas to screen
+ p0 *= Geom::Translate(-buf->rect.min());
+ p1 *= Geom::Translate(-buf->rect.min());
+ p2 *= Geom::Translate(-buf->rect.min());
+ p3 *= Geom::Translate(-buf->rect.min());
+
+ buf->cr->save();
+
+ buf->cr->begin_new_path();
+
+ buf->cr->move_to(p0.x(), p0.y());
+ buf->cr->line_to(p1.x(), p1.y());
+ buf->cr->line_to(p2.x(), p2.y());
+ buf->cr->line_to(p3.x(), p3.y());
+ buf->cr->close_path();
+ buf->cr->set_source_rgba(SP_RGBA32_R_F(_fill), SP_RGBA32_G_F(_fill),
+ SP_RGBA32_B_F(_fill), SP_RGBA32_A_F(_fill));
+ buf->cr->fill();
+
+ // Uncomment to show bounds
+ // Geom::Rect bounds = _bounds;
+ // bounds.expandBy(-1);
+ // bounds -= buf->rect.min();
+ // buf->cr->set_source_rgba(1.0, 0.0, 0.0, 1.0);
+ // buf->cr->rectangle(bounds.min().x(), bounds.min().y(), bounds.width(), bounds.height());
+ // buf->cr->stroke();
+
+ buf->cr->restore();
+}
+
+} // 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 :