diff --git a/src/desktop-events.cpp b/src/desktop-events.cpp index 96a8a612638e75933d65e01c92688153d2aad2cb..e4443e4637cac74ae859e5f97e5d83a546635c5a 100644 --- a/src/desktop-events.cpp +++ b/src/desktop-events.cpp @@ -156,10 +156,9 @@ bool sp_dt_guide_event(GdkEvent *event, Inkscape::CanvasItemGuideLine *guide_ite } if (drag_type == SP_DRAG_ROTATE || drag_type == SP_DRAG_TRANSLATE) { - guide_item->grab((Gdk::BUTTON_RELEASE_MASK | - Gdk::BUTTON_PRESS_MASK | - Gdk::POINTER_MOTION_MASK ), - nullptr); + guide_item->grab(Gdk::BUTTON_RELEASE_MASK | + Gdk::BUTTON_PRESS_MASK | + Gdk::POINTER_MOTION_MASK); } ret = true; } diff --git a/src/desktop.cpp b/src/desktop.cpp index b45625d662d64ba1830b834c375eb70ea32af3eb..f430710dae627e791ca52064ce05de504acc5b4f 100644 --- a/src/desktop.cpp +++ b/src/desktop.cpp @@ -223,14 +223,14 @@ SPDesktop::init (SPNamedView *nv, Inkscape::UI::Widget::Canvas *acanvas, SPDeskt canvas->set_drawing(canvas_drawing->get_drawing()); // Canvas needs access. Inkscape::DrawingItem *drawing_item = document->getRoot()->invoke_show( - *(canvas_drawing->get_drawing()), + *canvas_drawing->get_drawing(), dkey, SP_ITEM_SHOW_DISPLAY); if (drawing_item) { canvas_drawing->get_drawing()->root()->prependChild(drawing_item); } - temporary_item_list = new Inkscape::Display::TemporaryItemList( this ); + temporary_item_list = new Inkscape::Display::TemporaryItemList(); snapindicator = new Inkscape::Display::SnapIndicator ( this ); /* --------- End Canvas Items ----------- */ @@ -295,16 +295,12 @@ void SPDesktop::destroy() if (canvas_drawing) { doc()->getRoot()->invoke_hide(dkey); - delete canvas_drawing; // Why is canvas_drawing special? - canvas_drawing = nullptr; } _guides_message_context = nullptr; } -SPDesktop::~SPDesktop() -= default; - +SPDesktop::~SPDesktop() = default; //-------------------------------------------------------------------- /* Public methods */ @@ -335,6 +331,8 @@ SPDesktop::add_temporary_canvasitem (Inkscape::CanvasItem *item, guint lifetime, /** It is perfectly safe to call this function while the object has already been deleted due to a timeout. */ +// Note: This function may free the wrong temporary item if it is called on a freed pointer that +// has had another TemporaryItem reallocated in its place. void SPDesktop::remove_temporary_canvasitem (Inkscape::Display::TemporaryItem * tempitem) { diff --git a/src/display/CMakeLists.txt b/src/display/CMakeLists.txt index 1a9235f847d092667d49270968ed96fa5cd05a81..479206c9962fd6f873ce2a15a649acc3ef0b6a92 100644 --- a/src/display/CMakeLists.txt +++ b/src/display/CMakeLists.txt @@ -46,6 +46,7 @@ set(display_SRC control/canvas-item.cpp control/canvas-item-bpath.cpp control/canvas-item-catchall.cpp + control/canvas-item-context.cpp control/canvas-item-ctrl.cpp control/canvas-item-curve.cpp control/canvas-item-drawing.cpp @@ -112,6 +113,7 @@ set(display_SRC control/canvas-item-bpath.h control/canvas-item-buffer.h control/canvas-item-catchall.h + control/canvas-item-context.h control/canvas-item-ctrl.h control/canvas-item-curve.h control/canvas-item-drawing.h @@ -119,6 +121,7 @@ set(display_SRC control/canvas-item-grid.h control/canvas-item-group.h control/canvas-item-guideline.h + control/canvas-item-ptr.h control/canvas-item-quad.h control/canvas-item-rect.h control/canvas-item-text.h diff --git a/src/display/control/canvas-item-bpath.cpp b/src/display/control/canvas-item-bpath.cpp index 7367667557fa12e17a777570900eecbcd4e5d98c..acad9855d2cd12db0b541e5794e630bb32dc50a3 100644 --- a/src/display/control/canvas-item-bpath.cpp +++ b/src/display/control/canvas-item-bpath.cpp @@ -16,28 +16,21 @@ #include "canvas-item-bpath.h" -#include // unique_ptr -#include // std::move - #include "color.h" // SP_RGBA_x_F - #include "display/curve.h" #include "display/cairo-utils.h" - -#include "helper/geom.h" // bounds_exact_transformed() - -#include "ui/widget/canvas.h" +#include "helper/geom.h" // bounds_exact_transformed() namespace Inkscape { /** - * Create an null control bpath. + * Create a null control bpath. */ CanvasItemBpath::CanvasItemBpath(CanvasItemGroup *group) : CanvasItem(group) { _name = "CanvasItemBpath:Null"; - _pickable = true; // For now, nobody gets events from this class! + _pickable = true; // For now, everyone gets events from this class! } /** @@ -56,25 +49,17 @@ CanvasItemBpath::CanvasItemBpath(CanvasItemGroup *group, Geom::PathVector path, /** * Set a control bpath. Curve is in document coordinates. */ -void CanvasItemBpath::set_bpath(SPCurve *curve, bool phantom_line) +void CanvasItemBpath::set_bpath(SPCurve const *curve, bool phantom_line) { - if (curve) { // No test to see if *curve == *_curve so we always do the swap. - _path = curve->get_pathvector(); - } else { - _path.clear(); - } - - _phantom_line = phantom_line; - - request_update(); + set_bpath(curve ? curve->get_pathvector() : Geom::PathVector(), phantom_line); } /** * Set a control bpath. Path is in document coordinates. */ -void CanvasItemBpath::set_bpath(Geom::PathVector const &path, bool phantom_line) +void CanvasItemBpath::set_bpath(Geom::PathVector path, bool phantom_line) { - _path = path; + _path = std::move(path); _phantom_line = phantom_line; request_update(); @@ -83,14 +68,20 @@ void CanvasItemBpath::set_bpath(Geom::PathVector const &path, bool phantom_line) /** * Set the fill color and fill rule. */ -void CanvasItemBpath::set_fill(guint rgba, SPWindRule fill_rule) +void CanvasItemBpath::set_fill(uint32_t fill, SPWindRule fill_rule) { - if (_fill != rgba || _fill_rule != fill_rule) { - _fill = rgba; + if (_fill != fill || _fill_rule != fill_rule) { + _fill = fill; _fill_rule = fill_rule; request_redraw(); } } + +void CanvasItemBpath::set_dashes(std::vector &&dashes) +{ + _dashes = std::move(dashes); +} + /** * Set the stroke width */ @@ -105,14 +96,14 @@ void CanvasItemBpath::set_stroke_width(double width) /** * Returns distance between point in canvas units and nearest point on bpath. */ -double CanvasItemBpath::closest_distance_to(Geom::Point const &p) +double CanvasItemBpath::closest_distance_to(Geom::Point const &p) const { double d = Geom::infinity(); // Convert p to document coordinates (quicker than converting path to canvas units). - Geom::Point p_doc = p * _affine.inverse(); + Geom::Point p_doc = p * affine().inverse(); _path.nearestTime(p_doc, &d); - d *= _affine.descrim(); // Uniform scaling and rotation only. + d *= affine().descrim(); // Uniform scaling and rotation only. return d; } @@ -128,11 +119,12 @@ bool CanvasItemBpath::contains(Geom::Point const &p, double tolerance) // Check for 'inside' a filled bpath if a fill is being used. if ((_fill & 0xff) != 0) { - Geom::Point p_doc = p * _affine.inverse(); + Geom::Point p_doc = p * affine().inverse(); if (_path.winding(p_doc) % 2 != 0) { return true; } } + // Otherwise see how close we are to the outside line. return closest_distance_to(p) < tolerance; } @@ -140,57 +132,27 @@ bool CanvasItemBpath::contains(Geom::Point const &p, double tolerance) /** * Update and redraw control bpath. */ -void CanvasItemBpath::update(Geom::Affine const &affine) +void CanvasItemBpath::_update(bool) { - if (_affine == affine && !_need_update) { - // Nothing to do. - return; - } - // Queue redraw of old area (erase previous content). request_redraw(); - // Get new bounds - _affine = affine; - - _bounds = Geom::Rect(); // Reset bounds - - if (_path.empty()) return; // No path, no chocolate! - - Geom::OptRect bbox = bounds_exact_transformed(_path, _affine); - - if (bbox) { - _bounds = *bbox; - _bounds.expandBy(2); - } else { - _bounds = Geom::Rect(); + if (_path.empty()) { + _bounds = {}; + return; } + _bounds = expandedBy(bounds_exact_transformed(_path, affine()), 2); + // Queue redraw of new area request_redraw(); - - _need_update = false; } /** * Render bpath to screen via Cairo. */ -void CanvasItemBpath::render(Inkscape::CanvasItemBuffer *buf) +void CanvasItemBpath::_render(Inkscape::CanvasItemBuffer &buf) { - if (!buf) { - std::cerr << "CanvasItemBpath::Render: No buffer!" << std::endl; - return; - } - - if (!_visible) { - // Hidden - return; - } - - if (_path.empty()) { - return; - } - bool do_fill = (_fill & 0xff) != 0; // Not invisible. bool do_stroke = (_stroke & 0xff) != 0; // Not invisible. @@ -199,55 +161,47 @@ void CanvasItemBpath::render(Inkscape::CanvasItemBuffer *buf) return; } - buf->cr->save(); + buf.cr->save(); // Setup path - buf->cr->set_tolerance(0.5); - buf->cr->begin_new_path(); + buf.cr->set_tolerance(0.5); + buf.cr->begin_new_path(); - feed_pathvector_to_cairo (buf->cr->cobj(), _path, _affine, buf->rect, - /* optimized_stroke = */ !do_fill, 1); + feed_pathvector_to_cairo(buf.cr->cobj(), _path, affine(), buf.rect, + /* optimize_stroke */ !do_fill, 1); // Do fill if (do_fill) { - 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->set_fill_rule(_fill_rule == SP_WIND_RULE_EVENODD ? + 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->set_fill_rule(_fill_rule == SP_WIND_RULE_EVENODD ? Cairo::FILL_RULE_EVEN_ODD : Cairo::FILL_RULE_WINDING); - buf->cr->fill_preserve(); + buf.cr->fill_preserve(); } // Do stroke if (do_stroke) { if (!_dashes.empty()) { - buf->cr->set_dash(_dashes, 0.0); // 0.0 is offset + buf.cr->set_dash(_dashes, 0.0); // 0.0 is offset } if (_phantom_line) { - buf->cr->set_source_rgba(1.0, 1.0, 1.0, 0.25); - buf->cr->set_line_width(2.0); - buf->cr->stroke_preserve(); + buf.cr->set_source_rgba(1.0, 1.0, 1.0, 0.25); + buf.cr->set_line_width(2.0); + buf.cr->stroke_preserve(); } - buf->cr->set_source_rgba(SP_RGBA32_R_F(_stroke), SP_RGBA32_G_F(_stroke), - SP_RGBA32_B_F(_stroke), SP_RGBA32_A_F(_stroke)); - buf->cr->set_line_width(_stroke_width); - buf->cr->stroke(); + buf.cr->set_source_rgba(SP_RGBA32_R_F(_stroke), SP_RGBA32_G_F(_stroke), + SP_RGBA32_B_F(_stroke), SP_RGBA32_A_F(_stroke)); + buf.cr->set_line_width(_stroke_width); + buf.cr->stroke(); } else { - buf->cr->begin_new_path(); // Clears path + buf.cr->begin_new_path(); // Clears path } - // 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(); + buf.cr->restore(); } } // namespace Inkscape diff --git a/src/display/control/canvas-item-bpath.h b/src/display/control/canvas-item-bpath.h index 0556939b61c88a6b6d89244b8ecea5aba2f67901..dfd042c1d9bd3a0091a5cf84e15045a8fe511c9b 100644 --- a/src/display/control/canvas-item-bpath.h +++ b/src/display/control/canvas-item-bpath.h @@ -28,34 +28,31 @@ class SPCurve; namespace Inkscape { -class CanvasItemGroup; // A canvas control that contains other canvas controls. - -class CanvasItemBpath : public CanvasItem { - +class CanvasItemBpath final : public CanvasItem +{ public: CanvasItemBpath(CanvasItemGroup *group); CanvasItemBpath(CanvasItemGroup *group, Geom::PathVector path, bool phantom_line = false); // Geometry - void set_bpath (SPCurve *curve, bool phantom_line = false); - void set_bpath (Geom::PathVector const &path, bool phantom_line = false); - void set_affine_absolute(Geom::Affine const &affine); + void set_bpath(SPCurve const *curve, bool phantom_line = false); + void set_bpath(Geom::PathVector path, bool phantom_line = false); - void update(Geom::Affine const &affine) override; - double closest_distance_to(Geom::Point const &p); // Maybe not needed + double closest_distance_to(Geom::Point const &p) const; // Selection bool contains(Geom::Point const &p, double tolerance = 0) override; - // Display - void render(Inkscape::CanvasItemBuffer *buf) override; - // Properties - void set_fill (guint32 rgba, SPWindRule fill_rule); - void set_dashes (std::vector dashes) { _dashes = std::move(dashes); } + void set_fill(uint32_t rgba, SPWindRule fill_rule); + void set_dashes(std::vector &&dashes); void set_stroke_width(double width); protected: + ~CanvasItemBpath() override = default; + + void _update(bool propagate) override; + void _render(Inkscape::CanvasItemBuffer &buf) override; // Geometry Geom::PathVector _path; diff --git a/src/display/control/canvas-item-buffer.h b/src/display/control/canvas-item-buffer.h index 8e9dd3b54f49325e066da76f7f6bf67f02edcac6..a66cb4c5a174d5e746976fabc33cd96e1da8275b 100644 --- a/src/display/control/canvas-item-buffer.h +++ b/src/display/control/canvas-item-buffer.h @@ -26,14 +26,15 @@ namespace Inkscape { /** * Class used when rendering canvas items. */ -struct CanvasItemBuffer { +struct CanvasItemBuffer +{ Geom::IntRect rect; int device_scale; // For high DPI monitors. Cairo::RefPtr cr; bool outline_pass; }; -} // Namespace Inkscape +} // namespace Inkscape #endif // SEEN_CANVAS_ITEM_BUFFER_H diff --git a/src/display/control/canvas-item-catchall.cpp b/src/display/control/canvas-item-catchall.cpp index 91bd323448edbf3964410fd3b05c60dd543ba12b..b5ec3d9c9f058ceca384a88ce4ff84e3e002a638 100644 --- a/src/display/control/canvas-item-catchall.cpp +++ b/src/display/control/canvas-item-catchall.cpp @@ -16,10 +16,6 @@ #include "canvas-item-catchall.h" -#include "color.h" // SP_RGBA_x_F - -#include "ui/widget/canvas.h" - namespace Inkscape { /** @@ -33,14 +29,6 @@ CanvasItemCatchall::CanvasItemCatchall(CanvasItemGroup *group) _bounds = Geom::Rect(-Geom::infinity(), -Geom::infinity(), Geom::infinity(), Geom::infinity()); } -/** - * Returns distance between point in canvas units and nearest point on catchall. - */ -double CanvasItemCatchall::closest_distance_to(Geom::Point const &p) -{ - return 0.0; // We're everywhere! -} - /** * Returns true if point p (in canvas units) is within tolerance (canvas units) distance of catchall. */ @@ -52,21 +40,19 @@ bool CanvasItemCatchall::contains(Geom::Point const &p, double tolerance) /** * Update and redraw control catchall. */ -void CanvasItemCatchall::update(Geom::Affine const &affine) +void CanvasItemCatchall::_update(bool) { // No geometry to update. - _affine = affine; } /** * Render catchall to screen via Cairo. */ -void CanvasItemCatchall::render(Inkscape::CanvasItemBuffer *buf) +void CanvasItemCatchall::_render(Inkscape::CanvasItemBuffer &buf) { // Do nothing! (Needed as CanvasItem is abstract.) } - } // namespace Inkscape /* diff --git a/src/display/control/canvas-item-catchall.h b/src/display/control/canvas-item-catchall.h index d40ab458671f970688409f66feeb4846a59ecd89..8c705d4387bb151d9b82e883b446a984fb74bb2a 100644 --- a/src/display/control/canvas-item-catchall.h +++ b/src/display/control/canvas-item-catchall.h @@ -17,32 +17,24 @@ * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ -#include <2geom/point.h> -#include <2geom/transforms.h> - #include "canvas-item.h" namespace Inkscape { -class CanvasItemGroup; // A canvas control that contains other canvas controls. - -class CanvasItemCatchall : public CanvasItem { - +class CanvasItemCatchall final : public CanvasItem +{ public: CanvasItemCatchall(CanvasItemGroup *group); - // Geometry - void update(Geom::Affine const &affine) override; - double closest_distance_to(Geom::Point const &p); - // Selection - bool contains(Geom::Point const &p, double tolerance = 0) override; + bool contains(Geom::Point const &p, double tolerance) override; - // Display - void render(Inkscape::CanvasItemBuffer *buf) override; - -}; +protected: + ~CanvasItemCatchall() override = default; + void _update(bool propagate) override; + void _render(Inkscape::CanvasItemBuffer &buf) override; +}; } // namespace Inkscape diff --git a/src/display/control/canvas-item-context.cpp b/src/display/control/canvas-item-context.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5e1af73c00a1ca4c7840c819eb76b7dc2ba59bc3 --- /dev/null +++ b/src/display/control/canvas-item-context.cpp @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "canvas-item-context.h" +#include "canvas-item-group.h" + +namespace Inkscape { + +CanvasItemContext::CanvasItemContext(UI::Widget::Canvas *canvas) + : _canvas(canvas) + , _root(new CanvasItemGroup(this)) +{ +} + +CanvasItemContext::~CanvasItemContext() +{ + delete _root; +} + +} // 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 : diff --git a/src/display/control/canvas-item-context.h b/src/display/control/canvas-item-context.h new file mode 100644 index 0000000000000000000000000000000000000000..da4d57a1be934974919b9649b78c4fa6dc57ef9c --- /dev/null +++ b/src/display/control/canvas-item-context.h @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * The context in which a single CanvasItem tree exists. Holds the root node and common state. + */ +#ifndef SEEN_CANVAS_ITEM_CONTEXT_H +#define SEEN_CANVAS_ITEM_CONTEXT_H + +#include <2geom/affine.h> + +namespace Inkscape { + +namespace UI::Widget { class Canvas; } +class CanvasItemGroup; + +class CanvasItemContext +{ +public: + CanvasItemContext(UI::Widget::Canvas *canvas); + CanvasItemContext(CanvasItemContext const &) = delete; + CanvasItemContext &operator=(CanvasItemContext const &) = delete; + ~CanvasItemContext(); + + // Structure + UI::Widget::Canvas *canvas() const { return _canvas; } + CanvasItemGroup *root() const { return _root; } + + // Geometry + Geom::Affine const &affine() const { return _affine; } + void setAffine(Geom::Affine const &affine) { _affine = affine; } + +private: + // Structure + UI::Widget::Canvas *_canvas; + CanvasItemGroup *_root; + + // Geometry + Geom::Affine _affine; +}; + +} // namespace Inkscape + +#endif // SEEN_CANVAS_ITEM_CONTEXT_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/control/canvas-item-ctrl.cpp b/src/display/control/canvas-item-ctrl.cpp index d92ba9863a1443beac8ed533137bc2c235f5217d..a03198f03452d4f45c11de76407b18ff849b59f5 100644 --- a/src/display/control/canvas-item-ctrl.cpp +++ b/src/display/control/canvas-item-ctrl.cpp @@ -17,6 +17,7 @@ #include <2geom/transforms.h> #include "canvas-item-ctrl.h" +#include "helper/geom.h" #include "preferences.h" // Default size. #include "display/cairo-utils.h" // argb32_from_rgba() @@ -25,13 +26,8 @@ namespace Inkscape { -CanvasItemCtrl::~CanvasItemCtrl() -{ - delete[] _cache; -} - /** - * Create an null control node. + * Create a null control node. */ CanvasItemCtrl::CanvasItemCtrl(CanvasItemGroup *group) : CanvasItem(group) @@ -43,7 +39,7 @@ CanvasItemCtrl::CanvasItemCtrl(CanvasItemGroup *group) /** * Create a control ctrl. Shape auto-set by type. */ -CanvasItemCtrl::CanvasItemCtrl(CanvasItemGroup *group, Inkscape::CanvasItemCtrlType type) +CanvasItemCtrl::CanvasItemCtrl(CanvasItemGroup *group, CanvasItemCtrlType type) : CanvasItem(group) , _type(type) { @@ -58,17 +54,17 @@ CanvasItemCtrl::CanvasItemCtrl(CanvasItemGroup *group, Inkscape::CanvasItemCtrlT /** * Create a control ctrl. Point is in document coordinates. */ -CanvasItemCtrl::CanvasItemCtrl(CanvasItemGroup *group, Inkscape::CanvasItemCtrlType type, Geom::Point const &p) +CanvasItemCtrl::CanvasItemCtrl(CanvasItemGroup *group, CanvasItemCtrlType type, Geom::Point const &p) : CanvasItemCtrl(group, type) { _position = p; + request_update(); } - /** * Create a control ctrl. */ -CanvasItemCtrl::CanvasItemCtrl(CanvasItemGroup *group, Inkscape::CanvasItemCtrlShape shape) +CanvasItemCtrl::CanvasItemCtrl(CanvasItemGroup *group, CanvasItemCtrlShape shape) : CanvasItem(group) , _shape(shape) , _type(CANVAS_ITEM_CTRL_TYPE_DEFAULT) @@ -77,15 +73,13 @@ CanvasItemCtrl::CanvasItemCtrl(CanvasItemGroup *group, Inkscape::CanvasItemCtrlS _pickable = true; // Everybody gets events from this class! } - /** * Create a control ctrl. Point is in document coordinates. */ -CanvasItemCtrl::CanvasItemCtrl(CanvasItemGroup *group, Inkscape::CanvasItemCtrlShape shape, Geom::Point const &p) +CanvasItemCtrl::CanvasItemCtrl(CanvasItemGroup *group, CanvasItemCtrlShape shape, Geom::Point const &p) : CanvasItemCtrl(group, shape) { _position = p; - request_update(); } /** @@ -103,11 +97,10 @@ void CanvasItemCtrl::set_position(Geom::Point const &position) /** * Returns distance between point in canvas units and position of ctrl. */ -double CanvasItemCtrl::closest_distance_to(Geom::Point const &p) +double CanvasItemCtrl::closest_distance_to(Geom::Point const &p) const { // TODO: Different criteria for different shapes. - Geom::Point position = _position * _affine; - return Geom::distance(p, position); + return Geom::distance(p, _position * affine()); } /** @@ -118,35 +111,36 @@ double CanvasItemCtrl::closest_distance_to(Geom::Point const &p) bool CanvasItemCtrl::contains(Geom::Point const &p, double tolerance) { // TODO: Different criteria for different shapes. + if (!_bounds) return false; if (tolerance == 0) { - return _bounds.interiorContains(p); + return _bounds->interiorContains(p); } else { return closest_distance_to(p) <= tolerance; } } +static auto angle_of(Geom::Affine const &affine) +{ + return std::atan2(affine[1], affine[0]); +} + /** * Update and redraw control ctrl. */ -void CanvasItemCtrl::update(Geom::Affine const &affine) +void CanvasItemCtrl::_update(bool) { - if (_affine == affine && !_need_update) { - // Nothing to do. - return; - } - // Queue redraw of old area (erase previous content). request_redraw(); - // Get new bounds - _affine = affine; + // Width and height are always odd. + assert(_width % 2 == 1); + assert(_height % 2 == 1); - // We must be pixel aligned, width and height are always odd. - _bounds = Geom::Rect::from_xywh(-(_width/2.0 - 0.5), -(_height/2.0 - 0.5), _width, _height); + // Get half width and height, rounded down. + int const w_half = _width / 2; + int const h_half = _height / 2; - // Adjust for anchor - int w_half = _width/2; - int h_half = _height/2; + // Set _angle, and compute adjustment for anchor. int dx = 0; int dy = 0; @@ -157,56 +151,56 @@ void CanvasItemCtrl::update(Geom::Affine const &affine) case CANVAS_ITEM_CTRL_SHAPE_SALIGN: case CANVAS_ITEM_CTRL_SHAPE_CALIGN: { + double angle = _anchor * M_PI_4 + angle_of(affine()); + double const half = _width / 2.0; - _angle = _anchor * M_PI/4.0 + std::atan2(_affine[1], _affine[0]); - - double half = _width/2.0; - - dx = - (half + 2) * cos(_angle); // Add a bit to prevent tip from overlapping due to rounding errors. - dy = - (half + 2) * sin(_angle); + dx = -(half + 2) * cos(angle); // Add a bit to prevent tip from overlapping due to rounding errors. + dy = -(half + 2) * sin(angle); switch (_shape) { - case CANVAS_ITEM_CTRL_SHAPE_CARROW: - _angle += 5 * M_PI/4.0; + angle += 5 * M_PI_4; break; case CANVAS_ITEM_CTRL_SHAPE_SARROW: - _angle += M_PI/2.0; + angle += M_PI_2; break; case CANVAS_ITEM_CTRL_SHAPE_SALIGN: - dx = - (half/2 + 2) * cos(_angle); - dy = - (half/2 + 2) * sin(_angle); - _angle -= M_PI/2.0; + dx = -(half / 2 + 2) * cos(angle); + dy = -(half / 2 + 2) * sin(angle); + angle -= M_PI_2; break; case CANVAS_ITEM_CTRL_SHAPE_CALIGN: - _angle -= M_PI/4.0; - dx = (half/2 + 2) * ( sin(_angle) - cos(_angle)); - dy = (half/2 + 2) * (-sin(_angle) - cos(_angle)); + angle -= M_PI_4; + dx = (half / 2 + 2) * ( sin(angle) - cos(angle)); + dy = (half / 2 + 2) * (-sin(angle) - cos(angle)); break; default: break; } - _built = false; // Angle may have change, must rebuild! + if (_angle != angle) { + _angle = angle; + _built = false; + } break; } case CANVAS_ITEM_CTRL_SHAPE_PIVOT: - case CANVAS_ITEM_CTRL_SHAPE_MALIGN: - - _angle = std::atan2(_affine[1], _affine[0]); - - _built = false; // Angle may have change, must rebuild! - + case CANVAS_ITEM_CTRL_SHAPE_MALIGN: { + double const angle = angle_of(affine()); + if (_angle != angle) { + _angle = angle; + _built = false; + } break; + } default: - switch (_anchor) { case SP_ANCHOR_N: case SP_ANCHOR_CENTER: @@ -247,68 +241,47 @@ void CanvasItemCtrl::update(Geom::Affine const &affine) break; } - _bounds *= Geom::Translate(Geom::IntPoint(dx, dy)); - - // Position must also be integer. - Geom::Point position = _position * _affine; - Geom::IntPoint iposition = position.floor(); - - _bounds *= Geom::Translate(iposition); + auto const pt = Geom::IntPoint(-w_half, -h_half) + Geom::IntPoint(dx, dy) + (_position * affine()).floor(); + _bounds = Geom::IntRect(pt, pt + Geom::IntPoint(_width, _height)); // Queue redraw of new area request_redraw(); - - _need_update = false; } - -static inline guint32 compose_xor(guint32 bg, guint32 fg, guint32 a) +static inline uint32_t compose_xor(uint32_t bg, uint32_t fg, uint32_t a) { - guint32 c = bg * (255-a) + (((bg ^ ~fg) + (bg >> 2) - (bg > 127 ? 63 : 0)) & 255) * a; + uint32_t c = bg * (255 - a) + (((bg ^ ~fg) + (bg >> 2) - (bg > 127 ? 63 : 0)) & 255) * a; return (c + 127) / 255; } /** * Render ctrl to screen via Cairo. */ -void CanvasItemCtrl::render(Inkscape::CanvasItemBuffer *buf) +void CanvasItemCtrl::_render(CanvasItemBuffer &buf) { - if (!buf) { - std::cerr << "CanvasItemCtrl::Render: No buffer!" << std::endl; - return; - } - - if (!_bounds.intersects(buf->rect)) { - return; // Control not inside buffer rectangle. - } - - if (!_visible) { - return; // Hidden. - } - if (!_built) { - build_cache(buf->device_scale); + build_cache(buf.device_scale); } - Geom::Point c = _bounds.min() - buf->rect.min(); + Geom::Point c = _bounds->min() - buf.rect.min(); int x = c.x(); // Must be pixel aligned. int y = c.y(); - buf->cr->save(); + buf.cr->save(); // This code works regardless of source type. // 1. Copy the affected part of output to a temporary surface // Size in device pixels. Does not set device scale. - int width = _width * buf->device_scale; - int height = _height * buf->device_scale; + int width = _width * buf.device_scale; + int height = _height * buf.device_scale; auto work = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, width, height); - cairo_surface_set_device_scale(work->cobj(), buf->device_scale, buf->device_scale); // No C++ API! + cairo_surface_set_device_scale(work->cobj(), buf.device_scale, buf.device_scale); // No C++ API! auto cr = Cairo::Context::create(work); - cr->translate(-_bounds.left(), -_bounds.top()); - cr->set_source(buf->cr->get_target(), buf->rect.left(), buf->rect.top()); + cr->translate(-_bounds->left(), -_bounds->top()); + cr->set_source(buf.cr->get_target(), buf.rect.left(), buf.rect.top()); cr->paint(); // static int a = 0; // std::string name0 = "ctrl0_" + _name + "_" + std::to_string(a++) + ".png"; @@ -320,14 +293,14 @@ void CanvasItemCtrl::render(Inkscape::CanvasItemBuffer *buf) unsigned char *pxb = work->get_data(); // this code allow background become isolated from rendering so we can do things like outline overlay - guint32 backcolor = _canvas->get_effective_background(); - guint32 *p = _cache; + uint32_t backcolor = get_canvas()->get_effective_background(); + uint32_t *p = _cache.get(); for (int i = 0; i < height; ++i) { - guint32 *pb = reinterpret_cast(pxb + i*strideb); + auto pb = reinterpret_cast(pxb + i * strideb); for (int j = 0; j < width; ++j) { - guint32 base = *pb; - guint32 cc = *p++; - guint32 ac = cc & 0xff; + uint32_t base = *pb; + uint32_t cc = *p++; + uint32_t ac = cc & 0xff; if (*pb == 0 && cc != 0) { base = backcolor; } @@ -351,15 +324,15 @@ void CanvasItemCtrl::render(Inkscape::CanvasItemBuffer *buf) bb = (ab/255.0) * bb + (1-(ab/255.0)) * bbb; ab = 255; } - guint32 ro = compose_xor(rb, (cc & 0xff000000) >> 24, ac); - guint32 go = compose_xor(gb, (cc & 0x00ff0000) >> 16, ac); - guint32 bo = compose_xor(bb, (cc & 0x0000ff00) >> 8, ac); + uint32_t ro = compose_xor(rb, (cc & 0xff000000) >> 24, ac); + uint32_t go = compose_xor(gb, (cc & 0x00ff0000) >> 16, ac); + uint32_t bo = compose_xor(bb, (cc & 0x0000ff00) >> 8, ac); if (_mode == CANVAS_ITEM_CTRL_MODE_GRAYSCALED_XOR || _mode == CANVAS_ITEM_CTRL_MODE_DESATURATED_XOR) { - guint32 gray = ro * 0.299 + go * 0.587 + bo * 0.114; + uint32_t gray = ro * 0.299 + go * 0.587 + bo * 0.114; if (_mode == CANVAS_ITEM_CTRL_MODE_DESATURATED_XOR) { double f = 0.85; // desaturate by 15% - double p = sqrt(ro * ro * 0.299 + go * go * 0.587 + bo * bo * 0.114); + double p = sqrt(ro * ro * 0.299 + go * go * 0.587 + bo * bo * 0.114); ro = p + (ro - p) * f; go = p + (go - p) * f; bo = p + (bo - p) * f; @@ -381,39 +354,37 @@ void CanvasItemCtrl::render(Inkscape::CanvasItemBuffer *buf) // work->write_to_png(name1); // 3. Replace the affected part of output with contents of temporary surface - buf->cr->set_source(work, x, y); - - + buf.cr->set_source(work, x, y); - buf->cr->rectangle(x, y, _width, _height); - buf->cr->clip(); - buf->cr->set_operator(Cairo::OPERATOR_SOURCE); - buf->cr->paint(); - buf->cr->restore(); + buf.cr->rectangle(x, y, _width, _height); + buf.cr->clip(); + buf.cr->set_operator(Cairo::OPERATOR_SOURCE); + buf.cr->paint(); + buf.cr->restore(); } -void CanvasItemCtrl::set_fill(guint32 rgba) +void CanvasItemCtrl::set_fill(uint32_t fill) { - if (_fill != rgba) { - _fill = rgba; + if (_fill != fill) { + _fill = fill; _built = false; request_redraw(); } } -void CanvasItemCtrl::set_stroke(guint32 rgba) +void CanvasItemCtrl::set_stroke(uint32_t stroke) { - if (_stroke != rgba) { - _stroke = rgba; + if (_stroke != stroke) { + _stroke = stroke; _built = false; request_redraw(); } } -void CanvasItemCtrl::set_shape(int shape) +void CanvasItemCtrl::set_shape(CanvasItemCtrlShape shape) { if (_shape != shape) { - _shape = Inkscape::CanvasItemCtrlShape(shape); // Fixme + _shape = shape; _built = false; request_update(); // Geometry could change } @@ -475,21 +446,21 @@ void CanvasItemCtrl::set_shape_default() } } -void CanvasItemCtrl::set_mode(int mode) +void CanvasItemCtrl::set_mode(CanvasItemCtrlMode mode) { if (_mode != mode) { - _mode = Inkscape::CanvasItemCtrlMode(mode); // Fixme + _mode = mode; _built = false; request_update(); } } -void CanvasItemCtrl::set_pixbuf(GdkPixbuf *pixbuf) +void CanvasItemCtrl::set_pixbuf(Glib::RefPtr pixbuf) { if (_pixbuf != pixbuf) { - _pixbuf = pixbuf; - _width = gdk_pixbuf_get_width(pixbuf); - _height = gdk_pixbuf_get_height(pixbuf); + _pixbuf = std::move(pixbuf); + _width = _pixbuf->get_width(); + _height = _pixbuf->get_height(); _built = false; request_update(); } @@ -577,14 +548,13 @@ void CanvasItemCtrl::set_size_via_index(int size_index) void CanvasItemCtrl::set_size_default() { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - int size = prefs->getIntLimited("/options/grabsize/value", 3, 1, 15); + int size = Preferences::get()->getIntLimited("/options/grabsize/value", 3, 1, 15); set_size_via_index(size); } void CanvasItemCtrl::set_size_extra(int extra) { - if (_extra != extra && _pixbuf == nullptr) { // Don't enlarge pixbuf! + if (_extra != extra && !_pixbuf) { // Don't enlarge pixbuf! _width += (extra - _extra); _height += (extra - _extra); _extra = extra; @@ -593,16 +563,16 @@ void CanvasItemCtrl::set_size_extra(int extra) } } -void CanvasItemCtrl::set_type(Inkscape::CanvasItemCtrlType type) +void CanvasItemCtrl::set_type(CanvasItemCtrlType type) { if (_type != type) { _type = type; - // Use _type to set default values: + // Use _type to set default values. set_shape_default(); set_size_default(); _built = false; - request_update(); // Possible Geometry change + request_update(); // Possible geometry change } } @@ -624,20 +594,8 @@ void CanvasItemCtrl::set_anchor(SPAnchorType anchor) // ---------- Protected ---------- -// Helper function for build_cache(): -bool point_inside_triangle(Geom::Point p1,Geom::Point p2,Geom::Point p3, Geom::Point point){ - using Geom::X; - using Geom::Y; - double denominator = (p1[X]*(p2[Y] - p3[Y]) + p1[Y]*(p3[X] - p2[X]) + p2[X]*p3[Y] - p2[Y]*p3[X]); - double t1 = (point[X]*(p3[Y] - p1[Y]) + point[Y]*(p1[X] - p3[X]) - p1[X]*p3[Y] + p1[Y]*p3[X]) / denominator; - double t2 = (point[X]*(p2[Y] - p1[Y]) + point[Y]*(p1[X] - p2[X]) - p1[X]*p2[Y] + p1[Y]*p2[X]) / -denominator; - double see = t1 + t2; - return 0 <= t1 && t1 <= 1 && 0 <= t2 && t2 <= 1 && see <= 1; -} - - -void draw_darrow(Cairo::RefPtrcr, double size) { - +static void draw_darrow(Cairo::RefPtr const &cr, double size) +{ // Find points, starting from tip of one arrowhead, working clockwise. /* 1 4 ╱│ │╲ @@ -688,8 +646,8 @@ void draw_darrow(Cairo::RefPtrcr, double size) { cr->close_path(); } -void draw_carrow(Cairo::RefPtrcr, double size) { - +static void draw_carrow(Cairo::RefPtr const &cr, double size) +{ // Length of arrowhead (not including stroke). double delta = (size-3)/4.0; // Use unscaled width. @@ -730,8 +688,8 @@ void draw_carrow(Cairo::RefPtrcr, double size) { cr->close_path(); } -void draw_pivot(Cairo::RefPtrcr, double size) { - +static void draw_pivot(Cairo::RefPtr const &cr, double size) +{ double delta4 = (size-5)/4.0; // Keep away from edge or will clip when rotating. double delta8 = delta4/2; @@ -767,8 +725,8 @@ void draw_pivot(Cairo::RefPtrcr, double size) { cr->arc_negative(center, center, delta4, 0, -2 * M_PI); } -void draw_salign(Cairo::RefPtrcr, double size) { - +static void draw_salign(Cairo::RefPtr const &cr, double size) +{ // Triangle pointing at line. // Basic units. @@ -806,8 +764,8 @@ void draw_salign(Cairo::RefPtrcr, double size) { cr->close_path(); } -void draw_calign(Cairo::RefPtrcr, double size) { - +static void draw_calign(Cairo::RefPtr const &cr, double size) +{ // Basic units. double delta4 = (size-1)/4.0; // Use unscaled width. double delta8 = delta4/2; @@ -848,8 +806,8 @@ void draw_calign(Cairo::RefPtrcr, double size) { cr->close_path(); } -void draw_malign(Cairo::RefPtrcr, double size) { - +static void draw_malign(Cairo::RefPtr const &cr, double size) +{ // Basic units. double delta4 = (size-1)/4.0; // Use unscaled width. double delta8 = delta4/2; @@ -882,7 +840,6 @@ void draw_malign(Cairo::RefPtrcr, double size) { cr->line_to(tip_1 - delta4, tip_0 + delta4); cr->line_to(tip_1 - delta4, tip_0 - delta4); cr->close_path(); - } void CanvasItemCtrl::build_cache(int device_scale) @@ -891,12 +848,6 @@ void CanvasItemCtrl::build_cache(int device_scale) return; // Nothing to render } - // Get colors - guint32 fill = 0x0; - guint32 stroke = 0x0; - fill = _fill; - stroke = _stroke; - if (_shape != CANVAS_ITEM_CTRL_SHAPE_BITMAP) { if (_width % 2 == 0 || _height % 2 == 0) { std::cerr << "CanvasItemCtrl::build_cache: Width and/or height not odd integer! " @@ -905,33 +856,32 @@ void CanvasItemCtrl::build_cache(int device_scale) } // Get memory for cache. - int width = _width * device_scale; // Not unsigned or math errors occur! + int width = _width * device_scale; // Not unsigned or math errors occur! int height = _height * device_scale; int size = width * height; - if (_cache) delete[] _cache; - _cache = new guint32[size]; - guint32 *p = _cache; + _cache = std::make_unique(size); + auto p = _cache.get(); switch (_shape) { - case CANVAS_ITEM_CTRL_SHAPE_SQUARE: // Actually any rectanglular shape. for (int i = 0; i < width; ++i) { for (int j = 0; j < width; ++j) { - if (i + 1 > device_scale && device_scale < width - i && - j + 1 > device_scale && device_scale < height - j) { - *p++ = fill; + if (i + 1 > device_scale && device_scale < width - i && + j + 1 > device_scale && device_scale < height - j) + { + *p++ = _fill; } else { - *p++ = stroke; + *p++ = _stroke; } } } _built = true; break; - case CANVAS_ITEM_CTRL_SHAPE_DIAMOND: - { // Assume width == height. + case CANVAS_ITEM_CTRL_SHAPE_DIAMOND: { + // Assume width == height. int m = (width+1)/2; for (int i = 0; i < width; ++i) { @@ -940,13 +890,13 @@ void CanvasItemCtrl::build_cache(int device_scale) (width-1-i) + j > m-1+device_scale && (width-1-i) + (height-1-j) > m-1+device_scale && i + (height-1-j) > m-1+device_scale ) { - *p++ = fill; + *p++ = _fill; } else if ( i + j > m-2 && (width-1-i) + j > m-2 && (width-1-i) + (height-1-j) > m-2 && i + (height-1-j) > m-2 ) { - *p++ = stroke; + *p++ = _stroke; } else { *p++ = 0; } @@ -956,8 +906,8 @@ void CanvasItemCtrl::build_cache(int device_scale) break; } - case CANVAS_ITEM_CTRL_SHAPE_CIRCLE: - { // Assume width == height. + case CANVAS_ITEM_CTRL_SHAPE_CIRCLE: { + // Assume width == height. double rs = width/2.0; double rs2 = rs*rs; double rf = rs-device_scale; @@ -971,9 +921,9 @@ void CanvasItemCtrl::build_cache(int device_scale) double r2 = rx*rx + ry*ry; if (r2 < rf2) { - *p++ = fill; + *p++ = _fill; } else if (r2 < rs2) { - *p++ = stroke; + *p++ = _stroke; } else { *p++ = 0; } @@ -983,8 +933,7 @@ void CanvasItemCtrl::build_cache(int device_scale) break; } - case CANVAS_ITEM_CTRL_SHAPE_TRIANGLE: - { + case CANVAS_ITEM_CTRL_SHAPE_TRIANGLE: { Geom::Affine m = Geom::Translate(Geom::Point(-width/2.0,-height/2.0)); m *= Geom::Rotate(-_angle); m *= Geom::Translate(Geom::Point(width/2.0, height/2.0)); @@ -1014,18 +963,16 @@ void CanvasItemCtrl::build_cache(int device_scale) p2f *= m; p3f *= m; - for(int y = 0; y < height; y++) { - for(int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { Geom::Point point = Geom::Point(x+0.5, y+0.5); - if (point_inside_triangle(p1f, p2f, p3f, point)) { - p[(y*width)+x] = fill; - - } else if (point_inside_triangle(p1s, p2s, p3s, point)) { - p[(y*width)+x] = stroke; - + if (pointInTriangle(point, p1f, p2f, p3f)) { + p[y * width + x] = _fill; + } else if (pointInTriangle(point, p1s, p2s, p3s)) { + p[y * width + x] = _stroke; } else { - p[(y*width)+x] = 0; + p[y * width + x] = 0; } } } @@ -1034,11 +981,11 @@ void CanvasItemCtrl::build_cache(int device_scale) case CANVAS_ITEM_CTRL_SHAPE_CROSS: // Actually an 'X'. - for(int y = 0; y < height; y++) { - for(int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { if ( abs(x - y) < device_scale || abs(width - 1 - x - y) < device_scale ) { - *p++ = stroke; + *p++ = _stroke; } else { *p++ = 0; } @@ -1049,11 +996,11 @@ void CanvasItemCtrl::build_cache(int device_scale) case CANVAS_ITEM_CTRL_SHAPE_PLUS: // Actually an '+'. - for(int y = 0; y < height; y++) { - for(int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { if ( std::abs(x-width/2) < device_scale || std::abs(y-height/2) < device_scale ) { - *p++ = stroke; + *p++ = _stroke; } else { *p++ = 0; } @@ -1130,19 +1077,19 @@ void CanvasItemCtrl::build_cache(int device_scale) work->flush(); int strideb = work->get_stride(); unsigned char* pxb = work->get_data(); - guint32 *p = _cache; + auto p = _cache.get(); for (int i = 0; i < device_scale * size; ++i) { - guint32 *pb = reinterpret_cast(pxb + i*strideb); + auto pb = reinterpret_cast(pxb + i*strideb); for (int j = 0; j < width; ++j) { - guint32 color = 0x0; + uint32_t color = 0x0; // Need to un-premultiply alpha and change order argb -> rgba. - guint32 alpha = (*pb & 0xff000000) >> 24; + uint32_t alpha = (*pb & 0xff000000) >> 24; if (alpha == 0x0) { color = 0x0; } else { - guint32 rgb = unpremul_alpha(*pb & 0xffffff, alpha); + uint32_t rgb = unpremul_alpha(*pb & 0xffffff, alpha); color = (rgb << 8) + alpha; } @@ -1157,12 +1104,12 @@ void CanvasItemCtrl::build_cache(int device_scale) case CANVAS_ITEM_CTRL_SHAPE_BITMAP: { if (_pixbuf) { - unsigned char* px = gdk_pixbuf_get_pixels (_pixbuf); - unsigned int rs = gdk_pixbuf_get_rowstride (_pixbuf); + unsigned char* px = _pixbuf->get_pixels(); + unsigned int rs = _pixbuf->get_rowstride(); for (int y = 0; y < height/device_scale; y++){ for (int x = 0; x < width/device_scale; x++) { unsigned char *s = px + rs*y + 4*x; - guint32 color; + uint32_t color; if (s[3] < 0x80) { color = 0; } else if (s[0] < 0x80) { @@ -1174,7 +1121,7 @@ void CanvasItemCtrl::build_cache(int device_scale) // Fill in device_scale x device_scale block for (int i = 0; i < device_scale; ++i) { for (int j = 0; j < device_scale; ++j) { - guint* p = _cache + + auto p = _cache.get() + (x * device_scale + i) + // Column (y * device_scale + j) * width; // Row *p = color; @@ -1184,7 +1131,7 @@ void CanvasItemCtrl::build_cache(int device_scale) } } else { std::cerr << "CanvasItemCtrl::build_cache: No bitmap!" << std::endl; - guint *p = _cache; + auto p = _cache.get(); for (int y = 0; y < height/device_scale; y++){ for (int x = 0; x < width/device_scale; x++) { if (x == y) { @@ -1205,6 +1152,7 @@ void CanvasItemCtrl::build_cache(int device_scale) default: std::cerr << "CanvasItemCtrl::build_cache: unhandled shape!" << std::endl; + break; } } diff --git a/src/display/control/canvas-item-ctrl.h b/src/display/control/canvas-item-ctrl.h index 4cccc8843663cf55b688573775d16283b066ac8f..e686ceb17029cd7810d6ff3239f1ba040d1b202e 100644 --- a/src/display/control/canvas-item-ctrl.h +++ b/src/display/control/canvas-item-ctrl.h @@ -18,8 +18,8 @@ */ #include -#include #include <2geom/point.h> +#include #include "canvas-item.h" #include "canvas-item-enums.h" @@ -28,12 +28,9 @@ namespace Inkscape { -class CanvasItemGroup; // A canvas control that contains other canvas controls. - -class CanvasItemCtrl : public CanvasItem { - +class CanvasItemCtrl : public CanvasItem +{ public: - ~CanvasItemCtrl() override; CanvasItemCtrl(CanvasItemGroup *group); CanvasItemCtrl(CanvasItemGroup *group, CanvasItemCtrlType type); CanvasItemCtrl(CanvasItemGroup *group, CanvasItemCtrlType type, Geom::Point const &p); @@ -43,21 +40,17 @@ public: // Geometry void set_position(Geom::Point const &position); - void update(Geom::Affine const &affine) override; - double closest_distance_to(Geom::Point const &p); + double closest_distance_to(Geom::Point const &p) const; // Selection bool contains(Geom::Point const &p, double tolerance = 0) override; - // Display - void render(Inkscape::CanvasItemBuffer *buf) override; - // Properties - void set_fill(guint32 rgba) override; - void set_stroke(guint32 rgba) override; - void set_shape(int shape); + void set_fill(uint32_t rgba) override; + void set_stroke(uint32_t rgba) override; + void set_shape(CanvasItemCtrlShape shape); void set_shape_default(); // Use type to determine shape. - void set_mode(int mode); + void set_mode(CanvasItemCtrlMode mode); void set_mode_default(); void set_size(int size); virtual void set_size_via_index(int size_index); @@ -66,31 +59,35 @@ public: void set_anchor(SPAnchorType anchor); void set_angle(double angle); void set_type(CanvasItemCtrlType type); - void set_pixbuf(GdkPixbuf *pixbuf); + void set_pixbuf(Glib::RefPtr pixbuf); protected: + ~CanvasItemCtrl() override = default; + + void _update(bool propagate) override; + void _render(Inkscape::CanvasItemBuffer &buf) override; + void build_cache(int device_scale); // Geometry Geom::Point _position; // Display - guint32 *_cache = nullptr; + std::unique_ptr _cache; bool _built = false; // Properties - CanvasItemCtrlType _type = CANVAS_ITEM_CTRL_TYPE_DEFAULT; + CanvasItemCtrlType _type = CANVAS_ITEM_CTRL_TYPE_DEFAULT; CanvasItemCtrlShape _shape = CANVAS_ITEM_CTRL_SHAPE_SQUARE; - CanvasItemCtrlMode _mode = CANVAS_ITEM_CTRL_MODE_XOR; - unsigned int _width = 5; // Nominally width == height == size... unless we use a pixmap. - unsigned int _height = 5; - unsigned int _extra = 0; // Used to temporarily increase size. - double _angle = 0.0; // Used for triangles, could be used for arrows. + CanvasItemCtrlMode _mode = CANVAS_ITEM_CTRL_MODE_XOR; + int _width = 5; // Nominally width == height == size... unless we use a pixmap. + int _height = 5; + int _extra = 0; // Used to temporarily increase size. + double _angle = 0; // Used for triangles, could be used for arrows. SPAnchorType _anchor = SP_ANCHOR_CENTER; - GdkPixbuf *_pixbuf = nullptr; + Glib::RefPtr _pixbuf; }; - } // namespace Inkscape #endif // SEEN_CANVAS_ITEM_CTRL_H diff --git a/src/display/control/canvas-item-curve.cpp b/src/display/control/canvas-item-curve.cpp index a99a154b24bb36035bab65cd005d190edfca02d5..3a6524d0ae9f417c45b0eedcc9fd627ad0a16014 100644 --- a/src/display/control/canvas-item-curve.cpp +++ b/src/display/control/canvas-item-curve.cpp @@ -20,6 +20,7 @@ #include "color.h" // SP_RGBA_x_F +#include "helper/geom.h" #include "ui/widget/canvas.h" namespace Inkscape { @@ -31,7 +32,6 @@ CanvasItemCurve::CanvasItemCurve(CanvasItemGroup *group) : CanvasItem(group) { _name = "CanvasItemCurve:Null"; - _pickable = false; // For now, nobody gets events from this class! } /** @@ -42,9 +42,6 @@ CanvasItemCurve::CanvasItemCurve(CanvasItemGroup *group, Geom::Point const &p0, , _curve(std::make_unique(p0, p1)) { _name = "CanvasItemCurve:Line"; - _pickable = false; // For now, nobody gets events from this class! - - request_update(); } /** @@ -57,9 +54,6 @@ CanvasItemCurve::CanvasItemCurve(CanvasItemGroup *group, , _curve(std::make_unique(p0, p1, p2, p3)) { _name = "CanvasItemCurve:CubicBezier"; - _pickable = false; // For now, nobody gets events from this class! - - request_update(); } /** @@ -87,10 +81,9 @@ void CanvasItemCurve::set_coords(Geom::Point const &p0, Geom::Point const &p1, G /** * Set stroke width. */ -void CanvasItemCurve::set_width(int w) +void CanvasItemCurve::set_width(int width) { - width = w; - + _width = width; request_update(); } @@ -100,19 +93,18 @@ void CanvasItemCurve::set_width(int w) void CanvasItemCurve::set_bg_alpha(float alpha) { bg_alpha = alpha; - request_update(); } /** * Returns distance between point in canvas units and nearest point on curve. */ -double CanvasItemCurve::closest_distance_to(Geom::Point const &p) +double CanvasItemCurve::closest_distance_to(Geom::Point const &p) const { double d = Geom::infinity(); if (_curve) { Geom::BezierCurve curve = *_curve; - curve *= _affine; // Document to canvas. + curve *= affine(); // Document to canvas. Geom::Point n = curve.pointAt(curve.nearestTime(p)); d = Geom::distance(p, n); } @@ -130,96 +122,67 @@ bool CanvasItemCurve::contains(Geom::Point const &p, double tolerance) /** * Update and redraw control curve. */ -void CanvasItemCurve::update(Geom::Affine const &affine) +void CanvasItemCurve::_update(bool) { - if (_affine == affine && !_need_update) { - // Nothing to do. - return; - } - - if (!_curve) { - return; // No curve! See node.h. - } - // Queue redraw of old area (erase previous content). request_redraw(); // This is actually never useful as curves are always deleted - // and recreated when a node is moved! But keep it in case we - // change that. CHECK - // Get new bounds - _affine = affine; + // and recreated when a node is moved! But keep it in case we change that. - // Trade off between updating a larger area (typically twice for Beziers?) vs computation time for bounds. - _bounds = _curve->boundsExact(); // Document units. - _bounds *= _affine; // Document to canvas. - _bounds.expandBy(2); // Room for stroke. + if (!_curve || _curve->isDegenerate()) { + _bounds = {}; + return; // No curve! Can happen - see node.h. + } + + // Tradeoff between updating a larger area (typically twice for Beziers?) vs computation time for bounds. + _bounds = expandedBy(_curve->boundsExact() * affine(), 2); // Room for stroke. // Queue redraw of new area request_redraw(); - - _need_update = false; } /** * Render curve to screen via Cairo. */ -void CanvasItemCurve::render(Inkscape::CanvasItemBuffer *buf) +void CanvasItemCurve::_render(Inkscape::CanvasItemBuffer &buf) { - if (!buf) { - std::cerr << "CanvasItemCurve::Render: No buffer!" << std::endl; - return; - } - - if (!_curve) { - // Curve not defined (see node.h). - return; - } - - if (!_visible) { - // Hidden - return; - } - - if (_curve->isDegenerate()) { - // Nothing to render! - return; - } + assert(_curve); // Not called if _curve is null, since _bounds would be null. + // Todo: Transform, rather than copy. Geom::BezierCurve curve = *_curve; - curve *= _affine; // Document to canvas. - curve *= Geom::Translate(-buf->rect.min()); // Canvas to screen. + curve *= affine(); // Document to canvas. + curve *= Geom::Translate(-buf.rect.min()); // Canvas to screen. - buf->cr->save(); + buf.cr->save(); - buf->cr->begin_new_path(); + buf.cr->begin_new_path(); if (curve.size() == 2) { // Line - buf->cr->move_to(curve[0].x(), curve[0].y()); - buf->cr->line_to(curve[1].x(), curve[1].y()); + buf.cr->move_to(curve[0].x(), curve[0].y()); + buf.cr->line_to(curve[1].x(), curve[1].y()); } else { // Curve - buf->cr->move_to(curve[0].x(), curve[0].y()); - buf->cr->curve_to(curve[1].x(), curve[1].y(), curve[2].x(), curve[2].y(), curve[3].x(), curve[3].y()); + buf.cr->move_to(curve[0].x(), curve[0].y()); + buf.cr->curve_to(curve[1].x(), curve[1].y(), curve[2].x(), curve[2].y(), curve[3].x(), curve[3].y()); } - buf->cr->set_source_rgba(1.0, 1.0, 1.0, bg_alpha); - buf->cr->set_line_width(background_width); - buf->cr->stroke_preserve(); + buf.cr->set_source_rgba(1.0, 1.0, 1.0, bg_alpha); + buf.cr->set_line_width(background_width); + buf.cr->stroke_preserve(); - buf->cr->set_source_rgba(SP_RGBA32_R_F(_stroke), SP_RGBA32_G_F(_stroke), - SP_RGBA32_B_F(_stroke), SP_RGBA32_A_F(_stroke)); - buf->cr->set_line_width(width); - buf->cr->stroke(); + buf.cr->set_source_rgba(SP_RGBA32_R_F(_stroke), SP_RGBA32_G_F(_stroke), SP_RGBA32_B_F(_stroke), SP_RGBA32_A_F(_stroke)); + buf.cr->set_line_width(_width); + buf.cr->stroke(); // 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(); + // 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(); + buf.cr->restore(); } } // namespace Inkscape diff --git a/src/display/control/canvas-item-curve.h b/src/display/control/canvas-item-curve.h index 84d6511b4a25fbd1a3fc9a3e147f92c636ad730e..e7d0cce88d7da55d162bf7826c77ddcbcc72b0a3 100644 --- a/src/display/control/canvas-item-curve.h +++ b/src/display/control/canvas-item-curve.h @@ -24,10 +24,8 @@ namespace Inkscape { -class CanvasItemGroup; // A canvas control that contains other canvas controls. - -class CanvasItemCurve : public CanvasItem { - +class CanvasItemCurve final : public CanvasItem +{ public: CanvasItemCurve(CanvasItemGroup *group); CanvasItemCurve(CanvasItemGroup *group, Geom::Point const &p0, Geom::Point const &p1); @@ -37,40 +35,29 @@ public: // Geometry void set_coords(Geom::Point const &p0, Geom::Point const &p1); void set_coords(Geom::Point const &p0, Geom::Point const &p1, Geom::Point const &p2, Geom::Point const &p3); - void set(Geom::BezierCurve &curve); - void set_width(int w); + void set_width(int width); void set_bg_alpha(float alpha); - bool is_line() { return _curve->size() == 2; } + bool is_line() const { return _curve->size() == 2; } - void update(Geom::Affine const &affine) override; - double closest_distance_to(Geom::Point const &p); // Maybe not needed + double closest_distance_to(Geom::Point const &p) const; // Selection bool contains(Geom::Point const &p, double tolerance = 0) override; - - // Display - void render(Inkscape::CanvasItemBuffer *buf) override; - - // Properties - void set_is_fill(bool is_fill) { _is_fill = is_fill; } - bool get_is_fill() { return _is_fill; } - void set_corner0(int corner0) { _corner0 = corner0; } // Used for meshes - int get_corner0() { return _corner0; } - void set_corner1(int corner1) { _corner1 = corner1; } - int get_corner1() { return _corner1; } protected: - std::unique_ptr _curve; - bool _is_fill = true; // Fill or stroke, used by meshes. + ~CanvasItemCurve() override = default; - int width = 1; + void _update(bool propagate) override; + void _render(Inkscape::CanvasItemBuffer &buf) override; + + // Display + std::unique_ptr _curve; + + int _width = 1; int background_width = 3; // this should be an odd number so that the background appears on both the sides of the curve. float bg_alpha = 0.5f; - int _corner0 = -1; // For meshes - int _corner1 = -1; // For meshes }; - } // namespace Inkscape #endif // SEEN_CANVAS_ITEM_CURVE_H diff --git a/src/display/control/canvas-item-drawing.cpp b/src/display/control/canvas-item-drawing.cpp index 494ef0df5f0c09fe7961e7263a7e77d7c8bfa8f3..bb95c0293e13629891d4f241d02c925d6980b7cd 100644 --- a/src/display/control/canvas-item-drawing.cpp +++ b/src/display/control/canvas-item-drawing.cpp @@ -9,7 +9,7 @@ * * Copyright (C) 2020 Tavmjong Bah * - * Rewrite of _SPCavasArena. + * Rewrite of _SPCanvasArena. * * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ @@ -23,6 +23,7 @@ #include "display/drawing-item.h" #include "display/drawing-group.h" +#include "helper/geom.h" #include "ui/widget/canvas.h" #include "ui/modifiers.h" @@ -43,16 +44,6 @@ CanvasItemDrawing::CanvasItemDrawing(CanvasItemGroup *group) _drawing->setRoot(root); } -/** - * Returns distance between point in canvas units and nearest point on drawing. - */ -double CanvasItemDrawing::closest_distance_to(Geom::Point const &p) -{ - double d = Geom::infinity(); - std::cerr << "CanvasItemDrawing::closest_distance_to: Not implemented!" << std::endl; - return d; -} - /** * Returns true if point p (in canvas units) is inside some object in drawing. */ @@ -62,13 +53,11 @@ bool CanvasItemDrawing::contains(Geom::Point const &p, double tolerance) std::cerr << "CanvasItemDrawing::contains: Non-zero tolerance not implemented!" << std::endl; } - _drawing->update(Geom::IntRect::infinite(), _ctx.ctm, DrawingItem::STATE_PICK | DrawingItem::STATE_BBOX); _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-a-bout way of doing things but it matches what other pickable canvas-item classes - // do. + // round-about way of doing things but it matches what other pickable canvas-item classes do. return true; } @@ -78,33 +67,22 @@ bool CanvasItemDrawing::contains(Geom::Point const &p, double tolerance) /** * Update and redraw drawing. */ -void CanvasItemDrawing::update(Geom::Affine const &affine) +void CanvasItemDrawing::_update(bool) { - auto new_affine = affine; - - // Correct for y-axis. This should not be here!!!! - if (auto *desktop = _canvas->get_desktop()) { - new_affine = desktop->doc2dt() * new_affine; + // 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; } - // if (_affine == new_affine && !_need_update) { - // // Nothing to do. - // return; - // } - - _ctx.ctm = new_affine; // TODO Remove _ctx.ctm... it's exactly the same as _affine! - - unsigned reset = (_affine != new_affine ? DrawingItem::STATE_ALL : 0); - - _affine = new_affine; + bool affine_changed = _drawing_affine != new_drawing_affine; + if (affine_changed) { + _drawing_affine = new_drawing_affine; + } - _drawing->update(Geom::IntRect::infinite(), _ctx.ctm, DrawingItem::STATE_ALL, reset); + _drawing->update(Geom::IntRect::infinite(), _drawing_affine, DrawingItem::STATE_ALL, affine_changed * DrawingItem::STATE_ALL); - Geom::OptIntRect bbox = _drawing->root()->drawbox(); - if (bbox) { - _bounds = *bbox; - _bounds.expandBy(1); // Avoid aliasing artifacts. - } + _bounds = expandedBy(_drawing->root()->drawbox(), 1); // Avoid aliasing artifacts // Todo: This should be managed elsewhere. if (_cursor) { @@ -113,7 +91,7 @@ void CanvasItemDrawing::update(Geom::Affine const &affine) if (_active_item != new_drawing_item) { GdkEventCrossing ec; - ec.window = _canvas->get_window()->gobj(); + ec.window = get_canvas()->get_window()->gobj(); ec.send_event = true; ec.subwindow = ec.window; ec.time = GDK_CURRENT_TIME; @@ -134,26 +112,15 @@ void CanvasItemDrawing::update(Geom::Affine const &affine) } } } - - _need_update = false; } /** * Render drawing to screen via Cairo. */ -void CanvasItemDrawing::render(Inkscape::CanvasItemBuffer *buf) +void CanvasItemDrawing::_render(Inkscape::CanvasItemBuffer &buf) { - if (!buf) { - std::cerr << "CanvasItemDrawing::Render: No buffer!" << std::endl; - return; - } - - if (buf->rect.hasZeroArea()) { - return; - } - - auto dc = Inkscape::DrawingContext(buf->cr->cobj(), buf->rect.min()); - _drawing->render(dc, buf->rect, buf->outline_pass * DrawingItem::RENDER_OUTLINE); + auto dc = Inkscape::DrawingContext(buf.cr->cobj(), buf.rect.min()); + _drawing->render(dc, buf.rect, buf.outline_pass * DrawingItem::RENDER_OUTLINE); } /** @@ -174,8 +141,6 @@ bool CanvasItemDrawing::handle_event(GdkEvent *event) /* TODO ... event -> arena transform? */ _c = Geom::Point(event->crossing.x, event->crossing.y); - /* fixme: Not sure abut this, but seems the right thing (Lauris) */ - //_drawing->update(Geom::IntRect::infinite(), _ctx, DrawingItem::STATE_PICK | DrawingItem::STATE_BBOX, 0); _active_item = _drawing->pick(_c, _drawing->cursorTolerance(), _sticky * DrawingItem::PICK_STICKY | _pick_outline * DrawingItem::PICK_OUTLINE); retval = _drawing_event_signal.emit(event, _active_item); } @@ -194,9 +159,6 @@ bool CanvasItemDrawing::handle_event(GdkEvent *event) /* TODO ... event -> arena transform? */ _c = Geom::Point(event->motion.x, event->motion.y); - /* fixme: Not sure abut this, but seems the right thing (Lauris) */ - //_drawing->update(Geom::IntRect::infinite(), _ctx, DrawingItem::STATE_PICK | DrawingItem::STATE_BBOX); - auto new_drawing_item = _drawing->pick(_c, _drawing->cursorTolerance(), _sticky * DrawingItem::PICK_STICKY | _pick_outline * DrawingItem::PICK_OUTLINE); if (_active_item != new_drawing_item) { diff --git a/src/display/control/canvas-item-drawing.h b/src/display/control/canvas-item-drawing.h index ad4891f233dffa29b4e9665cbe484d048c93a540..a4f6562bb3ee353230233f65f73192dd092c97ee 100644 --- a/src/display/control/canvas-item-drawing.h +++ b/src/display/control/canvas-item-drawing.h @@ -21,7 +21,6 @@ #include "canvas-item.h" -#include "display/drawing-item.h" // Only for ctx... which should be remove (it's the same as _affine!). namespace Inkscape { @@ -29,24 +28,15 @@ class Drawing; class DrawingItem; class Updatecontext; -class CanvasItemGroup; // A canvas control that contains other canvas controls. - -class CanvasItemDrawing : public CanvasItem +class CanvasItemDrawing final : public CanvasItem { public: CanvasItemDrawing(CanvasItemGroup *group); - // Geometry - UpdateContext get_context() { return _ctx; } // TODO Remove this as ctx only contains affine. - - void update(Geom::Affine const &affine) override; - double closest_distance_to(Geom::Point const &p); - // Selection bool contains(Geom::Point const &p, double tolerance = 0) override; // Display - void render(Inkscape::CanvasItemBuffer *buf) override; Inkscape::Drawing *get_drawing() { return _drawing.get(); } // Drawing items @@ -54,7 +44,7 @@ public: Inkscape::DrawingItem *get_active() { return _active_item; } // Events - bool handle_event(GdkEvent* event) override; + bool handle_event(GdkEvent *event) override; void set_sticky(bool sticky) { _sticky = sticky; } void set_pick_outline(bool pick_outline) { _pick_outline = pick_outline; } @@ -64,8 +54,10 @@ public: } protected: + ~CanvasItemDrawing() override = default; - // Geometry + void _update(bool propagate) override; + void _render(Inkscape::CanvasItemBuffer &buf) override; // Selection Geom::Point _c; @@ -75,7 +67,7 @@ protected: // Display std::unique_ptr _drawing; - Inkscape::UpdateContext _ctx; // TODO Remove this... it's the same as _affine! + Geom::Affine _drawing_affine; // Events bool _cursor = false; @@ -86,7 +78,6 @@ protected: sigc::signal _drawing_event_signal; }; - } // namespace Inkscape #endif // SEEN_CANVAS_ITEM_DRAWING_H diff --git a/src/display/control/canvas-item-enums.h b/src/display/control/canvas-item-enums.h index dee3a45eac19419d8f01c2779dbf1e169de0df4c..7e44158905d51bd0e1562deb81c1cba2af39b6ac 100644 --- a/src/display/control/canvas-item-enums.h +++ b/src/display/control/canvas-item-enums.h @@ -1,11 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-or-later -#ifndef SEEN_CANVAS_ITEM_ENUMS_H -#define SEEN_CANVAS_ITEM_ENUMS_H - /** - * Enums for CanvasControlItem's. + * @file + * Enums for CanvasItems. */ - /* * Author: * Tavmjong Bah @@ -13,6 +10,9 @@ * Copyright (C) 2020 Tavmjong Bah */ +#ifndef SEEN_CANVAS_ITEM_ENUMS_H +#define SEEN_CANVAS_ITEM_ENUMS_H + namespace Inkscape { enum CanvasItemColor { diff --git a/src/display/control/canvas-item-grid.cpp b/src/display/control/canvas-item-grid.cpp index 8c27100423fc27a4e46e7747360daba12bd49606..f3ad7233eff5b080691d25083d9801fa118b53b1 100644 --- a/src/display/control/canvas-item-grid.cpp +++ b/src/display/control/canvas-item-grid.cpp @@ -14,7 +14,7 @@ #include "canvas-item-grid.h" #include "color.h" -#include "ui/widget/canvas.h" +#include "helper/geom.h" enum Dim3 { X, Y, Z }; @@ -50,7 +50,12 @@ CanvasItemGrid::CanvasItemGrid(CanvasItemGroup *group) { _bounds = Geom::Rect(-Geom::infinity(), -Geom::infinity(), Geom::infinity(), Geom::infinity()); - request_update(); // Update affine + _no_emp_when_zoomed_out = Preferences::get()->getBool("/options/grids/no_emphasize_when_zoomedout"); + _pref_tracker = Preferences::PreferencesObserver::create("/options/grids/no_emphasize_when_zoomedout", [this] (auto &entry) { + set_no_emp_when_zoomed_out(entry.getBool()); + }); + + request_update(); } /** @@ -73,7 +78,7 @@ static double signed_distance(Geom::Point const &point, Geom::Line const &line) static std::vector intersect_line_rectangle(Geom::Line const &line, Geom::Rect const &rect) { std::vector intersections; - for (unsigned i = 0; i < 4; ++i) { + for (int i = 0; i < 4; ++i) { Geom::LineSegment side(rect.corner(i), rect.corner((i + 1) % 4)); try { if (auto oc = Geom::intersection(line, side)) { @@ -92,21 +97,21 @@ void CanvasItemGrid::set_origin(Geom::Point const &point) request_update(); } -void CanvasItemGrid::set_major_color(guint32 color) +void CanvasItemGrid::set_major_color(uint32_t color) { _major_color = color; request_update(); } -void CanvasItemGrid::set_minor_color(guint32 color) +void CanvasItemGrid::set_minor_color(uint32_t color) { _minor_color = color; request_update(); } -void CanvasItemGrid::set_dotted(bool b) +void CanvasItemGrid::set_dotted(bool dotted) { - _dotted = b; + _dotted = dotted; request_update(); } @@ -116,36 +121,38 @@ void CanvasItemGrid::set_spacing(Geom::Point const &point) request_update(); } -void CanvasItemGrid::set_major_line_interval(guint n) +void CanvasItemGrid::set_major_line_interval(int n) { if (n < 1) return; - _major_line_interval = n; request_update(); } +void CanvasItemGrid::set_no_emp_when_zoomed_out(bool noemp) +{ + if (_no_emp_when_zoomed_out != noemp) { + _no_emp_when_zoomed_out = noemp; + request_redraw(); + } +} + /** ====== Rectangular Grid ====== **/ CanvasItemGridXY::CanvasItemGridXY(Inkscape::CanvasItemGroup *group) : CanvasItemGrid(group) -{} - -void CanvasItemGridXY::update(Geom::Affine const &affine) { - if (_affine == affine && !_need_update) { - // Nothing to do. - return; - } - _affine = affine; - _need_update = false; + _name = "CanvasItemGridXY"; +} +void CanvasItemGridXY::_update(bool) +{ // Queue redraw of grid area - ow = _origin * affine; - sw[0] = Geom::Point(_spacing[0], 0) * affine.withoutTranslation(); - sw[1] = Geom::Point(0, _spacing[1]) * affine.withoutTranslation(); + ow = _origin * affine(); + 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++) { + for (int dim : {0, 1}) { int const scaling_factor = calculate_scaling_factor(sw[dim].length(), _major_line_interval); sw[dim] *= scaling_factor; scaled[dim] = scaling_factor > 1; @@ -154,79 +161,72 @@ void CanvasItemGridXY::update(Geom::Affine const &affine) request_redraw(); } -void CanvasItemGridXY::render(Inkscape::CanvasItemBuffer *buf) +void CanvasItemGridXY::_render(Inkscape::CanvasItemBuffer &buf) { - if (!buf) { - std::cerr << "CanvasItemGridXY::render: No buffer!" << std::endl; - return; - } - - if (!_visible) - return; - // no_emphasize_when_zoomedout determines color (minor or major) when only major grid lines/dots shown. - guint32 _empcolor = ( (scaled[Geom::X] || scaled[Geom::Y]) && _no_emp_when_zoomed_out ) ? _minor_color : _major_color; - guint32 _color = _minor_color; + uint32_t empcolor = ((scaled[Geom::X] || scaled[Geom::Y]) && _no_emp_when_zoomed_out) ? _minor_color : _major_color; + uint32_t color = _minor_color; - buf->cr->save(); - buf->cr->translate(-buf->rect.left(), -buf->rect.top()); - buf->cr->set_line_width(1.0); - buf->cr->set_line_cap(Cairo::LINE_CAP_SQUARE); + buf.cr->save(); + buf.cr->translate(-buf.rect.left(), -buf.rect.top()); + buf.cr->set_line_width(1.0); + buf.cr->set_line_cap(Cairo::LINE_CAP_SQUARE); - // Adding a 2 px margin to the buffer rectangle to avoid missing intersections (in case of rounding errors, and due to adding 0.5 below) - Geom::IntRect buf_rect_with_margin = buf->rect; - buf_rect_with_margin.expandBy(2); + // Add a 2px margin to the buffer rectangle to avoid missing intersections (in case of rounding errors, and due to adding 0.5 below) + auto const buf_rect_with_margin = expandedBy(buf.rect, 2); - for (unsigned dim = 0; dim < 2; ++dim) { + for (int dim : {0, 1}) { + int const nrm = dim ^ 0x1; // 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] ); + Geom::Line axis = Geom::Line::from_origin_and_vector(ow, sw[dim]); + Geom::Line orth = Geom::Line::from_origin_and_vector(ow, sw[nrm]); - double spacing = sw[(dim+1)%2].length(); // Spacing between grid lines. - double dash = sw[dim].length(); // Total length of dash pattern. + double spacing = sw[nrm].length(); // Spacing between grid lines. + double dash = sw[dim].length(); // Total length of dash pattern. // Find the minimum and maximum distances of the buffer corners from axis. double min = Geom::infinity(); double max = -Geom::infinity(); - for (unsigned c = 0; c < 4; ++c) { + for (int c = 0; c < 4; ++c) { // We need signed distance... lib2geom offers only positive distance. - double distance = signed_distance( buf_rect_with_margin.corner(c), axis ); + double distance = signed_distance(buf_rect_with_margin.corner(c), axis); // Correct it for coordinate flips (inverts handedness). - if (Geom::cross( axis.vector(), orth.vector() ) > 0 ) { + if (Geom::cross(axis.vector(), orth.vector()) > 0) { distance = -distance; } - if (distance < min) - min = distance; - if (distance > max) - max = distance; + min = std::min(min, distance); + max = std::max(max, distance); } - int start = floor( min/spacing ); - int stop = floor( max/spacing ); + int start = std::floor(min / spacing); + int stop = std::floor(max / spacing); // Loop over grid lines that intersected buf rectangle. - for (int j = start+1; j <= stop; ++j) { + for (int j = start + 1; j <= stop; ++j) { - Geom::Line grid_line = Geom::make_parallel_line( ow + j * sw[(dim+1)%2], axis ); + Geom::Line grid_line = Geom::make_parallel_line(ow + j * sw[nrm], axis); - std::vector x = intersect_line_rectangle( grid_line, buf_rect_with_margin ); + std::vector x = intersect_line_rectangle(grid_line, buf_rect_with_margin); // 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) { + if (Geom::dot(vector.vector(), axis.vector()) < 0.0) { std::swap(x[0], x[1]); } // Set up line. Need to use floor()+0.5 such that Cairo will draw us lines with a width of a single pixel, without any aliasing. // For this we need to position the lines at exactly half pixels, see https://www.cairographics.org/FAQ/#sharp_lines // Must be consistent with the pixel alignment of the guide lines, see CanvasItemGridXY::render(), and the drawing of the rulers - buf->cr->move_to(floor(x[0][Geom::X]) + 0.5, floor(x[0][Geom::Y]) + 0.5); - buf->cr->line_to(floor(x[1][Geom::X]) + 0.5, floor(x[1][Geom::Y]) + 0.5); + buf.cr->move_to(floor(x[0].x()) + 0.5, floor(x[0].y()) + 0.5); + buf.cr->line_to(floor(x[1].x()) + 0.5, floor(x[1].y()) + 0.5); + + // Determine whether to draw with the emphasis color. + bool const noemp = !scaled[dim] && j % _major_line_interval != 0; // Set dash pattern and color. if (_dotted) { @@ -234,58 +234,51 @@ void CanvasItemGridXY::render(Inkscape::CanvasItemBuffer *buf) // 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; + uint32_t _empdot = (empcolor & 0xff) << 2; if (_empdot > 0xff) _empdot = 0xff; - _empdot += (_empcolor & 0xffffff00); + _empdot += (empcolor & 0xffffff00); - guint32 _colordot = (_color & 0xff) << 2; + uint32_t _colordot = (color & 0xff) << 2; if (_colordot > 0xff) _colordot = 0xff; - _colordot += (_color & 0xffffff00); + _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 ) { + double offset = std::fmod(signed_distance(x[0], orth), sw[dim].length()); + if (Geom::cross(axis.vector(), orth.vector()) > 0) { offset = -offset; } std::vector dashes; - if (!scaled[dim] && (abs(j) % _major_line_interval) != 0) { + if (noemp) { // Minor lines dashes.push_back(1.0); dashes.push_back(dash - 1.0); offset -= 0.5; - buf->cr->set_source_rgba(SP_RGBA32_R_F(_colordot), SP_RGBA32_G_F(_colordot), - SP_RGBA32_B_F(_colordot), SP_RGBA32_A_F(_colordot)); + buf.cr->set_source_rgba(SP_RGBA32_R_F(_colordot), SP_RGBA32_G_F(_colordot), + SP_RGBA32_B_F(_colordot), SP_RGBA32_A_F(_colordot)); } else { // Major lines dashes.push_back(3.0); dashes.push_back(dash - 3.0); offset -= 1.5; // Center dash on intersection. - buf->cr->set_source_rgba(SP_RGBA32_R_F(_empdot), SP_RGBA32_G_F(_empdot), - SP_RGBA32_B_F(_empdot), SP_RGBA32_A_F(_empdot)); + buf.cr->set_source_rgba(SP_RGBA32_R_F(_empdot), SP_RGBA32_G_F(_empdot), + SP_RGBA32_B_F(_empdot), SP_RGBA32_A_F(_empdot)); } - buf->cr->set_line_cap(Cairo::LINE_CAP_BUTT); - buf->cr->set_dash(dashes, -offset); + buf.cr->set_line_cap(Cairo::LINE_CAP_BUTT); + buf.cr->set_dash(dashes, -offset); } else { - // Solid lines - - // Set color - if (!scaled[dim] && (abs(j) % _major_line_interval) != 0) { - buf->cr->set_source_rgba(SP_RGBA32_R_F(_color), SP_RGBA32_G_F(_color), - SP_RGBA32_B_F(_color), SP_RGBA32_A_F(_color)); - } else { - buf->cr->set_source_rgba(SP_RGBA32_R_F(_empcolor), SP_RGBA32_G_F(_empcolor), - SP_RGBA32_B_F(_empcolor), SP_RGBA32_A_F(_empcolor)); - } + uint32_t col = noemp ? color : empcolor; + buf.cr->set_source_rgba(SP_RGBA32_R_F(col), SP_RGBA32_G_F(col), + SP_RGBA32_B_F(col), SP_RGBA32_A_F(col)); } - buf->cr->stroke(); + buf.cr->stroke(); } else { std::cerr << "CanvasItemGridXY::render: Grid line doesn't intersect!" << std::endl; @@ -293,7 +286,7 @@ void CanvasItemGridXY::render(Inkscape::CanvasItemBuffer *buf) } } - buf->cr->restore(); + buf.cr->restore(); } /** ========= Axonometric Grids ======== */ @@ -307,6 +300,8 @@ void CanvasItemGridXY::render(Inkscape::CanvasItemBuffer *buf) CanvasItemGridAxonom::CanvasItemGridAxonom(Inkscape::CanvasItemGroup *group) : CanvasItemGrid(group) { + _name = "CanvasItemGridAxonom"; + angle_deg[X] = 30.0; angle_deg[Y] = 30.0; angle_deg[Z] = 0.0; @@ -315,22 +310,15 @@ CanvasItemGridAxonom::CanvasItemGridAxonom(Inkscape::CanvasItemGroup *group) angle_rad[Y] = Geom::rad_from_deg(angle_deg[Y]); angle_rad[Z] = Geom::rad_from_deg(angle_deg[Z]); - tan_angle[X] = tan(angle_rad[X]); - tan_angle[Y] = tan(angle_rad[Y]); - tan_angle[Z] = tan(angle_rad[Z]); + tan_angle[X] = std::tan(angle_rad[X]); + tan_angle[Y] = std::tan(angle_rad[Y]); + tan_angle[Z] = std::tan(angle_rad[Z]); } -void CanvasItemGridAxonom::update(Geom::Affine const &affine) +void CanvasItemGridAxonom::_update(bool) { - if (_affine == affine && !_need_update) { - // Nothing to do. - return; - } - _affine = affine; - _need_update = false; - - ow = _origin * affine; - lyw = _spacing.y() * affine.descrim(); + ow = _origin * affine(); + lyw = _spacing.y() * affine().descrim(); int const scaling_factor = calculate_scaling_factor(lyw, _major_line_interval); lyw *= scaling_factor; @@ -352,7 +340,7 @@ void CanvasItemGridAxonom::set_angle_x(double deg) { angle_deg[X] = std::clamp(deg, 0.0, 89.0); // setting to 90 and values close cause extreme slowdowns angle_rad[X] = Geom::rad_from_deg(angle_deg[X]); - tan_angle[X] = tan(angle_rad[X]); + tan_angle[X] = std::tan(angle_rad[X]); request_update(); } @@ -362,164 +350,140 @@ void CanvasItemGridAxonom::set_angle_z(double deg) { angle_deg[Z] = std::clamp(deg, 0.0, 89.0); // setting to 90 and values close cause extreme slowdowns angle_rad[Z] = Geom::rad_from_deg(angle_deg[Z]); - tan_angle[Z] = tan(angle_rad[Z]); + tan_angle[Z] = std::tan(angle_rad[Z]); request_update(); } -static void drawline(Inkscape::CanvasItemBuffer *buf, gint x0, gint y0, gint x1, gint y1, guint32 rgba) +static void drawline(Inkscape::CanvasItemBuffer &buf, int x0, int y0, int x1, int y1, uint32_t rgba) { - buf->cr->move_to(0.5 + x0, 0.5 + y0); - buf->cr->line_to(0.5 + x1, 0.5 + y1); - buf->cr->set_source_rgba(SP_RGBA32_R_F(rgba), SP_RGBA32_G_F(rgba), - SP_RGBA32_B_F(rgba), SP_RGBA32_A_F(rgba)); - buf->cr->stroke(); + buf.cr->move_to(0.5 + x0, 0.5 + y0); + buf.cr->line_to(0.5 + x1, 0.5 + y1); + buf.cr->set_source_rgba(SP_RGBA32_R_F(rgba), SP_RGBA32_G_F(rgba), + SP_RGBA32_B_F(rgba), SP_RGBA32_A_F(rgba)); + buf.cr->stroke(); } -static void vline(Inkscape::CanvasItemBuffer *buf, gint x, gint ys, gint ye, guint32 rgba) +static void vline(Inkscape::CanvasItemBuffer &buf, int x, int ys, int ye, uint32_t rgba) { - if ((x < buf->rect.left()) || (x >= buf->rect.right())) + if (x < buf.rect.left() || x >= buf.rect.right()) return; - buf->cr->move_to(0.5 + x, 0.5 + ys); - buf->cr->line_to(0.5 + x, 0.5 + ye); - buf->cr->set_source_rgba(SP_RGBA32_R_F(rgba), SP_RGBA32_G_F(rgba), - SP_RGBA32_B_F(rgba), SP_RGBA32_A_F(rgba)); - buf->cr->stroke(); + buf.cr->move_to(0.5 + x, 0.5 + ys); + buf.cr->line_to(0.5 + x, 0.5 + ye); + buf.cr->set_source_rgba(SP_RGBA32_R_F(rgba), SP_RGBA32_G_F(rgba), + SP_RGBA32_B_F(rgba), SP_RGBA32_A_F(rgba)); + buf.cr->stroke(); } /** * This function calls Cairo to render a line on a particular canvas buffer. * Coordinates are interpreted as SCREENcoordinates */ -void CanvasItemGridAxonom::render(Inkscape::CanvasItemBuffer *buf) +void CanvasItemGridAxonom::_render(Inkscape::CanvasItemBuffer &buf) { - if (!buf) { - std::cerr << "CanvasItemGridAxonom::render: No buffer!" << std::endl; - return; - } - - if (!_visible) - return; - - //set correct coloring, depending preference (when zoomed out, always major coloring or minor coloring) - guint32 _empcolor = (scaled && _no_emp_when_zoomed_out) ? _minor_color : _major_color; - guint32 _color = _minor_color; + // Set correct coloring, depending preference (when zoomed out, always major coloring or minor coloring) + uint32_t empcolor = (scaled && _no_emp_when_zoomed_out) ? _minor_color : _major_color; + uint32_t color = _minor_color; - buf->cr->save(); - buf->cr->translate(-buf->rect.left(), -buf->rect.top()); - buf->cr->set_line_width(1.0); - buf->cr->set_line_cap(Cairo::LINE_CAP_SQUARE); + buf.cr->save(); + buf.cr->translate(-buf.rect.left(), -buf.rect.top()); + buf.cr->set_line_width(1.0); + buf.cr->set_line_cap(Cairo::LINE_CAP_SQUARE); // gc = gridcoordinates (the coordinates calculated from the grids origin 'grid->ow'. - // sc = screencoordinates ( for example "buf->rect.left()" is in screencoordinates ) + // sc = screencoordinates ( for example "buf.rect.left()" is in screencoordinates ) // bc = buffer patch coordinates (x=0 on left side of page, y=0 on bottom of page) // tl = topleft - auto const buf_tl_gc = buf->rect.min() - ow; + auto const buf_tl_gc = buf.rect.min() - ow; // render the three separate line groups representing the main-axes // x-axis always goes from topleft to bottomright. (0,0) - (1,1) - gdouble const xintercept_y_bc = (buf_tl_gc[Geom::X] * tan_angle[X]) - buf_tl_gc[Geom::Y] ; - gdouble const xstart_y_sc = ( xintercept_y_bc - floor(xintercept_y_bc/lyw)*lyw ) + buf->rect.top(); - gint const xlinestart = round( (xstart_y_sc - buf_tl_gc[Geom::X]*tan_angle[X] - ow[Geom::Y]) / lyw ); - gint xlinenum = xlinestart; + double const xintercept_y_bc = (buf_tl_gc.x() * tan_angle[X]) - buf_tl_gc.y(); + double const xstart_y_sc = (xintercept_y_bc - std::floor(xintercept_y_bc / lyw) * lyw) + buf.rect.top(); + int const xlinestart = std::round((xstart_y_sc - buf_tl_gc.x() * tan_angle[X] - ow.y()) / lyw); + int xlinenum = xlinestart; // lines starting on left side. - - for (gdouble y = xstart_y_sc; y < buf->rect.bottom(); y += lyw, xlinenum++) { - gint const x0 = buf->rect.left(); - gint const y0 = round(y); - gint x1 = x0 + round( (buf->rect.bottom() - y) / tan_angle[X] ); - gint y1 = buf->rect.bottom(); - if ( Geom::are_near(tan_angle[X],0.) ) { - x1 = buf->rect.right(); + for (double y = xstart_y_sc; y < buf.rect.bottom(); y += lyw, xlinenum++) { + int const x0 = buf.rect.left(); + int const y0 = round(y); + int x1 = x0 + round((buf.rect.bottom() - y) / tan_angle[X]); + int y1 = buf.rect.bottom(); + if (Geom::are_near(tan_angle[X], 0)) { + x1 = buf.rect.right(); y1 = y0; } - if (!scaled && (abs(xlinenum) % _major_line_interval) != 0) { - drawline(buf, x0, y0, x1, y1, _color); - } else { - drawline(buf, x0, y0, x1, y1, _empcolor); - } + bool const noemp = !scaled && xlinenum % _major_line_interval != 0; + drawline(buf, x0, y0, x1, y1, noemp ? color : empcolor); } + // lines starting from top side - if (!Geom::are_near(tan_angle[X],0.)) - { - gdouble const xstart_x_sc = buf->rect.left() + (lxw_x - (xstart_y_sc - buf->rect.top()) / tan_angle[X]) ; + if (!Geom::are_near(tan_angle[X], 0)) { + double const xstart_x_sc = buf.rect.left() + (lxw_x - (xstart_y_sc - buf.rect.top()) / tan_angle[X]); xlinenum = xlinestart-1; - for (gdouble x = xstart_x_sc; x < buf->rect.right(); x += lxw_x, xlinenum--) { - gint const y0 = buf->rect.top(); - gint const y1 = buf->rect.bottom(); - gint const x0 = round(x); - gint const x1 = x0 + round( (y1 - y0) / tan_angle[X] ); - - if (!scaled && (abs(xlinenum) % _major_line_interval) != 0) { - drawline(buf, x0, y0, x1, y1, _color); - } else { - drawline(buf, x0, y0, x1, y1, _empcolor); - } + for (double x = xstart_x_sc; x < buf.rect.right(); x += lxw_x, xlinenum--) { + int const y0 = buf.rect.top(); + int const y1 = buf.rect.bottom(); + int const x0 = round(x); + int const x1 = x0 + round((y1 - y0) / tan_angle[X]); + + bool const noemp = !scaled && xlinenum % _major_line_interval != 0; + drawline(buf, x0, y0, x1, y1, noemp ? color : empcolor); } } // y-axis lines (vertical) - gdouble const ystart_x_sc = floor (buf_tl_gc[Geom::X] / spacing_ylines) * spacing_ylines + ow[Geom::X]; - gint const ylinestart = round((ystart_x_sc - ow[Geom::X]) / spacing_ylines); - gint ylinenum = ylinestart; - for (gdouble x = ystart_x_sc; x < buf->rect.right(); x += spacing_ylines, ylinenum++) { - gint const x0 = floor(x); // sp_grid_vline will add 0.5 again, so we'll pre-emptively use floor() + double const ystart_x_sc = floor (buf_tl_gc[Geom::X] / spacing_ylines) * spacing_ylines + ow[Geom::X]; + int const ylinestart = round((ystart_x_sc - ow[Geom::X]) / spacing_ylines); + int ylinenum = ylinestart; + for (double x = ystart_x_sc; x < buf.rect.right(); x += spacing_ylines, ylinenum++) { + int const x0 = floor(x); // sp_grid_vline will add 0.5 again, so we'll pre-emptively use floor() // instead of round() to avoid biasing the vertical lines to the right by half a pixel; see // CanvasItemGridXY::render() for more details - if (!scaled && (abs(ylinenum) % _major_line_interval) != 0) { - vline(buf, x0, buf->rect.top(), buf->rect.bottom() - 1, _color); - } else { - vline(buf, x0, buf->rect.top(), buf->rect.bottom() - 1, _empcolor); - } + bool const noemp = !scaled && ylinenum % _major_line_interval != 0; + vline(buf, x0, buf.rect.top(), buf.rect.bottom() - 1, noemp ? color : empcolor); } // z-axis always goes from bottomleft to topright. (0,1) - (1,0) - gdouble const zintercept_y_bc = (buf_tl_gc[Geom::X] * -tan_angle[Z]) - buf_tl_gc[Geom::Y] ; - gdouble const zstart_y_sc = ( zintercept_y_bc - floor(zintercept_y_bc/lyw)*lyw ) + buf->rect.top(); - gint const zlinestart = round( (zstart_y_sc + buf_tl_gc[Geom::X]*tan_angle[Z] - ow[Geom::Y]) / lyw ); - gint zlinenum = zlinestart; + double const zintercept_y_bc = (buf_tl_gc.x() * -tan_angle[Z]) - buf_tl_gc.y(); + double const zstart_y_sc = (zintercept_y_bc - std::floor(zintercept_y_bc / lyw) * lyw) + buf.rect.top(); + int const zlinestart = std::round((zstart_y_sc + buf_tl_gc.x() * tan_angle[Z] - ow.y()) / lyw); + int zlinenum = zlinestart; // lines starting from left side - gdouble next_y = zstart_y_sc; - for (gdouble y = zstart_y_sc; y < buf->rect.bottom(); y += lyw, zlinenum++, next_y = y) { - gint const x0 = buf->rect.left(); - gint const y0 = round(y); - gint x1 = x0 + round( (y - buf->rect.top() ) / tan_angle[Z] ); - gint y1 = buf->rect.top(); - if ( Geom::are_near(tan_angle[Z],0.) ) { - x1 = buf->rect.right(); + double next_y = zstart_y_sc; + for (double y = zstart_y_sc; y < buf.rect.bottom(); y += lyw, zlinenum++, next_y = y) { + int const x0 = buf.rect.left(); + int const y0 = round(y); + int x1 = x0 + round((y - buf.rect.top()) / tan_angle[Z]); + int y1 = buf.rect.top(); + if (Geom::are_near(tan_angle[Z], 0)) { + x1 = buf.rect.right(); y1 = y0; } - if (!scaled && (abs(zlinenum) % _major_line_interval) != 0) { - drawline(buf, x0, y0, x1, y1, _color); - } else { - drawline(buf, x0, y0, x1, y1, _empcolor); - } + bool const noemp = !scaled && zlinenum % _major_line_interval != 0; + drawline(buf, x0, y0, x1, y1, noemp ? color : empcolor); } + // draw lines from bottom-up - if (!Geom::are_near(tan_angle[Z],0.)) - { - gdouble const zstart_x_sc = buf->rect.left() + (next_y - buf->rect.bottom()) / tan_angle[Z] ; - for (gdouble x = zstart_x_sc; x < buf->rect.right(); x += lxw_z, zlinenum++) { - gint const y0 = buf->rect.bottom(); - gint const y1 = buf->rect.top(); - gint const x0 = round(x); - gint const x1 = x0 + round(buf->rect.height() / tan_angle[Z] ); - - if (!scaled && (abs(zlinenum) % _major_line_interval) != 0) { - drawline(buf, x0, y0, x1, y1, _color); - } else { - drawline(buf, x0, y0, x1, y1, _empcolor); - } + if (!Geom::are_near(tan_angle[Z], 0)) { + double const zstart_x_sc = buf.rect.left() + (next_y - buf.rect.bottom()) / tan_angle[Z]; + for (double x = zstart_x_sc; x < buf.rect.right(); x += lxw_z, zlinenum++) { + int const y0 = buf.rect.bottom(); + int const y1 = buf.rect.top(); + int const x0 = round(x); + int const x1 = x0 + round(buf.rect.height() / tan_angle[Z]); + + bool const noemp = !scaled && zlinenum % _major_line_interval != 0; + drawline(buf, x0, y0, x1, y1, noemp ? color : empcolor); } } - buf->cr->restore(); + buf.cr->restore(); } } // namespace Inkscape diff --git a/src/display/control/canvas-item-grid.h b/src/display/control/canvas-item-grid.h index 8b72564cf89b2c66935657035a407d698254a4b9..6ca3d0ae1d3c1516c1c9bcb2d1a853bfa1f4fc1b 100644 --- a/src/display/control/canvas-item-grid.h +++ b/src/display/control/canvas-item-grid.h @@ -23,56 +23,53 @@ uint32_t constexpr GRID_DEFAULT_MINOR_COLOR = 0x0099e526; namespace Inkscape { -class CanvasItemGroup; // A canvas control that contains other canvas controls. - -class CanvasItemGrid : public CanvasItem { - +class CanvasItemGrid : public CanvasItem +{ public: CanvasItemGrid(CanvasItemGroup *group); - CanvasItemGrid(CanvasItemGrid const &) = delete; - CanvasItemGrid &operator=(CanvasItemGrid const &) = delete; - - // Geometry - void update(Geom::Affine const &affine) override = 0; // Selection bool contains(Geom::Point const &p, double tolerance = 0) override; - // Display - void render(Inkscape::CanvasItemBuffer *buf) override = 0; - // Properties - void set_major_color(guint32 color); - void set_minor_color(guint32 color); + void set_major_color(uint32_t color); + void set_minor_color(uint32_t color); void set_origin(Geom::Point const &point); void set_spacing(Geom::Point const &point); void set_dotted(bool b); - void set_major_line_interval(guint n); + void set_major_line_interval(int n); + void set_no_emp_when_zoomed_out(bool noemp); protected: - Pref _no_emp_when_zoomed_out = Pref("/options/grids/no_emphasize_when_zoomedout"); + ~CanvasItemGrid() override = default; + bool _dotted; Geom::Point _origin; Geom::Point _spacing; /**< Spacing between elements of the grid */ - guint _major_line_interval; - guint32 _major_color; - guint32 _minor_color; + int _major_line_interval; + bool _no_emp_when_zoomed_out; + uint32_t _major_color; + uint32_t _minor_color; + +private: + std::unique_ptr _pref_tracker; }; /** Canvas Item for rectangular grids */ -class CanvasItemGridXY : public CanvasItemGrid { +class CanvasItemGridXY final : public CanvasItemGrid +{ public: - CanvasItemGridXY(Inkscape::CanvasItemGroup *group); - - void update(Geom::Affine const &affine) override; - void render(Inkscape::CanvasItemBuffer *buf) override; + CanvasItemGridXY(CanvasItemGroup *group); protected: friend class GridSnapperXY; + void _update(bool propagate) override; + void _render(CanvasItemBuffer &buf) override; + bool scaled[2]; /**< Whether the grid is in scaled mode, which can be different in the X or Y direction, hence two variables */ @@ -81,12 +78,10 @@ protected: }; /** Canvas Item for axonometric grids */ -class CanvasItemGridAxonom : public CanvasItemGrid { +class CanvasItemGridAxonom final : public CanvasItemGrid +{ public: - CanvasItemGridAxonom(Inkscape::CanvasItemGroup *group); - - void update(Geom::Affine const &affine) override; - void render(Inkscape::CanvasItemBuffer *buf) override; + CanvasItemGridAxonom(CanvasItemGroup *group); // Properties void set_angle_x(double value); @@ -95,6 +90,9 @@ public: protected: friend class GridSnapperAxonom; + void _update(bool propagate) override; + void _render(CanvasItemBuffer &buf) override; + bool scaled; /**< Whether the grid is in scaled mode */ double angle_deg[3]; /**< Angle of each axis (note that angle[2] == 0) */ diff --git a/src/display/control/canvas-item-group.cpp b/src/display/control/canvas-item-group.cpp index 67cca000c664a6efbdd9871e23b79dc738759a6e..62ab6485321016646d8e1222de2beea6c05bcabc 100644 --- a/src/display/control/canvas-item-group.cpp +++ b/src/display/control/canvas-item-group.cpp @@ -2,7 +2,6 @@ /** * A CanvasItem that contains other CanvasItem's. */ - /* * Author: * Tavmjong Bah @@ -14,8 +13,10 @@ * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ +#include #include "canvas-item-group.h" -#include "canvas-item-ctrl.h" // Update sizes + +constexpr bool DEBUG_LOGGING = false; namespace Inkscape { @@ -26,134 +27,85 @@ CanvasItemGroup::CanvasItemGroup(CanvasItemGroup *group) _pickable = true; // For now all groups are pickable... look into turning this off for some groups (e.g. temp). } -CanvasItemGroup::~CanvasItemGroup() +CanvasItemGroup::CanvasItemGroup(CanvasItemContext *context) + : CanvasItem(context) { - while (!items.empty()) { - CanvasItem & item = items.front(); - remove(&item); - } - - if (_parent) { - _parent->remove(this, false); // remove() should not delete this or we'll double delete! - } + _name = "CanvasItemGroup:Root"; + _pickable = true; // see above } -void CanvasItemGroup::add(CanvasItem *item) +CanvasItemGroup::~CanvasItemGroup() { -#ifdef CANVAS_ITEM_DEBUG - std::cout << "CanvasItemGroup::add: " << item->get_name() << " to " << _name << " " << items.size() << std::endl; -#endif - items.push_back(*item); - // canvas request update + items.clear_and_dispose([] (auto c) { delete c; }); } -void CanvasItemGroup::remove(CanvasItem *item, bool Delete) +void CanvasItemGroup::_update(bool propagate) { -#ifdef CANVAS_ITEM_DEBUG - std::cout << "CanvasItemGroup::remove: " << item->get_name() << " from " << _name << " " << items.size() << std::endl; -#endif - auto position = items.iterator_to(*item); - if (position != items.end()) { - position->set_parent(nullptr); - items.erase(position); - if (Delete) { - delete (&*position); // An item directly deleted should not be deleted here. - } + _bounds = {}; + + // Update all children and calculate new bounds. + for (auto &item : items) { + item.update(propagate); + _bounds |= item.get_bounds(); } } -void CanvasItemGroup::update(Geom::Affine const &affine) +void CanvasItemGroup::_mark_net_invisible() { - if (_affine == affine && !_need_update) { - // Nothing to do. + if (!_net_visible) { return; } - - _affine = affine; + _net_visible = false; _need_update = false; - - _bounds = Geom::Rect(); // Zero - - // Update all children and calculate new bounds. - for (auto & item : items) { - // We don't need to update what is not visible - if (!item.is_visible()) continue; - item.update(_affine); - _bounds.unionWith(item.get_bounds()); + for (auto &item : items) { + item._mark_net_invisible(); } + _bounds = {}; } -void CanvasItemGroup::visit_page_rects(std::function f) const +void CanvasItemGroup::visit_page_rects(std::function const &f) const { - for (auto & item : items) { + for (auto &item : items) { if (!item.is_visible()) continue; item.visit_page_rects(f); } } -void CanvasItemGroup::render(Inkscape::CanvasItemBuffer *buf) +void CanvasItemGroup::_render(Inkscape::CanvasItemBuffer &buf) { - if (_visible) { - if (_bounds.interiorIntersects(buf->rect)) { - for (auto & item : items) { - item.render(buf); - } - } + for (auto &item : items) { + item.render(buf); } } // Return last visible and pickable item that contains point. // SPCanvasGroup returned distance but it was not used. -CanvasItem* CanvasItemGroup::pick_item(Geom::Point& p) +CanvasItem *CanvasItemGroup::pick_item(Geom::Point const &p) { -#ifdef CANVAS_ITEM_DEBUG - std::cout << "CanvasItemGroup::pick_item:" << std::endl; - std::cout << " PICKING: In group: " << _name << " bounds: " << _bounds << std::endl; -#endif - for (auto item = items.rbegin(); item != items.rend(); ++item) { // C++20 will allow us to loop in reverse. -#ifdef CANVAS_ITEM_DEBUG - std::cout << " PICKING: Checking: " << item->get_name() << " bounds: " << item->get_bounds() << std::endl; -#endif - CanvasItem* picked_item = nullptr; - if (item->is_visible() && - item->is_pickable() && - item->contains(p) ) { - - auto group = dynamic_cast(&*item); - if (group) { - picked_item = group->pick_item(p); + if constexpr (DEBUG_LOGGING) { + std::cout << "CanvasItemGroup::pick_item:" << std::endl; + std::cout << " PICKING: In group: " << _name << " bounds: " << _bounds << std::endl; + } + + for (auto &item : boost::adaptors::reverse(items)) { + if constexpr (DEBUG_LOGGING) std::cout << " PICKING: Checking: " << item.get_name() << " bounds: " << item.get_bounds() << std::endl; + + if (item.is_visible() && item.is_pickable() && item.contains(p)) { + if (auto group = dynamic_cast(&item)) { + if (auto ret = group->pick_item(p)) { + return ret; + } } else { - picked_item = &*item; + return &item; } } - - if (picked_item != nullptr) { -#ifdef CANVAS_ITEM_DEBUG - std::cout << " PICKING: pick_item: " << picked_item->get_name() << std::endl; -#endif - return picked_item; - } } - return nullptr; + return nullptr; } -void CanvasItemGroup::update_canvas_item_ctrl_sizes(int size_index) -{ - for (auto & item : items) { - auto ctrl = dynamic_cast(&item); - if (ctrl) { - // We can't use set_size_default as the preference file is updated ->after<- the signal is emitted! - ctrl->set_size_via_index(size_index); - } - auto group = dynamic_cast(&item); - if (group) { - group->update_canvas_item_ctrl_sizes(size_index); - } - } -} +} // namespace Inkscape -} // Namespace Inkscape /* Local Variables: mode:c++ diff --git a/src/display/control/canvas-item-group.h b/src/display/control/canvas-item-group.h index 8ac061f1610343baac0340e6699c584ee204ebc3..712d95258dca047c93928c731325e3a39f580441 100644 --- a/src/display/control/canvas-item-group.h +++ b/src/display/control/canvas-item-group.h @@ -3,9 +3,8 @@ #define SEEN_CANVAS_ITEM_GROUP_H /** - * A CanvasItem that contains other CanvasItem's. + * A CanvasItem that contains other CanvasItems. */ - /* * Author: * Tavmjong Bah @@ -17,45 +16,43 @@ * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ -//#include <2geom/rect.h> -#include - #include "canvas-item.h" namespace Inkscape { -class CanvasItemGroup : public CanvasItem { - +class CanvasItemGroup final : public CanvasItem +{ public: - CanvasItemGroup(CanvasItemGroup* group = nullptr); - ~CanvasItemGroup() override; - - // Structure - void add(CanvasItem *item); - void remove(CanvasItem *item, bool Delete = true); + CanvasItemGroup(CanvasItemGroup *group); + CanvasItemGroup(CanvasItemContext *context); // Geometry - void update(Geom::Affine const &affine) override; - void visit_page_rects(std::function) const override; - - // Display - void render(Inkscape::CanvasItemBuffer *buf) override; + void visit_page_rects(std::function const &) const override; // Selection - CanvasItem* pick_item(Geom::Point &p); - CanvasItemList& get_items() { return items; } - - // Properties - void update_canvas_item_ctrl_sizes(int size_index); + CanvasItem *pick_item(Geom::Point const &p); protected: + friend class CanvasItem; // access to items + friend class CanvasItemContext; // access to destructor -private: -public: - // TODO: Make private (used in canvas-item.cpp). - CanvasItemList items; // Used to speed deletion. -}; + ~CanvasItemGroup() override; + void _update(bool propagate) override; + void _mark_net_invisible() override; + void _render(Inkscape::CanvasItemBuffer &buf) override; + + /** + * Type for linked list storing CanvasItems. + * Used to speed deletion when a group contains a large number of items (as in nodes for a complex path). + */ + using CanvasItemList = boost::intrusive::list< + Inkscape::CanvasItem, + boost::intrusive::member_hook, + &Inkscape::CanvasItem::member_hook>>; + + CanvasItemList items; +}; } // namespace Inkscape diff --git a/src/display/control/canvas-item-guideline.cpp b/src/display/control/canvas-item-guideline.cpp index f4be1c158145e092ea5001cd470c38934c643f0d..966ae69cf023dc636007d5b1e50d9b6d2120a3fb 100644 --- a/src/display/control/canvas-item-guideline.cpp +++ b/src/display/control/canvas-item-guideline.cpp @@ -14,14 +14,12 @@ * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ -#include "canvas-item-guideline.h" - #include <2geom/line.h> +#include "canvas-item-guideline.h" #include "canvas-item-ctrl.h" #include "desktop.h" // Canvas orientation so label is orientated correctly. - #include "ui/widget/canvas.h" namespace Inkscape { @@ -39,19 +37,17 @@ CanvasItemGuideLine::CanvasItemGuideLine(CanvasItemGroup *group, Glib::ustring l _name = "CanvasItemGuideLine:" + _label; _pickable = true; // For now, everybody gets events from this class! - // Required when rotating canvas: + // Required when rotating canvas _bounds = Geom::Rect(-Geom::infinity(), -Geom::infinity(), Geom::infinity(), Geom::infinity()); // Control to move guide line. - _origin_ctrl = std::make_unique(group, _origin, this); + _origin_ctrl = make_canvasitem(group, _origin, this); _origin_ctrl->set_name("CanvasItemGuideLine:Ctrl:" + _label); _origin_ctrl->set_size_default(); _origin_ctrl->set_pickable(true); // The handle will also react to dragging set_locked(false); // Init _origin_ctrl shape and stroke. } -CanvasItemGuideLine::~CanvasItemGuideLine() = default; - /** * Sets origin of guide line (place where handle is located). */ @@ -86,16 +82,14 @@ void CanvasItemGuideLine::set_inverted(bool inverted) } } - /** * Returns distance between point in canvas units and nearest point on guideLine. */ double CanvasItemGuideLine::closest_distance_to(Geom::Point const &p) { // Maybe store guide as a Geom::Line? - Geom::Line guide = - Geom::Line::from_origin_and_vector(_origin, Geom::rot90(_normal)); - guide *= _affine; + auto guide = Geom::Line::from_origin_and_vector(_origin, Geom::rot90(_normal)); + guide *= affine(); return Geom::distance(p, guide); } @@ -122,39 +116,20 @@ CanvasItemGuideHandle* CanvasItemGuideLine::dot() const /** * Update and redraw control guideLine. */ -void CanvasItemGuideLine::update(Geom::Affine const &affine) +void CanvasItemGuideLine::_update(bool) { - if (_affine == affine && !_need_update) { - // Nothing to do. - return; - } - - _affine = affine; - // Queue redraw of new area (and old too). request_redraw(); - - _need_update = false; } /** * Render guideLine to screen via Cairo. */ -void CanvasItemGuideLine::render(Inkscape::CanvasItemBuffer *buf) +void CanvasItemGuideLine::_render(Inkscape::CanvasItemBuffer &buf) { - if (!buf) { - std::cerr << "CanvasItemGuideLine::Render: No buffer!" << std::endl; - return; - } - - if (!_visible) { - // Hidden - return; - } - // Document to canvas - Geom::Point const normal = _normal * _affine.withoutTranslation(); // Direction only - Geom::Point const origin = _origin * _affine; + Geom::Point const normal = _normal * affine().withoutTranslation(); // Direction only + Geom::Point const origin = _origin * affine(); /* Need to use floor()+0.5 such that Cairo will draw us lines with a width of a single pixel, * without any aliasing. For this we need to position the lines at exactly half pixels, see @@ -167,9 +142,9 @@ void CanvasItemGuideLine::render(Inkscape::CanvasItemBuffer *buf) Geom::Point const aligned_origin = origin.floor() + Geom::Point(0.5, 0.5); // Set up the Cairo rendering context - auto ctx = buf->cr; + auto ctx = buf.cr; ctx->save(); - ctx->translate(-buf->rect.left(), -buf->rect.top()); // Canvas to screen + ctx->translate(-buf.rect.left(), -buf.rect.top()); // Canvas to screen ctx->set_source_rgba(SP_RGBA32_R_F(_stroke), SP_RGBA32_G_F(_stroke), SP_RGBA32_B_F(_stroke), SP_RGBA32_A_F(_stroke)); ctx->set_line_width(1); @@ -183,10 +158,7 @@ void CanvasItemGuideLine::render(Inkscape::CanvasItemBuffer *buf) ctx->save(); ctx->translate(aligned_origin.x(), aligned_origin.y()); - SPDesktop *desktop = nullptr; - if (_canvas) { - desktop = _canvas->get_desktop(); - } + auto desktop = get_canvas()->get_desktop(); ctx->rotate(atan2(normal.cw()) + M_PI * (desktop && desktop->is_yaxisdown() ? 1 : 0)); ctx->translate(0, -(_origin_ctrl->radius() + LABEL_SEP)); // Offset by dot radius + 2 ctx->move_to(0, 0); @@ -201,13 +173,13 @@ void CanvasItemGuideLine::render(Inkscape::CanvasItemBuffer *buf) if (Geom::are_near(normal.y(), 0.0)) { // Vertical double const position = aligned_origin.x(); - ctx->move_to(position, buf->rect.top() + 0.5); - ctx->line_to(position, buf->rect.bottom() - 0.5); + ctx->move_to(position, buf.rect.top() + 0.5); + ctx->line_to(position, buf.rect.bottom() - 0.5); } else if (Geom::are_near(normal.x(), 0.0)) { // Horizontal double position = aligned_origin.y(); - ctx->move_to(buf->rect.left() + 0.5, position); - ctx->line_to(buf->rect.right() - 0.5, position); + ctx->move_to(buf.rect.left() + 0.5, position); + ctx->line_to(buf.rect.right() - 0.5, position); } else { // Angled Geom::Line line = Geom::Line::from_origin_and_vector(aligned_origin, Geom::rot90(normal)); @@ -215,13 +187,13 @@ void CanvasItemGuideLine::render(Inkscape::CanvasItemBuffer *buf) // Find intersections of the line with buf rectangle. There should be zero or two. std::vector intersections; for (unsigned i = 0; i < 4; ++i) { - Geom::LineSegment side(buf->rect.corner(i), buf->rect.corner((i+1)%4)); + Geom::LineSegment side(buf.rect.corner(i), buf.rect.corner((i+1)%4)); try { Geom::OptCrossing oc = Geom::intersection(line, side); if (oc) { - intersections.push_back(line.pointAt((*oc).ta)); + intersections.push_back(line.pointAt(oc->ta)); } - } catch (Geom::InfiniteSolutions) { + } catch (Geom::InfiniteSolutions const &) { // Shouldn't happen as we have already taken care of horizontal/vertical guides. std::cerr << "CanvasItemGuideLine::render: Error: Infinite intersections." << std::endl; } @@ -241,19 +213,13 @@ void CanvasItemGuideLine::render(Inkscape::CanvasItemBuffer *buf) ctx->restore(); } -void CanvasItemGuideLine::hide() -{ - CanvasItem::hide(); - _origin_ctrl->hide(); -} - -void CanvasItemGuideLine::show() +void CanvasItemGuideLine::set_visible(bool visible) { - CanvasItem::show(); - _origin_ctrl->show(); + CanvasItem::set_visible(visible); + _origin_ctrl->set_visible(visible); } -void CanvasItemGuideLine::set_stroke(guint32 color) +void CanvasItemGuideLine::set_stroke(uint32_t color) { // Make sure the fill of the control is the same as the stroke // of the guide-line: @@ -261,10 +227,10 @@ void CanvasItemGuideLine::set_stroke(guint32 color) CanvasItem::set_stroke(color); } -void CanvasItemGuideLine::set_label(Glib::ustring const & label) +void CanvasItemGuideLine::set_label(Glib::ustring &&label) { if (_label != label) { - _label = label; + _label = std::move(label); request_update(); } } diff --git a/src/display/control/canvas-item-guideline.h b/src/display/control/canvas-item-guideline.h index af22e4e49a7c7c14103428970aefaa7b995ba57b..ebc6a0b87e01954b15257426deb7bacab48522b4 100644 --- a/src/display/control/canvas-item-guideline.h +++ b/src/display/control/canvas-item-guideline.h @@ -24,73 +24,68 @@ #include "canvas-item.h" #include "canvas-item-ctrl.h" +#include "canvas-item-ptr.h" namespace Inkscape { -class CanvasItemGroup; // A canvas control that contains other canvas controls. -class CanvasItemGuideHandle; // A handle ("dot") serving as draggable origin control - -class CanvasItemGuideLine : public CanvasItem { +class CanvasItemGuideHandle; +class CanvasItemGuideLine final : public CanvasItem +{ public: - CanvasItemGuideLine(CanvasItemGroup *group, Glib::ustring label, - Geom::Point const &origin, Geom::Point const &normal); - ~CanvasItemGuideLine() override; + CanvasItemGuideLine(CanvasItemGroup *group, Glib::ustring label, Geom::Point const &origin, Geom::Point const &normal); // Geometry void set_origin(Geom::Point const &origin); void set_normal(Geom::Point const &normal); - bool is_horizontal() const { return (_normal.x() == 0.0); } - bool is_vertical() const { return (_normal.y() == 0.0); } - void update(Geom::Affine const &affine) override; double closest_distance_to(Geom::Point const &p); // Selection bool contains(Geom::Point const &p, double tolerance = 0) override; - // Display - void render(Inkscape::CanvasItemBuffer *buf) override; - // Properties - void hide() override; - void show() override; - void set_stroke(guint32 color) final; - void set_label(Glib::ustring const & label); + void set_visible(bool visible) override; + void set_stroke(uint32_t color) override; + void set_label(Glib::ustring &&label); void set_locked(bool locked); void set_inverted(bool inverted); - void set_sensitive(bool sensitive) { _sensitive = sensitive; } // Getters - CanvasItemGuideHandle* dot() const; + CanvasItemGuideHandle *dot() const; protected: + ~CanvasItemGuideLine() override = default; + + void _update(bool propagate) override; + void _render(Inkscape::CanvasItemBuffer &buf) override; + Geom::Point _origin; - Geom::Point _normal = Geom::Point(0,1); + Geom::Point _normal = Geom::Point(0, 1); Glib::ustring _label; bool _locked = true; // Flipped in constructor to trigger init of _origin_ctrl. bool _inverted = false; - bool _sensitive = false; - std::unique_ptr _origin_ctrl; + CanvasItemPtr _origin_ctrl; -private: - inline static guint32 const CONTROL_LOCKED_COLOR = 0x00000080; // RGBA black semitranslucent - inline static double const LABEL_SEP = 2.0; // Distance between the label and the origin control + static constexpr uint32_t CONTROL_LOCKED_COLOR = 0x00000080; // RGBA black semitranslucent + static constexpr double LABEL_SEP = 2.0; // Distance between the label and the origin control }; - -class CanvasItemGuideHandle : public CanvasItemCtrl { - +// A handle ("dot") serving as draggable origin control +class CanvasItemGuideHandle final : public CanvasItemCtrl +{ public: CanvasItemGuideHandle(CanvasItemGroup *group, Geom::Point const &pos, CanvasItemGuideLine *line); double radius() const; - void set_size_via_index(int index) final; + void set_size_via_index(int index) override; + +protected: + ~CanvasItemGuideHandle() override = default; -private: CanvasItemGuideLine *_my_line; // The guide line we belong to // static data - inline static double const SCALE = 0.55; // handle size relative to an auto-smooth node - inline static unsigned const MINIMUM_SIZE = 7; // smallest handle size, must be an odd int + static constexpr double SCALE = 0.55; // handle size relative to an auto-smooth node + static constexpr unsigned MINIMUM_SIZE = 7; // smallest handle size, must be an odd int }; } // namespace Inkscape diff --git a/src/display/control/canvas-item-ptr.h b/src/display/control/canvas-item-ptr.h new file mode 100644 index 0000000000000000000000000000000000000000..b8c198cd6e6a40dc16d2adc63f3dfbc90595bbd0 --- /dev/null +++ b/src/display/control/canvas-item-ptr.h @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#ifndef SEEN_CANVAS_ITEM_PTR_H +#define SEEN_CANVAS_ITEM_PTR_H + +/* + * An entirely analogous file to display/drawing-item-ptr.h. + */ + +#include +#include + +namespace Inkscape { class CanvasItem; } + +/// Deleter object which calls the unlink() method of CanvasItem. +struct CanvasItemUnlinkDeleter +{ + template + void operator()(T *t) + { + static_assert(std::is_base_of_v); + t->unlink(); + } +}; + +/// Smart pointer used to hold CanvasItems, like std::unique_ptr. +template +using CanvasItemPtr = std::unique_ptr; + +/// Convienence function to create a CanvasItemPtr, like std::make_unique. +template +auto make_canvasitem(Args&&... args) +{ + return CanvasItemPtr(new T(std::forward(args)...)); +}; + +#endif // SEEN_CANVAS_ITEM_PTR_H diff --git a/src/display/control/canvas-item-quad.cpp b/src/display/control/canvas-item-quad.cpp index 4a437770425a587f581b63a7df2e06deb5fb9949..f02fffc76967c06cd6059eb9d0607b7d3d12c70e 100644 --- a/src/display/control/canvas-item-quad.cpp +++ b/src/display/control/canvas-item-quad.cpp @@ -14,11 +14,12 @@ * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ +#include + #include "canvas-item-quad.h" #include "color.h" // SP_RGBA_x_F - -#include "ui/widget/canvas.h" +#include "helper/geom.h" namespace Inkscape { @@ -29,11 +30,10 @@ 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. + * Create a control quad. Points are in document coordinates. */ CanvasItemQuad::CanvasItemQuad(CanvasItemGroup *group, Geom::Point const &p0, Geom::Point const &p1, @@ -45,9 +45,6 @@ CanvasItemQuad::CanvasItemQuad(CanvasItemGroup *group, , _p3(p3) { _name = "CanvasItemQuad"; - _pickable = false; // For now, nobody gets events from this class! - - request_update(); } /** @@ -63,16 +60,6 @@ void CanvasItemQuad::set_coords(Geom::Point const &p0, Geom::Point const &p1, Ge 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. */ @@ -82,10 +69,10 @@ bool CanvasItemQuad::contains(Geom::Point const &p, double tolerance) 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; + 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 @@ -98,101 +85,65 @@ bool CanvasItemQuad::contains(Geom::Point const &p, double tolerance) /** * Update and redraw control quad. */ -void CanvasItemQuad::update(Geom::Affine const &affine) +void CanvasItemQuad::_update(bool) { - if (_affine == affine && !_need_update) { - // Nothing to do. - return; - } - - if (_p0 == _p1 || - _p1 == _p2 || - _p2 == _p3 || - _p3 == _p0) { + if (_p0 == _p1 || _p1 == _p2 || _p2 == _p3 || _p3 == _p0) { + _bounds = {}; 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; + // and recreated when a node is moved! But keep it in case we change that. + + _bounds = expandedBy(bounds_of(_p0, _p1, _p2, _p3) * affine(), 2); // Room for anti-aliasing effects. // Queue redraw of new area request_redraw(); - - _need_update = false; } /** * Render quad to screen via Cairo. */ -void CanvasItemQuad::render(Inkscape::CanvasItemBuffer *buf) +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; + 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()); + 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->save(); - buf->cr->begin_new_path(); + 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->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(); if (_inverted) { - cairo_set_operator(buf->cr->cobj(), CAIRO_OPERATOR_DIFFERENCE); + cairo_set_operator(buf.cr->cobj(), CAIRO_OPERATOR_DIFFERENCE); } - 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_preserve(); + 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_preserve(); - buf->cr->set_line_width(1); - buf->cr->set_source_rgba(SP_RGBA32_R_F(_stroke), SP_RGBA32_G_F(_stroke), - SP_RGBA32_B_F(_stroke), SP_RGBA32_A_F(_stroke)); - buf->cr->stroke_preserve(); - buf->cr->begin_new_path(); + buf.cr->set_line_width(1); + buf.cr->set_source_rgba(SP_RGBA32_R_F(_stroke), SP_RGBA32_G_F(_stroke), + SP_RGBA32_B_F(_stroke), SP_RGBA32_A_F(_stroke)); + buf.cr->stroke_preserve(); + buf.cr->begin_new_path(); - buf->cr->restore(); + buf.cr->restore(); } void CanvasItemQuad::set_inverted(bool inverted) diff --git a/src/display/control/canvas-item-quad.h b/src/display/control/canvas-item-quad.h index fc763442c9a0733fbcd51117d1d5f3c58d4785f7..19f9fdf1e44edd97d6aa6cda8c049c2e98498341 100644 --- a/src/display/control/canvas-item-quad.h +++ b/src/display/control/canvas-item-quad.h @@ -24,10 +24,8 @@ namespace Inkscape { -class CanvasItemGroup; // A canvas control that contains other canvas controls. - -class CanvasItemQuad : public CanvasItem { - +class CanvasItemQuad final : public CanvasItem +{ public: CanvasItemQuad(CanvasItemGroup *group); CanvasItemQuad(CanvasItemGroup *group, Geom::Point const &p0, Geom::Point const &p1, @@ -36,18 +34,17 @@ public: // Geometry void set_coords(Geom::Point const &p0, Geom::Point const &p1, Geom::Point const &p2, Geom::Point const &p3); - void update(Geom::Affine const &affine) override; - double closest_distance_to(Geom::Point const &p); // Maybe not needed - // Selection bool contains(Geom::Point const &p, double tolerance = 0) override; - // Display - void render(Inkscape::CanvasItemBuffer *buf) override; - void set_inverted(bool inverted); protected: + ~CanvasItemQuad() override = default; + + void _update(bool propagate) override; + void _render(Inkscape::CanvasItemBuffer &buf) override; + Geom::Point _p0; Geom::Point _p1; Geom::Point _p2; @@ -56,7 +53,6 @@ protected: bool _inverted = false; }; - } // namespace Inkscape #endif // SEEN_CANVAS_ITEM_QUAD_H diff --git a/src/display/control/canvas-item-rect.cpp b/src/display/control/canvas-item-rect.cpp index 7518369a97148a88a8c0b69314f8e1aba6590160..d821087621b818e55d1870368d9eefc7b785cdd1 100644 --- a/src/display/control/canvas-item-rect.cpp +++ b/src/display/control/canvas-item-rect.cpp @@ -17,10 +17,11 @@ #include #include "canvas-item-rect.h" -#include "display/cairo-utils.h" +#include "display/cairo-utils.h" #include "color.h" // SP_RGBA_x_F -#include "inkscape.h" // +#include "helper/geom.h" +#include "inkscape.h" #include "ui/util.h" #include "ui/widget/canvas.h" @@ -33,7 +34,6 @@ CanvasItemRect::CanvasItemRect(CanvasItemGroup *group) : CanvasItem(group) { _name = "CanvasItemRect:Null"; - _pickable = false; // For now, nobody gets events from this class! } /** @@ -44,8 +44,6 @@ CanvasItemRect::CanvasItemRect(CanvasItemGroup *group, Geom::Rect const &rect) , _rect(rect) { _name = "CanvasItemRect"; - _pickable = false; // For now, nobody gets events from this class! - request_update(); } /** @@ -60,25 +58,11 @@ void CanvasItemRect::set_rect(Geom::Rect const &rect) /** * Run a callback for each rectangle that should be filled and painted in the background. */ -void CanvasItemRect::visit_page_rects(std::function f) const +void CanvasItemRect::visit_page_rects(std::function const &f) const { - if (_is_page && _fill != 0) f(_rect); -} - -/** - * Returns distance between point in canvas units and nearest point in rect (zero if inside rect). - * Only valid if canvas is not rotated. (A rotated Geom::Rect yields a new axis-aligned Geom::Rect - * that contains the original rectangle; not a rotated rectangle.) - */ -double CanvasItemRect::closest_distance_to(Geom::Point const &p) -{ - if (_affine.isNonzeroRotation()) { - std::cerr << "CanvasItemRect::closest_distance_to: Affine includes rotation!" << std::endl; + if (_is_page && _fill != 0) { + f(_rect); } - - Geom::Rect rect = _rect; - rect *= _affine; // Convert from document to canvas coordinates. (TODO Cache this.) - return Geom::distance(p, rect); } /** @@ -91,174 +75,114 @@ bool CanvasItemRect::contains(Geom::Point const &p, double tolerance) std::cerr << "CanvasItemRect::contains: Non-zero tolerance not implemented!" << std::endl; } - Geom::Point p0 = _rect.corner(0) * _affine; - Geom::Point p1 = _rect.corner(1) * _affine; - Geom::Point p2 = _rect.corner(2) * _affine; - Geom::Point p3 = _rect.corner(3) * _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; + return _rect.contains(p * affine().inverse()); } /** * Update and redraw control rect. */ -void CanvasItemRect::update(Geom::Affine const &affine) +void CanvasItemRect::_update(bool) { - if (_affine == affine && !_need_update) { - // Nothing to do. - return; - } - - if (_rect.area() == 0) { + if (_rect.hasZeroArea()) { + _bounds = {}; return; // Nothing to show } // Queue redraw of old area (erase previous content). request_redraw(); - // Get new bounds - _affine = affine; - // Enlarge bbox by twice shadow size (to allow for shadow on any side with a 45deg rotation). _bounds = _rect; // note: add shadow size before applying transformation, since get_shadow_size accounts for scale - _bounds.expandBy(2 * get_shadow_size()); - _bounds *= _affine; - _bounds.expandBy(2); // Room for stroke. + if (_shadow_width > 0 && !_dashed) { + _bounds->expandBy(2 * get_shadow_size()); + } + *_bounds *= affine(); + _bounds->expandBy(2); // Room for stroke. // Queue redraw of new area request_redraw(); - - _need_update = false; } /** * Render rect to screen via Cairo. */ -void CanvasItemRect::render(Inkscape::CanvasItemBuffer *buf) +void CanvasItemRect::_render(Inkscape::CanvasItemBuffer &buf) { - if (!buf) { - std::cerr << "CanvasItemRect::Render: No buffer!" << std::endl; - return; - } - - if (!_bounds.intersects(buf->rect)) { - return; // Rectangle not inside buffer rectangle. - } - - if (!_visible) { - // Hidden - return; - } - - // Geom::Rect is an axis-aligned rectangle. We need to rotate it if the canvas is rotated! - - // 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 into window coordinates. - Geom::Point rect_transformed[4]; - for (unsigned int i = 0; i < 4; ++i) { - rect_transformed[i] = _rect.corner(i) * _affine; - } + auto const &aff = affine(); + bool const axis_aligned = (Geom::are_near(aff[1], 0) && Geom::are_near(aff[2], 0)) + || (Geom::are_near(aff[0], 0) && Geom::are_near(aff[3], 0)); + // If so, then snap the rectangle to the pixel grid. auto rect = _rect; - - using Geom::X; - using Geom::Y; - if (axis_aligned) { - auto temp = _rect * _affine; - auto min = temp.min(); - auto max = temp.max(); - auto pixgrid = Geom::Rect( - Geom::Point(floor(min[X]) + 0.5, floor(min[Y]) + 0.5), - Geom::Point(floor(max[X]) + 0.5, floor(max[Y]) + 0.5)); - rect = pixgrid * _affine.inverse(); + rect = (floor(_rect * aff) + Geom::Point(0.5, 0.5)) * aff.inverse(); } - buf->cr->save(); - buf->cr->translate(-buf->rect.left(), -buf->rect.top()); + buf.cr->save(); + buf.cr->translate(-buf.rect.left(), -buf.rect.top()); if (_inverted) { - // buf->cr->set_operator(Cairo::OPERATOR_XOR); // Blend mode operators do not have C++ bindings! - cairo_set_operator(buf->cr->cobj(), CAIRO_OPERATOR_DIFFERENCE); + buf.cr->set_operator(Cairo::OPERATOR_XOR); } - // Draw shadow first. Shadow extends under rectangle to reduce aliasing effects. - if (_shadow_width > 0 && !_dashed && !(_is_page && _canvas->get_opengl_enabled())) { - // there's only one UI knob to adjust border and shadow color, so instead of using border color - // transparency as is, it is boosted by this function, since shadow attenuates it - const auto a = (exp(-3 * SP_RGBA32_A_F(_shadow_color)) - 1) / (exp(-3) - 1); - buf->cr->save(); - - auto affine = _affine; - if (auto desktop = _canvas->get_desktop()) { - rect *= desktop->doc2dt(); - affine = desktop->doc2dt() * affine; + // Draw shadow first. Shadow extends under rectangle to reduce aliasing effects. Canvas draws page shadows in OpenGL mode. + if (_shadow_width > 0 && !_dashed && !(_is_page && get_canvas()->get_opengl_enabled())) { + // There's only one UI knob to adjust border and shadow color, so instead of using border color + // transparency as is, it is boosted by this function, since shadow attenuates it. + auto const alpha = (std::exp(-3 * SP_RGBA32_A_F(_shadow_color)) - 1) / (std::exp(-3) - 1); + + // Flip shadow upside-down if y-axis is inverted. + auto doc2dt = Geom::identity(); + if (auto desktop = get_canvas()->get_desktop()) { + doc2dt = desktop->doc2dt(); } - buf->cr->transform(geom_to_cairo(affine)); - ink_cairo_draw_drop_shadow(buf->cr, rect, get_shadow_size(), _shadow_color, a); - buf->cr->restore(); + + buf.cr->save(); + buf.cr->transform(geom_to_cairo(doc2dt * aff)); + ink_cairo_draw_drop_shadow(buf.cr, rect * doc2dt, get_shadow_size(), _shadow_color, alpha); + buf.cr->restore(); } - // Setup rectangle path - if (axis_aligned) { - // Snap to pixel grid - Geom::Rect outline( _rect.min() * _affine, _rect.max() * _affine); - buf->cr->rectangle(floor(outline.min()[X])+0.5, - floor(outline.min()[Y])+0.5, - floor(outline.max()[X]) - floor(outline.min()[X]), - floor(outline.max()[Y]) - floor(outline.min()[Y])); - } else { - - // Rotated - buf->cr->move_to(rect_transformed[0][X], rect_transformed[0][Y] ); - buf->cr->line_to(rect_transformed[1][X], rect_transformed[1][Y] ); - buf->cr->line_to(rect_transformed[2][X], rect_transformed[2][Y] ); - buf->cr->line_to(rect_transformed[3][X], rect_transformed[3][Y] ); - buf->cr->close_path(); + // Get the points we need transformed into window coordinates. + buf.cr->begin_new_path(); + for (int i = 0; i < 4; ++i) { + auto pt = rect.corner(i) * aff; + buf.cr->line_to(pt.x(), pt.y()); } + buf.cr->close_path(); + + // Draw border. static std::valarray dashes = {4.0, 4.0}; if (_dashed) { - buf->cr->set_dash(dashes, -0.5); + buf.cr->set_dash(dashes, -0.5); } - // Draw border (stroke). - buf->cr->set_line_width(1); + buf.cr->set_line_width(1); // we maybe have painted the background, back to "normal" compositing - - buf->cr->set_source_rgba(SP_RGBA32_R_F(_stroke), SP_RGBA32_G_F(_stroke), - SP_RGBA32_B_F(_stroke), SP_RGBA32_A_F(_stroke)); - buf->cr->stroke_preserve(); + buf.cr->set_source_rgba(SP_RGBA32_R_F(_stroke), SP_RGBA32_G_F(_stroke), + SP_RGBA32_B_F(_stroke), SP_RGBA32_A_F(_stroke)); + buf.cr->stroke_preserve(); // Highlight the border by drawing it in _shadow_color. if (_shadow_width == 1 && _dashed) { - buf->cr->set_dash(dashes, 3.5); // Dash offset by dash length. - buf->cr->set_source_rgba(SP_RGBA32_R_F(_shadow_color), SP_RGBA32_G_F(_shadow_color), - SP_RGBA32_B_F(_shadow_color), SP_RGBA32_A_F(_shadow_color)); - buf->cr->stroke_preserve(); + buf.cr->set_dash(dashes, 3.5); // Dash offset by dash length. + buf.cr->set_source_rgba(SP_RGBA32_R_F(_shadow_color), SP_RGBA32_G_F(_shadow_color), + SP_RGBA32_B_F(_shadow_color), SP_RGBA32_A_F(_shadow_color)); + buf.cr->stroke_preserve(); } - buf->cr->begin_new_path(); // Clear path or get weird artifacts. + buf.cr->begin_new_path(); // Clear path or get weird artifacts. // Uncomment to show bounds // Geom::Rect bounds = _bounds; // bounds.expandBy(-1); - // bounds -= buf->rect.min(); - // buf->cr->set_source_rgba(1.0, 0.0, _shadow_width / 3.0, 1.0); - // buf->cr->rectangle(bounds.min().x(), bounds.min().y(), bounds.width(), bounds.height()); - // buf->cr->stroke(); + // bounds -= buf.rect.min(); + // buf.cr->set_source_rgba(1.0, 0.0, _shadow_width / 3.0, 1.0); + // buf.cr->rectangle(bounds.min().x(), bounds.min().y(), bounds.width(), bounds.height()); + // buf.cr->stroke(); - buf->cr->restore(); + buf.cr->restore(); } void CanvasItemRect::set_is_page(bool is_page) @@ -269,10 +193,10 @@ void CanvasItemRect::set_is_page(bool is_page) } } -void CanvasItemRect::set_fill(guint32 color) +void CanvasItemRect::set_fill(uint32_t fill) { - if (color != _fill && _is_page) _canvas->set_page(color); - CanvasItem::set_fill(color); + if (fill != _fill && _is_page) get_canvas()->set_page(fill); + CanvasItem::set_fill(fill); } void CanvasItemRect::set_dashed(bool dashed) @@ -291,29 +215,29 @@ void CanvasItemRect::set_inverted(bool inverted) } } -void CanvasItemRect::set_shadow(guint32 color, int width) +void CanvasItemRect::set_shadow(uint32_t color, int width) { if (_shadow_color != color || _shadow_width != width) { _shadow_color = color; _shadow_width = width; request_redraw(); - if (_is_page) _canvas->set_border(_shadow_width > 0 ? color : 0x0); + if (_is_page) get_canvas()->set_border(_shadow_width > 0 ? color : 0x0); } } -double CanvasItemRect::get_shadow_size() const { +double CanvasItemRect::get_shadow_size() const +{ // gradient drop shadow needs much more room than solid one, so inflating the size; // fudge factor of 6 used to make sizes baked in svg documents work as steps: // typical value of 2 will work out to 12 pixels which is a narrow shadow (b/c of exponential fall of) auto size = _shadow_width * 6; if (size < 0) { size = 0; - } - else if (size > 120) { + } else if (size > 120) { // arbitrarily selected max size, so Cairo gradient doesn't blow up if document has bogus shadow values size = 120; } - auto scale = get_scale(); + auto scale = affine().descrim(); // calculate space for gradient shadow; if divided by 'scale' it would be zoom independent (fixed in size); // if 'scale' is not used, drop shadow will be getting smaller with document zoom; diff --git a/src/display/control/canvas-item-rect.h b/src/display/control/canvas-item-rect.h index 84507f1e84fd76a55ffa39dadbe06346f65a3d57..c9904d26d4e65b23a54f7a4bba85a009f811b4ba 100644 --- a/src/display/control/canvas-item-rect.h +++ b/src/display/control/canvas-item-rect.h @@ -24,36 +24,33 @@ namespace Inkscape { -class CanvasItemGroup; // A canvas control that contains other canvas controls. - -class CanvasItemRect : public CanvasItem { - +class CanvasItemRect final : public CanvasItem +{ public: CanvasItemRect(CanvasItemGroup *group); CanvasItemRect(CanvasItemGroup *group, Geom::Rect const &rect); // Geometry void set_rect(Geom::Rect const &rect); - Geom::Rect get_rect() const {return _rect;} - void visit_page_rects(std::function) const override; - - void update(Geom::Affine const &affine) override; - double closest_distance_to(Geom::Point const &p); // Maybe not needed + void visit_page_rects(std::function const &) const override; // Selection bool contains(Geom::Point const &p, double tolerance = 0) override; - // Display - void render(Inkscape::CanvasItemBuffer *buf) override; - // Properties void set_is_page(bool is_page); - void set_fill(guint32 color) override; + void set_fill(uint32_t color) override; void set_dashed(bool dash = true); void set_inverted(bool inverted = false); void set_shadow(uint32_t color, int width); protected: + ~CanvasItemRect() override = default; + + void _update(bool propagate) override; + void _render(Inkscape::CanvasItemBuffer &buf) override; + + // Geometry double get_shadow_size() const; Geom::Rect _rect; diff --git a/src/display/control/canvas-item-text.cpp b/src/display/control/canvas-item-text.cpp index c2e77cc357e6c7a4fd33df64b2b83df0df205289..c25740e8a2de9249844445f7cac5ea867d72ed3e 100644 --- a/src/display/control/canvas-item-text.cpp +++ b/src/display/control/canvas-item-text.cpp @@ -23,18 +23,16 @@ #include "color.h" // SP_RGBA_x_F #include "ui/util.h" -#include "ui/widget/canvas.h" namespace Inkscape { /** - * Create an null control text. + * Create a null control text. */ CanvasItemText::CanvasItemText(CanvasItemGroup *group) : CanvasItem(group) { _name = "CanvasItemText"; - _pickable = false; // Text is never pickable. _fill = 0x33337fff; // Override CanvasItem default. } @@ -48,7 +46,6 @@ CanvasItemText::CanvasItemText(CanvasItemGroup *group, Geom::Point const &p, Gli , _scaled(scaled) { _name = "CanvasItemText"; - _pickable = false; // Text is never pickable. _fill = 0x33337fff; // Override CanvasItem default. request_update(); @@ -67,23 +64,13 @@ void CanvasItemText::set_coord(Geom::Point const &p) /** * Set a text position. Position is in document coordinates. */ -void CanvasItemText::set_bg_radius(double const &rad) +void CanvasItemText::set_bg_radius(double rad) { _bg_rad = rad; request_update(); } -/** - * Returns distance between point in canvas units and nearest point on text. - */ -double CanvasItemText::closest_distance_to(Geom::Point const &p) -{ - double d = Geom::infinity(); - std::cerr << "CanvasItemText::closest_distance_to: Not implemented!" << std::endl; - return d; -} - /** * Returns true if point p (in canvas units) is within tolerance (canvas units) distance of text. */ @@ -95,21 +82,13 @@ bool CanvasItemText::contains(Geom::Point const &p, double tolerance) /** * Update and redraw control text. */ -void CanvasItemText::update(Geom::Affine const &affine) +void CanvasItemText::_update(bool) { - if (_affine == affine && !_need_update) { - // Nothing to do. - return; - } - // Queue redraw of old area (erase previous content). request_redraw(); - // Get new bounds - _affine = affine; - // Point needs to be scaled manually if not cairo scaling - Geom::Point p = _scaled ? _p : _p * _affine; + Geom::Point p = _scaled ? _p : _p * affine(); // Measure text size _text_box = load_text_extents(); @@ -119,47 +98,35 @@ void CanvasItemText::update(Geom::Affine const &affine) double offset_y = -(_anchor_position.y() * _text_box.height()); offset_x += p.x() + _adjust_offset.x(); offset_y += p.y() + _adjust_offset.y(); - _text_box *= Geom::Translate(Geom::Point(int(offset_x), int(offset_y))); + _text_box *= Geom::Translate(Geom::Point(offset_x, offset_y).floor()); // Pixel alignment of background. Avoid aliasing artifacts on redraw. _text_box = _text_box.roundOutwards(); // Don't apply affine here, to keep text at the same size in screen coords. _bounds = _text_box; - if (_scaled) { - _bounds *= _affine; - _bounds = _bounds.roundOutwards(); + if (_scaled && _bounds) { + *_bounds *= affine(); + _bounds = _bounds->roundOutwards(); } // Queue redraw of new area request_redraw(); - - _need_update = false; } /** * Render text to screen via Cairo. */ -void CanvasItemText::render(Inkscape::CanvasItemBuffer *buf) +void CanvasItemText::_render(Inkscape::CanvasItemBuffer &buf) { - if (!buf) { - std::cerr << "CanvasItemText::Render: No buffer!" << std::endl; - return; - } - - if (!_visible) { - // Hidden - return; - } - - buf->cr->save(); + buf.cr->save(); // Screen to desktop coords. - buf->cr->translate(-buf->rect.left(), -buf->rect.top()); + buf.cr->translate(-buf.rect.left(), -buf.rect.top()); if (_scaled) { // Convert from canvas space to document space - buf->cr->transform(geom_to_cairo(_affine)); + buf.cr->transform(geom_to_cairo(affine())); } double x = _text_box.min().x(); @@ -170,39 +137,39 @@ void CanvasItemText::render(Inkscape::CanvasItemBuffer *buf) // Background if (_use_background) { if (_bg_rad == 0.0) { - buf->cr->rectangle(x, y, w, h); + buf.cr->rectangle(x, y, w, h); } else { double radius = _bg_rad * (std::min(w ,h) / 2); - buf->cr->arc(x + w - radius, y + radius, radius, -M_PI_2, 0); - buf->cr->arc(x + w - radius, y + h - radius, radius, 0, M_PI_2); - buf->cr->arc(x + radius, y + h - radius, radius, M_PI_2, M_PI); - buf->cr->arc(x + radius, y + radius, radius, M_PI, 3*M_PI_2); + buf.cr->arc(x + w - radius, y + radius, radius, -M_PI_2, 0); + buf.cr->arc(x + w - radius, y + h - radius, radius, 0, M_PI_2); + buf.cr->arc(x + radius, y + h - radius, radius, M_PI_2, M_PI); + buf.cr->arc(x + radius, y + radius, radius, M_PI, 3*M_PI_2); } - buf->cr->set_line_width(2); - buf->cr->set_source_rgba(SP_RGBA32_R_F(_background), SP_RGBA32_G_F(_background), - SP_RGBA32_B_F(_background), SP_RGBA32_A_F(_background)); - buf->cr->fill(); + buf.cr->set_line_width(2); + buf.cr->set_source_rgba(SP_RGBA32_R_F(_background), SP_RGBA32_G_F(_background), + SP_RGBA32_B_F(_background), SP_RGBA32_A_F(_background)); + buf.cr->fill(); } // Center the text inside the draw background box auto bx = x + w / 2.0; auto by = y + h / 2.0 + 1; - buf->cr->move_to(int(bx - _text_size.x_bearing - _text_size.width/2.0), - int(by - _text_size.y_bearing - _text_extent.height/2.0)); - - buf->cr->select_font_face(_fontname, Cairo::FONT_SLANT_NORMAL, Cairo::FONT_WEIGHT_NORMAL); - buf->cr->set_font_size(_fontsize); - buf->cr->text_path(_text); - 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(); - buf->cr->restore(); + buf.cr->move_to(int(bx - _text_size.x_bearing - _text_size.width/2.0), + int(by - _text_size.y_bearing - _text_extent.height/2.0)); + + buf.cr->select_font_face(_fontname, Cairo::FONT_SLANT_NORMAL, Cairo::FONT_WEIGHT_NORMAL); + buf.cr->set_font_size(_fontsize); + buf.cr->text_path(_text); + 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(); + buf.cr->restore(); } -void CanvasItemText::set_text(Glib::ustring const &text) +void CanvasItemText::set_text(Glib::ustring text) { if (_text != text) { - _text = text; + _text = std::move(text); request_update(); // Might be larger than before! } } @@ -227,18 +194,18 @@ Geom::Rect CanvasItemText::load_text_extents() context->get_text_extents(_text, _text_size); if (_fixed_line) { - // TRANSLATORS: This is a set of letters to test for font accender and decenders. + // TRANSLATORS: This is a set of letters to test for font ascender and descenders. context->get_text_extents(_("lg1p$"), _text_extent); } else { _text_extent = _text_size; } return Geom::Rect::from_xywh(0, 0, - _text_size.x_advance + (_border * 2), - _text_extent.height + (_border * 2)); + _text_size.x_advance + _border * 2, + _text_extent.height + _border * 2); } -void CanvasItemText::set_background(guint32 background) +void CanvasItemText::set_background(uint32_t background) { if (_background != background) { _background = background; @@ -254,7 +221,7 @@ void CanvasItemText::set_anchor(Geom::Point const &anchor_pt) { if (_anchor_position != anchor_pt) { _anchor_position = anchor_pt; - _canvas->request_update(); + request_update(); } } @@ -262,7 +229,7 @@ void CanvasItemText::set_adjust(Geom::Point const &adjust_pt) { if (_adjust_offset != adjust_pt) { _adjust_offset = adjust_pt; - _canvas->request_update(); + request_update(); } } @@ -270,7 +237,7 @@ void CanvasItemText::set_fixed_line(bool fixed_line) { if (_fixed_line != fixed_line) { _fixed_line = fixed_line; - _canvas->request_update(); + request_update(); } } @@ -278,7 +245,7 @@ void CanvasItemText::set_border(double border) { if (_border != border) { _border = border; - _canvas->request_update(); + request_update(); } } diff --git a/src/display/control/canvas-item-text.h b/src/display/control/canvas-item-text.h index 9021c12f7fb6f9cf6d554e0397b1dd250704cef5..78d92806d34484f2477994612f38c71a605d46a4 100644 --- a/src/display/control/canvas-item-text.h +++ b/src/display/control/canvas-item-text.h @@ -17,50 +17,43 @@ * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ -#include - #include <2geom/point.h> #include <2geom/transforms.h> +#include + #include "canvas-item.h" namespace Inkscape { -namespace UI::Widget { -class Canvas; -} - -class CanvasItemGroup; // A canvas control that contains other canvas controls. - -class CanvasItemText : public CanvasItem { - +class CanvasItemText final : public CanvasItem +{ public: CanvasItemText(CanvasItemGroup *group); CanvasItemText(CanvasItemGroup *group, Geom::Point const &p, Glib::ustring text, bool scaled = false); // Geometry void set_coord(Geom::Point const &p); - void set_bg_radius(double const &rad); - - void update(Geom::Affine const &affine) override; - double closest_distance_to(Geom::Point const &p); // Maybe not needed + void set_bg_radius(double rad); // Selection bool contains(Geom::Point const &p, double tolerance = 0) override; - // Display - void render(Inkscape::CanvasItemBuffer *buf) override; - // Properties - void set_text(Glib::ustring const &text); + void set_text(Glib::ustring text); void set_fontsize(double fontsize); void set_border(double border); - void set_background(guint32 background); + void set_background(uint32_t background); void set_anchor(Geom::Point const &anchor_pt); void set_adjust(Geom::Point const &adjust_pt); void set_fixed_line(bool fixed_line); protected: + ~CanvasItemText() override = default; + + void _update(bool propagate) override; + void _render(Inkscape::CanvasItemBuffer &buf) override; + Geom::Point _p; // Position of text (not box around text). Cairo::TextExtents _text_extent; Cairo::TextExtents _text_size; @@ -72,7 +65,7 @@ protected: double _fontsize = 10; double _border = 3; double _bg_rad = 0; - guint32 _background = 0x0000007f; + uint32_t _background = 0x0000007f; bool _use_background = false; bool _fixed_line = false; // Correction for font heights bool _scaled = false; @@ -80,7 +73,6 @@ protected: Geom::Rect load_text_extents(); }; - } // namespace Inkscape #endif // SEEN_CANVAS_ITEM_TEXT_H diff --git a/src/display/control/canvas-item.cpp b/src/display/control/canvas-item.cpp index 259e02e22075bc0d741c061c281f7523bfa2c7a8..61944142d744667770f02e80142a4e649870ce64 100644 --- a/src/display/control/canvas-item.cpp +++ b/src/display/control/canvas-item.cpp @@ -15,91 +15,87 @@ */ #include "canvas-item.h" - #include "canvas-item-group.h" +#include "canvas-item-ctrl.h" #include "ui/widget/canvas.h" +constexpr bool DEBUG_LOGGING = false; +constexpr bool DEBUG_BOUNDS = false; + namespace Inkscape { -CanvasItem::CanvasItem(CanvasItemGroup *group) - : _name("CanvasItem") +CanvasItem::CanvasItem(CanvasItemContext *context) + : _context(context) + , _parent(nullptr) { - if (group) { - group->add(this); - _parent = group; - _canvas = group->get_canvas(); - _affine = group->get_affine(); - } + if constexpr (DEBUG_LOGGING) std::cout << "CanvasItem: create root " << get_name() << std::endl; + request_update(); } -CanvasItem::~CanvasItem() +CanvasItem::CanvasItem(CanvasItemGroup *parent) + : _context(parent->_context) + , _parent(parent) { - if (_parent) { - _parent->remove(this, false); // remove() should not delete this or we'll double delete! - } + if constexpr (DEBUG_LOGGING) std::cout << "CanvasItem: add " << get_name() << " to " << parent->get_name() << " " << parent->items.size() << std::endl; + parent->items.push_back(*this); + request_update(); +} +void CanvasItem::unlink() +{ // Clear canvas of item. request_redraw(); + // Remove from parent. + if (_parent) { + if constexpr (DEBUG_LOGGING) std::cout << "CanvasItem: remove " << get_name() << " from " << _parent->get_name() << " " << _parent->items.size() << std::endl; + auto it = _parent->items.iterator_to(*this); + assert(it != _parent->items.end()); + _parent->items.erase(it); + _parent->request_update(); + } else { + if constexpr (DEBUG_LOGGING) std::cout << "CanvasItem: destroy root " << get_name() << std::endl; + } + + delete this; +} + +CanvasItem::~CanvasItem() +{ // Clear any pointers to this object in canvas. - _canvas->canvas_item_destructed(this); + get_canvas()->canvas_item_destructed(this); } -bool CanvasItem::is_descendant_of(CanvasItem *ancestor) +bool CanvasItem::is_descendant_of(CanvasItem const *ancestor) const { auto item = this; while (item) { if (item == ancestor) { return true; } - item = item->get_parent(); + item = item->_parent; } return false; } -int CanvasItem::get_z_position() -{ - if (!_parent) { - std::cerr << "CanvasItem::get_z_position: No parent!" << std::endl; - return -1; - } - - size_t position = 0; - for (auto it = _parent->items.begin(); it != _parent->items.end(); ++it, ++position) { - if (&*it == this) { - return position; - } - } - - std::cerr << "CanvasItem::get_z_position: item not found!" << std::endl; - return -1; -} - -void CanvasItem::set_z_position(unsigned int n) +void CanvasItem::set_z_position(int zpos) { if (!_parent) { std::cerr << "CanvasItem::set_z_position: No parent!" << std::endl; - } - - if (n == 0) { - this->lower_to_bottom(); // Low cost operation - return; - } - - if (n > _parent->items.size() - 2) { - this->raise_to_top(); // Low cost operation return; } _parent->items.erase(_parent->items.iterator_to(*this)); - size_t position = 0; - for (auto it = _parent->items.begin(); it != _parent->items.end(); ++it, ++position) { - if (position == n) { - _parent->items.insert(it, *this); - break; - } + if (zpos <= 0) { + _parent->items.push_front(*this); + } else if (zpos >= _parent->items.size() - 1) { + _parent->items.push_back(*this); + } else { + auto it = _parent->items.begin(); + std::advance(it, zpos); + _parent->items.insert(it, *this); } } @@ -107,6 +103,7 @@ void CanvasItem::raise_to_top() { if (!_parent) { std::cerr << "CanvasItem::raise_to_top: No parent!" << std::endl; + return; } _parent->items.erase(_parent->items.iterator_to(*this)); @@ -117,6 +114,7 @@ void CanvasItem::lower_to_bottom() { if (!_parent) { std::cerr << "CanvasItem::lower_to_bottom: No parent!" << std::endl; + return; } _parent->items.erase(_parent->items.iterator_to(*this)); @@ -126,130 +124,174 @@ void CanvasItem::lower_to_bottom() // Indicate geometry changed and bounds needs recalculating. void CanvasItem::request_update() { + if (_need_update || !_visible) { + return; + } + _need_update = true; + if (_parent) { _parent->request_update(); } else { - _canvas->request_update(); + get_canvas()->request_update(); } } -bool CanvasItem::set_visible(bool set) +void CanvasItem::update(bool propagate) { - set ? show() : hide(); - return set; -} + if (!_visible) { + _mark_net_invisible(); + return; + } -void CanvasItem::show() -{ - if (_visible) { - return; // Already visible. + bool reappearing = !_net_visible; + _net_visible = true; + + if (!_need_update && !reappearing && !propagate) { + return; } - _visible = true; - // update bounds when visibility changes - request_update(); - request_redraw(); + _need_update = false; + + // Get new bounds + _update(propagate); + + if (reappearing) { + request_redraw(); + } } -int CanvasItem::grab(Gdk::EventMask event_mask, GdkCursor *cursor) +void CanvasItem::_mark_net_invisible() { - return grab(event_mask, Glib::wrap(cursor)); + if (!_net_visible) { + return; + } + _net_visible = false; + _need_update = false; + request_redraw(); + _bounds = {}; } -// Grab all events! TODO: Return boolean -int CanvasItem::grab(Gdk::EventMask event_mask, Glib::RefPtr cursor) +// Grab all events! +void CanvasItem::grab(Gdk::EventMask event_mask, Glib::RefPtr const &cursor) { -#ifdef CANVAS_ITEM_DEBUG - std::cout << "CanvasItem::grab: " << _name << std::endl; -#endif + if constexpr (DEBUG_LOGGING) std::cout << "CanvasItem::grab: " << _name << std::endl; + + auto canvas = get_canvas(); + // Don't grab if we already have a grabbed item! - if (_canvas->get_grabbed_canvas_item()) { - return -1; + if (canvas->get_grabbed_canvas_item()) { + return; } - gtk_grab_add(GTK_WIDGET(_canvas->gobj())); + gtk_grab_add(GTK_WIDGET(canvas->gobj())); - _canvas->set_grabbed_canvas_item(this, event_mask); - _canvas->set_current_canvas_item(this); // So that all events go to grabbed item. - return 0; + canvas->set_grabbed_canvas_item(this, event_mask); + canvas->set_current_canvas_item(this); // So that all events go to grabbed item. } void CanvasItem::ungrab() { -#ifdef CANVAS_ITEM_DEBUG - std::cout << "CanvasItem::ungrab: " << _name << std::endl; -#endif - if (_canvas->get_grabbed_canvas_item() != this) { + if constexpr (DEBUG_LOGGING) std::cout << "CanvasItem::ungrab: " << _name << std::endl; + + auto canvas = get_canvas(); + + if (canvas->get_grabbed_canvas_item() != this) { return; // Sanity check } - _canvas->set_grabbed_canvas_item(nullptr, (Gdk::EventMask)0); // Zero mask + canvas->set_grabbed_canvas_item(nullptr, (Gdk::EventMask)0); // Zero mask - gtk_grab_remove(GTK_WIDGET(_canvas->gobj())); + gtk_grab_remove(GTK_WIDGET(canvas->gobj())); } -void CanvasItem::hide() +void CanvasItem::render(CanvasItemBuffer &buf) { - if (!_visible) { - return; // Already hidden + if (_visible && _bounds && _bounds->interiorIntersects(buf.rect)) { + _render(buf); + if constexpr (DEBUG_BOUNDS) { + auto 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(); + } } +} - _visible = false; - // update bounds when visibility changes - request_update(); - request_redraw(); +void CanvasItem::set_visible(bool visible) +{ + if (_visible == visible) return; + if (_visible) { + request_update(); + _visible = false; + } else { + _visible = true; + request_update(); + } } -void CanvasItem::set_fill(guint32 rgba) +void CanvasItem::request_redraw() { - if (_fill != rgba) { - _fill = rgba; - request_redraw(); + // Queue redraw request + if (_bounds) { + get_canvas()->redraw_area(*_bounds); } } -void CanvasItem::set_stroke(guint32 rgba) +void CanvasItem::set_fill(uint32_t fill) { - if (_stroke != rgba) { - _stroke = rgba; + if (_fill != fill) { + _fill = fill; request_redraw(); } } -void CanvasItem::request_redraw() { - if (_canvas) { - // Queue redraw request - _canvas->redraw_area(_bounds); +void CanvasItem::set_stroke(uint32_t stroke) +{ + if (_stroke != stroke) { + _stroke = stroke; + request_redraw(); } } -} // Namespace Inkscape +void CanvasItem::update_canvas_item_ctrl_sizes(int size_index) +{ + if (auto ctrl = dynamic_cast(this)) { + // We can't use set_size_default as the preference file is updated ->after<- the signal is emitted! + ctrl->set_size_via_index(size_index); + } else if (auto group = dynamic_cast(this)) { + for (auto &item : group->items) { + item.update_canvas_item_ctrl_sizes(size_index); + } + } +} -void canvas_item_print_tree(Inkscape::CanvasItem *item) +void CanvasItem::canvas_item_print_tree(int level, int zorder) const { - static int level = 0; if (level == 0) { std::cout << "Canvas Item Tree" << std::endl; } std::cout << "CC: "; - for (unsigned i = 0; i < level; ++i) { + for (int i = 0; i < level; ++i) { std::cout << " "; } - std::cout << item->get_z_position() << ": " << item->get_name() << std::endl; + std::cout << zorder << ": " << _name << std::endl; - auto group = dynamic_cast(item); - if (group) { - ++level; - for (auto & item : group->items) { - canvas_item_print_tree(&item); + if (auto group = dynamic_cast(this)) { + int i = 0; + for (auto &item : group->items) { + item.canvas_item_print_tree(level + 1, i); + i++; } - --level; } } +} // namespace Inkscape + /* Local Variables: mode:c++ diff --git a/src/display/control/canvas-item.h b/src/display/control/canvas-item.h index 0cc184381d7c46239f0aa5674856df9bfd5ea869..fe5f5f9d33efafe01c3a0eabdff3c8f203946489 100644 --- a/src/display/control/canvas-item.h +++ b/src/display/control/canvas-item.h @@ -26,122 +26,117 @@ * The affine contains only scaling and rotating components. */ -//#define CANVAS_ITEM_DEBUG - -#include // GdkEvent -#include // Gdk::EventMask -#include // guint32 -#include - +#include +#include #include <2geom/rect.h> +#include -#include +#include // Gdk::EventMask +#include // GdkEvent -#include "canvas-item-buffer.h" #include "canvas-item-enums.h" +#include "canvas-item-buffer.h" +#include "canvas-item-context.h" class SPItem; namespace Inkscape { -static constexpr uint32_t CANVAS_ITEM_COLORS[] = { 0x0000ff7f, 0xff00007f, 0xffff007f }; +inline constexpr uint32_t CANVAS_ITEM_COLORS[] = { 0x0000ff7f, 0xff00007f, 0xffff007f }; -namespace UI::Widget { -class Canvas; -} - -class CanvasItemGroup; // A canvas control that contains other canvas controls. - -class CanvasItem { +namespace UI::Widget { class Canvas; } +class CanvasItemGroup; +class CanvasItem +{ public: - CanvasItem(CanvasItemGroup* group); - virtual ~CanvasItem(); + CanvasItem(CanvasItemContext *context); + CanvasItem(CanvasItemGroup *parent); + CanvasItem(CanvasItem const &) = delete; + CanvasItem &operator=(CanvasItem const &) = delete; + void unlink(); // Structure - void set_canvas(UI::Widget::Canvas *canvas) { _canvas = canvas; } - UI::Widget::Canvas* get_canvas() const { return _canvas; } - - void set_parent(CanvasItemGroup *parent) { _parent = parent; } - CanvasItemGroup* get_parent() const { return _parent; } - - void set_item(SPItem *item) { _item = item; } - SPItem* get_item() const { return _item; } + UI::Widget::Canvas *get_canvas() const { return _context->canvas(); } + CanvasItemGroup *get_parent() const { return _parent; } + bool is_descendant_of(CanvasItem const *ancestor) const; // Z Position - bool is_descendant_of(CanvasItem *ancestor); - void set_z_position(unsigned int n); - int get_z_position(); // z position in group. - // void raise_by(unsigned int n); + void set_z_position(int zpos); void raise_to_top(); // Move to top of group (last entry). - // void lower_by(unsigned int n); void lower_to_bottom(); // Move to bottom of group (first entry). // Geometry void request_update(); - virtual void update(Geom::Affine const &affine) = 0; - virtual void visit_page_rects(std::function) const {} - Geom::Affine get_affine() const { return _affine; } - Geom::Rect get_bounds() const { return _bounds; } - double get_scale() const { return std::sqrt(std::abs(_affine.det())); } + void update(bool propagate); + virtual void visit_page_rects(std::function const &) const {} + Geom::OptRect const &get_bounds() const { return _bounds; } // Selection - virtual bool contains(Geom::Point const &p, double tolerance = 0) { return _bounds.interiorContains(p); } - int grab(Gdk::EventMask event_mask, GdkCursor *cursor = nullptr); - int grab(Gdk::EventMask event_mask, Glib::RefPtr cursor); + virtual bool contains(Geom::Point const &p, double tolerance = 0) { return _bounds && _bounds->interiorContains(p); } + void grab(Gdk::EventMask event_mask, Glib::RefPtr const & = {}); void ungrab(); // Display - virtual void render(Inkscape::CanvasItemBuffer *buf) = 0; + void render(Inkscape::CanvasItemBuffer &buf); bool is_visible() const { return _visible; } - bool set_visible(bool set); - virtual void hide(); - virtual void show(); - void request_redraw(); // queue redraw request + virtual void set_visible(bool visible); + void show() { set_visible(true); } + void hide() { set_visible(false); } + void request_redraw(); // queue redraw request // Properties - virtual void set_fill(guint32 rgba); + virtual void set_fill(uint32_t rgba); void set_fill(CanvasItemColor color) { set_fill(CANVAS_ITEM_COLORS[color]); } - virtual void set_stroke(guint32 rgba); + virtual void set_stroke(uint32_t rgba); void set_stroke(CanvasItemColor color) { set_stroke(CANVAS_ITEM_COLORS[color]); } - void set_name(std::string const &name) { _name = name; } - std::string get_name() const { return _name; } + void set_name(std::string &&name) { _name = std::move(name); } + std::string const &get_name() const { return _name; } + void update_canvas_item_ctrl_sizes(int size_index); // Events void set_pickable(bool pickable) { _pickable = pickable; } bool is_pickable() const { return _pickable; } - sigc::connection connect_event(sigc::slot slot) { + sigc::connection connect_event(sigc::slot const &slot) { return _event_signal.connect(slot); } virtual bool handle_event(GdkEvent *event) { - return _event_signal.emit(event); // Default just emit event. + return _event_signal.emit(event); // Default just emits event. } + // Recursively print CanvasItem tree. + void canvas_item_print_tree(int level = 0, int zorder = 0) const; + // Boost linked list member hook, speeds deletion. boost::intrusive::list_member_hook<> member_hook; protected: + friend class CanvasItemGroup; + + virtual ~CanvasItem(); // Structure - CanvasItemGroup *_parent = nullptr; - Inkscape::UI::Widget::Canvas *_canvas = nullptr; - SPItem *_item; // The object this canvas item is linked to in some sense. Can be nullptr. + CanvasItemContext *_context; + CanvasItemGroup *_parent; // Geometry - Geom::Rect _bounds; - Geom::Affine _affine; - bool _need_update = true; // Need update after creation! + Geom::OptRect _bounds; + bool _need_update = false; + Geom::Affine const &affine() const { return _context->affine(); } + virtual void _update(bool propagate) = 0; + virtual void _mark_net_invisible(); // Display bool _visible = true; - bool _align_to_drawing = false; // Rotate if drawing is rotated. TODO: Implement! + bool _net_visible = true; + virtual void _render(Inkscape::CanvasItemBuffer &buf) = 0; // Selection bool _pickable = false; // Most items are just for display and are not pickable! // Properties - guint32 _fill = CANVAS_ITEM_COLORS[CANVAS_ITEM_SECONDARY]; - guint32 _stroke = CANVAS_ITEM_COLORS[CANVAS_ITEM_PRIMARY]; + uint32_t _fill = CANVAS_ITEM_COLORS[CANVAS_ITEM_SECONDARY]; + uint32_t _stroke = CANVAS_ITEM_COLORS[CANVAS_ITEM_PRIMARY]; std::string _name; // For debugging // Events @@ -150,18 +145,11 @@ protected: } // namespace Inkscape -/** Type for linked list storing CanvasItems. - * - * Used to speed deletion when a group contains a large number of items (as in nodes for a - * complex path). - */ -typedef boost::intrusive::list< - Inkscape::CanvasItem, - boost::intrusive::member_hook, - &Inkscape::CanvasItem::member_hook> > CanvasItemList; - -// Recursively print CanvasItem tree. -void canvas_item_print_tree(Inkscape::CanvasItem *item); +// Todo: Move to lib2geom. +inline auto &operator<<(std::ostream &s, Geom::OptRect const &rect) +{ + return rect ? (s << *rect) : (s << "(empty)"); +} #endif // SEEN_CANVAS_ITEM_H diff --git a/src/display/control/canvas-page.cpp b/src/display/control/canvas-page.cpp index edca4185c417d3736b83f1746b9e5c26a56a29a5..9a434761726c5f222e167bc4880e0d6e11d69f62 100644 --- a/src/display/control/canvas-page.cpp +++ b/src/display/control/canvas-page.cpp @@ -17,13 +17,9 @@ namespace Inkscape { -CanvasPage::~CanvasPage() -{ - for (auto item : canvas_items) { - delete item; - } - canvas_items.clear(); -} +CanvasPage::CanvasPage() = default; + +CanvasPage::~CanvasPage() = default; /** * Add the page canvas to the given canvas item groups (canvas view is implicit) @@ -33,16 +29,18 @@ void CanvasPage::add(Geom::Rect size, CanvasItemGroup *background_group, CanvasI // Foreground 'border' if (auto item = new CanvasItemRect(border_group, size)) { item->set_name("foreground"); - canvas_items.push_back(item); + item->set_is_page(true); + canvas_items.emplace_back(item); } // Background rectangle 'fill' if (auto item = new CanvasItemRect(background_group, size)) { item->set_name("background"); + item->set_is_page(true); item->set_dashed(false); item->set_inverted(false); item->set_stroke(0x00000000); - canvas_items.push_back(item); + canvas_items.emplace_back(item); } if (auto item = new CanvasItemRect(border_group, size)) { @@ -50,7 +48,7 @@ void CanvasPage::add(Geom::Rect size, CanvasItemGroup *background_group, CanvasI item->set_dashed(false); item->set_inverted(false); item->set_stroke(_margin_color); - canvas_items.push_back(item); + canvas_items.emplace_back(item); } if (auto item = new CanvasItemRect(border_group, size)) { @@ -58,12 +56,12 @@ void CanvasPage::add(Geom::Rect size, CanvasItemGroup *background_group, CanvasI item->set_dashed(false); item->set_inverted(false); item->set_stroke(_bleed_color); - canvas_items.push_back(item); + canvas_items.emplace_back(item); } if (auto label = new CanvasItemText(border_group, Geom::Point(0, 0), "{Page Label}")) { label->set_fixed_line(false); - canvas_items.push_back(label); + canvas_items.emplace_back(label); } } /** @@ -74,7 +72,6 @@ void CanvasPage::remove(UI::Widget::Canvas *canvas) g_assert(canvas != nullptr); for (auto it = canvas_items.begin(); it != canvas_items.end();) { if (canvas == (*it)->get_canvas()) { - delete (*it); it = canvas_items.erase(it); } else { ++it; @@ -84,14 +81,14 @@ void CanvasPage::remove(UI::Widget::Canvas *canvas) void CanvasPage::show() { - for (auto item : canvas_items) { + for (auto &item : canvas_items) { item->show(); } } void CanvasPage::hide() { - for (auto item : canvas_items) { + for (auto &item : canvas_items) { item->hide(); } } @@ -121,25 +118,28 @@ void CanvasPage::update(Geom::Rect size, Geom::OptRect margin, Geom::OptRect ble border_color = select_color; } - for (auto item : canvas_items) { - if (auto rect = dynamic_cast(item)) { + for (auto &item : canvas_items) { + if (auto rect = dynamic_cast(item.get())) { if (rect->get_name() == "margin") { rect->set_stroke(margin_color); - if (rect->set_visible(margin && *margin != size)) { + bool vis = margin && *margin != size; + rect->set_visible(vis); + if (vis) { rect->set_rect(*margin); } continue; } if (rect->get_name() == "bleed") { rect->set_stroke(bleed_color); - if (rect->set_visible(bleed && *bleed != size)) { + bool vis = bleed && *bleed != size; + rect->set_visible(vis); + if (vis) { rect->set_rect(*bleed); } continue; } rect->set_rect(size); - rect->set_is_page(true); bool is_foreground = (rect->get_name() == "foreground"); // This will put the border on the background OR foreground layer as needed. @@ -169,8 +169,7 @@ void CanvasPage::update(Geom::Rect size, Geom::OptRect margin, Geom::OptRect ble rect->set_fill(0x0); rect->set_shadow(0x0, 0); } - } - if (auto label = dynamic_cast(item)) { + } else if (auto label = dynamic_cast(item.get())) { _updateTextItem(label, size, txt ? txt : ""); } } @@ -210,19 +209,15 @@ void CanvasPage::_updateTextItem(CanvasItemText *label, Geom::Rect page, std::st } } - label->show(); label->set_fontsize(fontsize); label->set_fill(foreground); label->set_background(is_selected ? selected : background); label->set_bg_radius(radius); label->set_anchor(anchor); label->set_coord(coord); - label->set_text(txt.c_str()); + label->set_visible(!txt.empty()); + label->set_text(std::move(txt)); label->set_border(4.0); - - if (txt.empty()) { - label->hide(); - } } bool CanvasPage::setOnTop(bool on_top) @@ -265,8 +260,7 @@ bool CanvasPage::setLabelStyle(const std::string &style) return false; } - -}; +} // namespace Inkscape /* Local Variables: diff --git a/src/display/control/canvas-page.h b/src/display/control/canvas-page.h index 0da335c8ac5abfc4c3a2ca323c177847281d2215..df9a539af3e74d0e567719f43db14b7a46d3509a 100644 --- a/src/display/control/canvas-page.h +++ b/src/display/control/canvas-page.h @@ -16,22 +16,18 @@ #include #include -#include "canvas-item.h" +#include "canvas-item-ptr.h" namespace Inkscape { - namespace UI { - namespace Widget { - class Canvas; - }; - }; +namespace UI::Widget { class Canvas; } - class CanvasItemGroup; - class CanvasItemText; +class CanvasItemGroup; +class CanvasItemText; class CanvasPage { public: - CanvasPage() = default; + CanvasPage(); ~CanvasPage(); void update(Geom::Rect size, Geom::OptRect margin, Geom::OptRect bleed, const char *txt, bool outline = false); @@ -52,7 +48,7 @@ private: // This may make this look like a CanvasItemGroup, but it's not one. This // isn't a collection of items, but a set of items in multiple Canvases. // Each item can belong in either a foreground or background group. - std::vector canvas_items; + std::vector> canvas_items; int _shadow_size = 0; bool _border_on_top = true; @@ -65,7 +61,7 @@ private: std::string _label_style = "default"; }; -}; +} // namespace Inkscape #endif // SEEN_CANVAS_PAGE_H diff --git a/src/display/control/canvas-temporary-item-list.cpp b/src/display/control/canvas-temporary-item-list.cpp index 4be97f994cca1c70e4153f5d8c28a2fcfb8ffec9..6ff516d5e12ed004f20a22c41d2502d38a054082 100644 --- a/src/display/control/canvas-temporary-item-list.cpp +++ b/src/display/control/canvas-temporary-item-list.cpp @@ -11,18 +11,13 @@ * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ +#include #include "canvas-temporary-item.h" #include "canvas-temporary-item-list.h" namespace Inkscape { namespace Display { -TemporaryItemList::TemporaryItemList(SPDesktop *desktop) - : desktop(desktop) -{ - -} - TemporaryItemList::~TemporaryItemList() { // delete all items in list so the timeouts are removed @@ -32,49 +27,38 @@ TemporaryItemList::~TemporaryItemList() itemlist.clear(); } -/* Note that TemporaryItem or TemporaryItemList is responsible for deletion and such, so this return pointer can safely be ignored. */ -TemporaryItem * -TemporaryItemList::add_item(CanvasItem *item, unsigned int lifetime) +// Note that TemporaryItem or TemporaryItemList is responsible for deletion and such, so this return pointer can safely be ignored. +TemporaryItem *TemporaryItemList::add_item(CanvasItem *item, int lifetime_msecs) { // beware of strange things happening due to very short timeouts - TemporaryItem * tempitem; - if (lifetime == 0) - tempitem = new TemporaryItem(item, 0, true); + TemporaryItem *tempitem; + if (lifetime_msecs == 0) + tempitem = new TemporaryItem(item, 0); else { - tempitem = new TemporaryItem(item, lifetime); - tempitem->signal_timeout.connect( sigc::mem_fun(*this, &TemporaryItemList::_item_timeout) ); + tempitem = new TemporaryItem(item, lifetime_msecs); + tempitem->signal_timeout.connect([this] (auto tempitem) { itemlist.remove(tempitem); }); + // no need to delete the item, it does that itself after signal_timeout.emit() completes } - itemlist.push_back(tempitem); + itemlist.emplace_back(tempitem); return tempitem; } -void -TemporaryItemList::delete_item( TemporaryItem * tempitem ) +void TemporaryItemList::delete_item(TemporaryItem *tempitem) { // check if the item is in the list, if so, delete it. (in other words, don't wait for the item to delete itself) - bool in_list = false; - for (auto & it : itemlist) { - if ( it == tempitem ) { - in_list = true; - break; - } - } - if (in_list) { - itemlist.remove(tempitem); + auto it = std::find_if(itemlist.begin(), itemlist.end(), [=] (auto *item) { + return item == tempitem; + }); + + if (it != itemlist.end()) { + itemlist.erase(it); delete tempitem; } } -void -TemporaryItemList::_item_timeout(TemporaryItem * tempitem) -{ - itemlist.remove(tempitem); - // no need to delete the item, it does that itself after signal_timeout.emit() completes -} - -} //namespace Display -} /* namespace Inkscape */ +} // namespace Display +} // namespace Inkscape /* Local Variables: diff --git a/src/display/control/canvas-temporary-item-list.h b/src/display/control/canvas-temporary-item-list.h index 29b270adb97f4c110d2bd46bf9ac160280604a01..1321cbf5f0200c0f39624cb413e3113b35cef0d1 100644 --- a/src/display/control/canvas-temporary-item-list.h +++ b/src/display/control/canvas-temporary-item-list.h @@ -13,7 +13,6 @@ #include -struct SPCanvasItem; class SPDesktop; namespace Inkscape { @@ -25,33 +24,27 @@ namespace Display { class TemporaryItem; /** - * Provides a class that can contain active TemporaryItem[s] on a desktop. + * Provides a class that can contain active TemporaryItems on a desktop. */ -class TemporaryItemList { +class TemporaryItemList final +{ public: - TemporaryItemList(SPDesktop *desktop); - virtual ~TemporaryItemList(); + TemporaryItemList() = default; + TemporaryItemList(TemporaryItemList const &) = delete; + TemporaryItemList &operator=(TemporaryItemList const &) = delete; + ~TemporaryItemList(); - TemporaryItem* add_item (SPCanvasItem *item, unsigned int lifetime); - TemporaryItem* add_item (CanvasItem *item, unsigned int lifetime); - void delete_item (TemporaryItem * tempitem); + TemporaryItem* add_item(CanvasItem *item, int lifetime_msecs); + void delete_item(TemporaryItem *tempitem); protected: - SPDesktop *desktop; /** Desktop we are on. */ - - std::list itemlist; /** list of temp items */ - - void _item_timeout (TemporaryItem * tempitem); - -private: - TemporaryItemList(const TemporaryItemList&) = delete; - TemporaryItemList& operator=(const TemporaryItemList&) = delete; + std::list itemlist; ///< List of temp items. }; -} //namespace Display -} //namespace Inkscape +} // namespace Display +} // namespace Inkscape -#endif +#endif // INKSCAPE_CANVAS_TEMPORARY_ITEM_LIST_H /* Local Variables: diff --git a/src/display/control/canvas-temporary-item.cpp b/src/display/control/canvas-temporary-item.cpp index c7a033da95699fb5acc5626b9482a725c76eae1d..d95ad216939ab9684f4a7b624aa9f14de1af4e11 100644 --- a/src/display/control/canvas-temporary-item.cpp +++ b/src/display/control/canvas-temporary-item.cpp @@ -15,59 +15,31 @@ * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ -#include +#include #include "canvas-temporary-item.h" - #include "canvas-item.h" namespace Inkscape { namespace Display { -/** lifetime is measured in milliseconds - */ -TemporaryItem::TemporaryItem(CanvasItem *item, guint lifetime, bool deselect_destroy) - : canvasitem(item), - timeout_id(0), - destroy_on_deselect(deselect_destroy) +TemporaryItem::TemporaryItem(CanvasItem *item, int lifetime_msecs) + : canvasitem(std::move(item)) { - if (lifetime > 0 && destroy_on_deselect) { - g_warning ("Warning: lifetime should be 0 when destroy_on_deselect is true"); - lifetime = 0; - } - // zero lifetime means stay forever, so do not add timeout event. - if (lifetime > 0) { - timeout_id = g_timeout_add(lifetime, &TemporaryItem::_timeout, this); + // Zero lifetime means stay forever, so do not add timeout event. + if (lifetime_msecs > 0) { + timeout_conn = Glib::signal_timeout().connect([this] { + signal_timeout.emit(this); + delete this; + return false; + }, lifetime_msecs); } } -TemporaryItem::~TemporaryItem() -{ - // when it has not expired yet... - if (timeout_id) { - g_source_remove(timeout_id); - timeout_id = 0; - } - - if (canvasitem) { - // destroying the item automatically hides it - delete canvasitem; - canvasitem = nullptr; - } -} - -/* static method */ -int TemporaryItem::_timeout(void* data) { - TemporaryItem *tempitem = static_cast(data); - tempitem->timeout_id = 0; - tempitem->signal_timeout.emit(tempitem); - delete tempitem; - return FALSE; -} - +TemporaryItem::~TemporaryItem() = default; -} //namespace Display -} /* namespace Inkscape */ +} // namespace Display +} // namespace Inkscape /* Local Variables: diff --git a/src/display/control/canvas-temporary-item.h b/src/display/control/canvas-temporary-item.h index 316a0980c719b9425692d952ec821e71a5de8dda..4ce27875c8759dce3d62fc2a5c8600a5fc60bbc4 100644 --- a/src/display/control/canvas-temporary-item.h +++ b/src/display/control/canvas-temporary-item.h @@ -11,8 +11,10 @@ * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ - #include +#include +#include "display/control/canvas-item-ptr.h" +#include "helper/auto-connection.h" namespace Inkscape { @@ -23,30 +25,27 @@ namespace Display { /** * Provides a class to put a canvasitem temporarily on-canvas. */ -class TemporaryItem { +class TemporaryItem final +{ public: - TemporaryItem(Inkscape::CanvasItem *item, unsigned int lifetime, bool destroy_on_deselect = false); - virtual ~TemporaryItem(); - - TemporaryItem(const TemporaryItem&) = delete; - TemporaryItem& operator=(const TemporaryItem&) = delete; + TemporaryItem(CanvasItem *item, int lifetime_msecs); + TemporaryItem(TemporaryItem const &) = delete; + TemporaryItem &operator=(TemporaryItem const &) = delete; + ~TemporaryItem(); sigc::signal signal_timeout; protected: friend class TemporaryItemList; - Inkscape::CanvasItem * canvasitem = nullptr; /** The item we are holding on to */ - unsigned int timeout_id; /** ID by which glib knows the timeout event */ - bool destroy_on_deselect; // only destroy when parent item is deselected, not when mouse leaves - - static int _timeout(void* data); ///< callback for when lifetime expired + CanvasItemPtr canvasitem; ///< The item we are holding on to. + auto_connection timeout_conn; }; } //namespace Display } //namespace Inkscape -#endif +#endif // INKSCAPE_CANVAS_TEMPORARY_ITEM_H /* Local Variables: diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index d89460800b2b15b1bad31f2fbe35c4f2cabfe018..c38f0c22ed27a313b6749a53d15252bc69be56d7 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -247,7 +247,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap box->set_stroke(pre_snap ? 0x7f7f7fff : 0xff0000ff); box->set_dashed(true); box->set_pickable(false); // Is false by default. - box->set_z_position(0); + box->lower_to_bottom(); _snaptarget_bbox = _desktop->add_temporary_canvasitem(box, timeout_val*1000.0); } } diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index 681228bfc16cb9a64e0044b2a92604e137b06658..7ceb02e6bef0fd90b85fd698cb0e60338d1090d1 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -97,8 +97,12 @@ DrawingItem::~DrawingItem() itemdrawing->set_active(nullptr); } } else { - // Can happen, e.g. in Eraser tool. - // std::cerr << "DrawingItem::~DrawingItem: Missing CanvasItemDrawing!" << std::endl; + // Typically happens, e.g. for any non-Canvas Drawing. + } + + // Remove caching candidate entry. + if (_has_cache_iterator) { + _drawing._candidate_items.erase(_cache_iterator); } // Remove from the set of cached items and delete cache. @@ -264,10 +268,6 @@ void DrawingItem::_setCached(bool cached, bool persistent) } else { _drawing._cached_items.erase(this); _cache.reset(); - if (_has_cache_iterator) { - _drawing._candidate_items.erase(_cache_iterator); - _has_cache_iterator = false; - } } } @@ -1106,8 +1106,7 @@ void DrawingItem::_markForUpdate(unsigned flags, bool propagate) if (drawing().getCanvasItemDrawing()) { drawing().getCanvasItemDrawing()->request_update(); } else { - // Can happen, e.g. Eraser tool. - // std::cerr << "DrawingItem::_markForUpdate: Missing CanvasItemDrawing!" << std::endl; + // Typically happens, e.g. for any non-Canvas Drawing. } } } diff --git a/src/display/drawing.cpp b/src/display/drawing.cpp index f5453c34a8d97e345e3dd0c0d4601a2cba5dce41..4f8133c3897f8d69e061bfb8208a2b120cda63aa 100644 --- a/src/display/drawing.cpp +++ b/src/display/drawing.cpp @@ -320,7 +320,8 @@ void Drawing::_loadPrefs() // Enable caching only for the Canvas's drawing, since only it is persistent. if (_canvas_item_drawing) { - _cache_budget = (1 << 20) * prefs->getIntLimited("/options/renderingcache/size", 64, 0, 4096); + // Preference is stored in MiB; convert to bytes, taking care not to overflow. + _cache_budget = (size_t{1} << 20) * prefs->getIntLimited("/options/renderingcache/size", 64, 0, 4096); } else { _cache_budget = 0; } diff --git a/src/display/drawing.h b/src/display/drawing.h index 22dedc5596e10c76bd8dcf61e40a58ecca00e0bc..f78adc884f04e518ca9e12aac9ef5527319e130b 100644 --- a/src/display/drawing.h +++ b/src/display/drawing.h @@ -99,7 +99,7 @@ private: RenderMode _rendermode = RenderMode::NORMAL; ColorMode _colormode = ColorMode::NORMAL; - bool _outlineoverlay; + bool _outlineoverlay = false; Filters::FilterColorMatrix::ColorMatrixMatrix _grayscale_matrix; uint32_t _clip_outline_color; uint32_t _mask_outline_color; @@ -127,14 +127,7 @@ private: Util::FuncLog _funclog; template - void defer(F &&f) - { - if (!_snapshotted) { - f(); - } else { - _funclog.emplace(std::forward(f)); - } - } + void defer(F &&f) { _snapshotted ? _funclog.emplace(std::forward(f)) : f(); } friend class DrawingItem; }; diff --git a/src/document.cpp b/src/document.cpp index 279ff7065eb16a070941f3197f9397bcd62d0284..9980bd11665849030989f7e911b0c96decc4be0e 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -41,6 +41,8 @@ #include #include +#include + #include <2geom/transforms.h> #include "desktop.h" @@ -48,7 +50,6 @@ #include "event-log.h" #include "file.h" #include "id-clash.h" -#include "inkscape-version.h" #include "inkscape.h" #include "inkscape-window.h" #include "profile-manager.h" @@ -64,7 +65,6 @@ #include "3rdparty/adaptagrams/libavoid/router.h" -#include "3rdparty/libcroco/cr-parser.h" #include "3rdparty/libcroco/cr-sel-eng.h" #include "3rdparty/libcroco/cr-selector.h" @@ -1487,40 +1487,33 @@ static std::vector &find_items_in_area(std::vector &s, return s; } -SPItem *SPDocument::getItemFromListAtPointBottom(unsigned int dkey, SPGroup *group, std::vector const &list,Geom::Point const &p, bool take_insensitive) +SPItem *SPDocument::getItemFromListAtPointBottom(unsigned dkey, SPGroup *group, std::vector const &list, Geom::Point const &p, bool take_insensitive) { - g_return_val_if_fail(group, NULL); - SPItem *bottomMost = nullptr; - - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - gdouble delta = prefs->getDouble("/options/cursortolerance/value", 1.0); - - for (auto& o: group->children) { - if (bottomMost) { - break; - } - if (is(&o)) { - auto item = cast(&o); - Inkscape::DrawingItem *arenaitem = item->get_arenaitem(dkey); + if (!group) { + return nullptr; + } - if (arenaitem) { - arenaitem->drawing().update(); - } + double const delta = Inkscape::Preferences::get()->getDouble("/options/cursortolerance/value", 1.0); - if (arenaitem && arenaitem->pick(p, delta, 1) != nullptr - && (take_insensitive || item->isVisibleAndUnlocked(dkey))) { - if (find(list.begin(), list.end(), item) != list.end()) { - bottomMost = item; + for (auto &c: group->children) { + if (auto item = cast(&c)) { + if (auto di = item->get_arenaitem(dkey)) { + if (di->pick(p, delta, Inkscape::DrawingItem::PICK_STICKY) && (take_insensitive || item->isVisibleAndUnlocked(dkey))) { + if (std::find(list.begin(), list.end(), item) != list.end()) { + return item; + } } } - if (!bottomMost && is(&o)) { - // return null if not found: - bottomMost = getItemFromListAtPointBottom(dkey, cast(&o), list, p, take_insensitive); + if (auto group = cast(item)) { + if (auto ret = getItemFromListAtPointBottom(dkey, group, list, p, take_insensitive)) { + return ret; + } } } } - return bottomMost; + + return nullptr; } /** @@ -1555,27 +1548,24 @@ upwards in z-order and returns what it has found so far (i.e. the found items ar guaranteed to be lower than upto). Requires a list of nodes built by build_flat_item_list. If items_count > 0, it'll return the topmost (in z-order) items_count items. */ -static std::vector find_items_at_point(std::deque *nodes, unsigned int dkey, - Geom::Point const &p, int items_count=0, SPItem* upto=nullptr) +static std::vector find_items_at_point(std::deque const &nodes, unsigned dkey, + Geom::Point const &p, int items_count = 0, SPItem *upto = nullptr) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - gdouble delta = prefs->getDouble("/options/cursortolerance/value", 1.0); + double const delta = Inkscape::Preferences::get()->getDouble("/options/cursortolerance/value", 1.0); - SPItem *child; std::vector result; - bool seen_upto = (!upto); - for (auto node : *nodes) { - child = node; - if (!seen_upto){ - if(child == upto) + + bool seen_upto = !upto; + for (auto node : nodes) { + if (!seen_upto) { + if (node == upto) { seen_upto = true; + } continue; } - Inkscape::DrawingItem *arenaitem = child->get_arenaitem(dkey); - if (arenaitem) { - arenaitem->drawing().update(); - if (arenaitem->pick(p, delta, 1) != nullptr) { - result.push_back(child); + if (auto di = node->get_arenaitem(dkey)) { + if (di->pick(p, delta, Inkscape::DrawingItem::PICK_STICKY)) { + result.emplace_back(node); if (--items_count == 0) { break; } @@ -1586,7 +1576,7 @@ static std::vector find_items_at_point(std::deque *nodes, unsi return result; } -static SPItem *find_item_at_point(std::deque *nodes, unsigned int dkey, Geom::Point const &p, SPItem* upto=nullptr) +static SPItem *find_item_at_point(std::deque const &nodes, unsigned dkey, Geom::Point const &p, SPItem *upto = nullptr) { auto items = find_items_at_point(nodes, dkey, p, 1, upto); if (items.empty()) { @@ -1596,41 +1586,29 @@ static SPItem *find_item_at_point(std::deque *nodes, unsigned int dkey, } /** -Returns the topmost non-layer group from the descendants of group which is at point -p, or NULL if none. Recurses into layers but not into groups. + * Returns the topmost non-layer group from the descendants of group which is at point p, + * or null if none. Recurses into layers but not into groups. */ -static SPItem *find_group_at_point(unsigned int dkey, SPGroup *group, Geom::Point const &p) +static SPItem *find_group_at_point(unsigned dkey, SPGroup *group, Geom::Point const &p) { - SPItem *seen = nullptr; - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - gdouble delta = prefs->getDouble("/options/cursortolerance/value", 1.0); - - for (auto& o: group->children) { - if (!is(&o)) { - continue; - } - if (is(&o) && cast(&o)->effectiveLayerMode(dkey) == SPGroup::LAYER) { - SPItem *newseen = find_group_at_point(dkey, cast(&o), p); - if (newseen) { - seen = newseen; - } - } - if (is(&o) && cast(&o)->effectiveLayerMode(dkey) != SPGroup::LAYER ) { - auto child = cast(&o); - Inkscape::DrawingItem *arenaitem = child->get_arenaitem(dkey); - if (arenaitem) { - arenaitem->drawing().update(); - } + double const delta = Inkscape::Preferences::get()->getDouble("/options/cursortolerance/value", 1.0); - // seen remembers the last (topmost) of groups pickable at this point - if (arenaitem && arenaitem->pick(p, delta, 1) != nullptr) { - seen = child; + for (auto &c : boost::adaptors::reverse(group->children)) { + if (auto group = cast(&c)) { + if (group->effectiveLayerMode(dkey) == SPGroup::LAYER) { + if (auto ret = find_group_at_point(dkey, group, p)) { + return ret; + } + } else if (auto di = group->get_arenaitem(dkey)) { + if (di->pick(p, delta, Inkscape::DrawingItem::PICK_STICKY)) { + return group; + } } } } - return seen; -} + return nullptr; +} /** * Return list of items, contained in box @@ -1685,7 +1663,7 @@ std::vector SPDocument::getItemsAtPoints(unsigned const key, std::vecto } size_t item_counter = 0; for(int i = points.size()-1;i>=0; i--) { - std::vector items = find_items_at_point(&_node_cache, key, points[i], topmost_only); + std::vector items = find_items_at_point(_node_cache, key, points[i], topmost_only); for (SPItem *item : items) { if (item && result.end()==find(result.begin(), result.end(), item)) if(all_layers || (desktop && desktop->layerManager().layerForObject(item) == current_layer)){ @@ -1721,7 +1699,7 @@ SPItem *SPDocument::getItemAtPoint( unsigned const key, Geom::Point const &p, _node_cache_valid=true; } - SPItem *res = find_item_at_point(&_node_cache, key, p, upto); + SPItem *res = find_item_at_point(_node_cache, key, p, upto); if(!into_groups) _node_cache = bak; return res; diff --git a/src/gradient-drag.cpp b/src/gradient-drag.cpp index ebd2b0b809c4a484e553f54281241a6e90b2f41f..090d5c691bd9157c1ff78eabab05a035e62f52fe 100644 --- a/src/gradient-drag.cpp +++ b/src/gradient-drag.cpp @@ -584,10 +584,9 @@ bool GrDrag::dropColor(SPItem */*item*/, gchar const *c, Geom::Point p) } // now see if we're over line and create a new stop - for (auto curve : item_curves) { - if (curve->is_line() && curve->get_item() && curve->contains(p, 5)) { - SPStop *stop = addStopNearPoint(curve->get_item(), p, 5/desktop->current_zoom()); - if (stop) { + for (auto &it : item_curves) { + if (it.curve->is_line() && it.item && it.curve->contains(p, 5)) { + if (auto stop = addStopNearPoint(it.item, p, 5 / desktop->current_zoom())) { SPCSSAttr *css = sp_repr_css_attr_new(); sp_repr_css_set_property( css, "stop-color", stopIsNull ? nullptr : toUse.c_str() ); sp_repr_css_set_property( css, "stop-opacity", "1" ); @@ -600,7 +599,6 @@ bool GrDrag::dropColor(SPItem */*item*/, gchar const *c, Geom::Point p) return false; } - GrDrag::GrDrag(SPDesktop *desktop) : keep_selection(false), local_change(false), @@ -673,9 +671,6 @@ GrDrag::~GrDrag() this->draggers.clear(); this->selected.clear(); - for (auto curve : item_curves) { - delete curve; - } item_curves.clear(); } @@ -685,17 +680,14 @@ GrDraggable::GrDraggable(SPItem *item, GrPointType point_type, guint point_i, In point_i(point_i), fill_or_stroke(fill_or_stroke) { - //g_object_ref(G_OBJECT(item)); sp_object_ref(item); } GrDraggable::~GrDraggable() { - //g_object_unref (G_OBJECT (this->item)); - sp_object_unref(this->item); + sp_object_unref(item); } - SPObject *GrDraggable::getServer() { SPObject *server = nullptr; @@ -2043,22 +2035,23 @@ void GrDrag::setDeselected(GrDragger *dragger) desktop->emit_gradient_stop_selected(this, nullptr); } - /** * Create a line from p1 to p2 and add it to the curves list. Used for linear and radial gradients. */ void GrDrag::addLine(SPItem *item, Geom::Point p1, Geom::Point p2, Inkscape::PaintTarget fill_or_stroke) { - auto canvas_item_color = (fill_or_stroke == Inkscape::FOR_FILL) ? Inkscape::CANVAS_ITEM_PRIMARY : Inkscape::CANVAS_ITEM_SECONDARY; - auto item_curve = new Inkscape::CanvasItemCurve(desktop->getCanvasControls(), p1, p2); - item_curve->set_name("GradientLine"); - item_curve->set_stroke(canvas_item_color); - item_curve->set_is_fill(fill_or_stroke == Inkscape::FOR_FILL); - item_curve->set_item(item); - item_curves.push_back(item_curve); -} + auto const canvas_item_color = fill_or_stroke == Inkscape::FOR_FILL ? Inkscape::CANVAS_ITEM_PRIMARY : Inkscape::CANVAS_ITEM_SECONDARY; + auto curve = make_canvasitem(desktop->getCanvasControls(), p1, p2); + curve->set_name("GradientLine"); + curve->set_stroke(canvas_item_color); + auto item_curve = ItemCurve(); + item_curve.item = item; + item_curve.curve = std::move(curve); + item_curve.is_fill = fill_or_stroke == Inkscape::FOR_FILL; + item_curves.emplace_back(std::move(item_curve)); +} /** * Create a curve from p0 to p3 and add it to the curves list. Used for mesh sides. @@ -2080,23 +2073,20 @@ void GrDrag::addCurve(SPItem *item, Geom::Point p0, Geom::Point p1, Geom::Point highlight = true; } - auto canvas_item_color = - (fill_or_stroke == Inkscape::FOR_FILL) ? Inkscape::CANVAS_ITEM_PRIMARY : Inkscape::CANVAS_ITEM_SECONDARY; - if (highlight) { - canvas_item_color = - (fill_or_stroke == Inkscape::FOR_FILL) ? Inkscape::CANVAS_ITEM_SECONDARY : Inkscape::CANVAS_ITEM_PRIMARY; - } + auto const canvas_item_color = (fill_or_stroke == Inkscape::FOR_FILL) ^ highlight ? Inkscape::CANVAS_ITEM_PRIMARY : Inkscape::CANVAS_ITEM_SECONDARY; - auto item_curve = new Inkscape::CanvasItemCurve(desktop->getCanvasControls(), p0, p1, p2, p3); - item_curve->set_name("GradientCurve"); - item_curve->set_stroke(canvas_item_color); - item_curve->set_is_fill(fill_or_stroke == Inkscape::FOR_FILL); - item_curve->set_item(item); - item_curve->set_corner0(corner0); - item_curve->set_corner1(corner1); - item_curves.push_back(item_curve); -} + auto curve = make_canvasitem(desktop->getCanvasControls(), p0, p1, p2, p3); + curve->set_name("GradientCurve"); + curve->set_stroke(canvas_item_color); + auto item_curve = ItemCurve(); + item_curve.item = item; + item_curve.curve = std::move(curve); + item_curve.is_fill = fill_or_stroke == Inkscape::FOR_FILL; + item_curve.corner0 = corner0; + item_curve.corner1 = corner1; + item_curves.emplace_back(std::move(item_curve)); +} /** * If there already exists a dragger within MERGE_DIST of p, add the draggable to it; otherwise create @@ -2463,9 +2453,6 @@ bool GrDrag::mouseOver() */ void GrDrag::updateLines() { - for (auto curve : item_curves) { - delete curve; - } item_curves.clear(); g_return_if_fail(this->selection != nullptr); diff --git a/src/gradient-drag.h b/src/gradient-drag.h index 86e1bde26d54a37c031853bf77447fa1e0a0a27e..e981c4e93228e27fdbcbce49eb883d133d2c9dbd 100644 --- a/src/gradient-drag.h +++ b/src/gradient-drag.h @@ -30,6 +30,7 @@ #include "object/sp-gradient.h" // TODO refactor enums to external .h file #include "object/sp-mesh-array.h" +#include "display/control/canvas-item-ptr.h" class SPKnot; @@ -195,7 +196,16 @@ public: // FIXME: make more of this private! std::vector vert_levels; std::vector draggers; - std::vector item_curves; + + struct ItemCurve + { + SPItem *item; + CanvasItemPtr curve; + bool is_fill = true; // Fill or stroke, used by meshes. + int corner0 = -1; // For meshes + int corner1 = -1; // For meshes + }; + std::vector item_curves; void updateDraggers(); void refreshDraggers(); diff --git a/src/helper/geom.h b/src/helper/geom.h index bf1652e3e9b02adcf6f295c1dc3d0a5ba7e08433..e6a3aaa730084035d62448d96022f4b113bf6733 100644 --- a/src/helper/geom.h +++ b/src/helper/geom.h @@ -64,6 +64,21 @@ inline auto expandedBy(Geom::IntRect rect, int amount) return rect; } +inline auto expandedBy(Geom::Rect rect, double amount) +{ + rect.expandBy(amount); + return rect; +} + +inline Geom::OptRect expandedBy(Geom::OptRect const &rect, double amount) +{ + if (!rect) { + return {}; + } else { + return expandedBy(*rect, amount); + } +} + inline auto distSq(Geom::IntPoint const &pt, Geom::IntRect const &rect) { auto v = rect.clamp(pt) - pt; @@ -136,6 +151,29 @@ inline auto regularised(Geom::OptIntRect const &r) return r && !r->hasZeroArea() ? r : Geom::OptIntRect(); } +/// Get the bounding box of a collection of points. +template +auto bounds_of(Geom::Point const &pt, Args const &... args) +{ + if constexpr (sizeof...(args) == 0) { + return Geom::Rect(pt, pt); + } else { + auto rect = bounds_of(args...); + rect.expandTo(pt); + return rect; + } +} + +inline auto floor(Geom::Rect const &rect) +{ + return Geom::Rect(rect.min().floor(), rect.max().floor()); +} + +inline auto roundedOutwards(Geom::OptRect const &rect) +{ + return rect ? rect->roundOutwards() : Geom::OptIntRect(); +} + #endif // INKSCAPE_HELPER_GEOM_H /* diff --git a/src/live_effects/parameter/text.cpp b/src/live_effects/parameter/text.cpp index ea0171dc2ed5b938e66c2570be864b55ae554ef2..a3ea6f66badef26743ea07b7af299ffae2e843bb 100644 --- a/src/live_effects/parameter/text.cpp +++ b/src/live_effects/parameter/text.cpp @@ -41,16 +41,11 @@ TextParam::TextParam( const Glib::ustring& label, const Glib::ustring& tip, , defvalue(default_value) { if (SPDesktop *desktop = SP_ACTIVE_DESKTOP) { // FIXME: we shouldn't use this! - canvas_text = new Inkscape::CanvasItemText(desktop->getCanvasTemp(), Geom::Point(0, 0), default_value); + canvas_text = make_canvasitem(desktop->getCanvasTemp(), Geom::Point(0, 0), default_value); } } -TextParam::~TextParam() -{ - if (canvas_text) { - delete canvas_text; - } -} +TextParam::~TextParam() = default; void TextParam::param_set_default() @@ -68,10 +63,7 @@ TextParam::param_update_default(const gchar * default_value) void TextParam::param_hide_canvas_text() { - if (canvas_text) { - delete canvas_text; - canvas_text = nullptr; - } + canvas_text.reset(); } void @@ -156,20 +148,18 @@ TextParam::param_newWidget() return return_widg; } -void -TextParam::param_setValue(const Glib::ustring newvalue) +void TextParam::param_setValue(Glib::ustring newvalue) { if (value != newvalue) { param_effect->refresh_widgets = true; } - value = newvalue; + value = std::move(newvalue); if (canvas_text) { - canvas_text->set_text(newvalue); + canvas_text->set_text(value); } } } /* namespace LivePathEffect */ - } /* namespace Inkscape */ /* diff --git a/src/live_effects/parameter/text.h b/src/live_effects/parameter/text.h index 42700ad40c9723755f568eeea35cfbf49d7ae8ac..0a3a87ba3493f96a53fa9f6addf44618bff07f55 100644 --- a/src/live_effects/parameter/text.h +++ b/src/live_effects/parameter/text.h @@ -17,6 +17,7 @@ #include #include "live_effects/parameter/parameter.h" +#include "display/control/canvas-item-ptr.h" namespace Inkscape { @@ -60,7 +61,7 @@ private: double anchor_y; Glib::ustring value; Glib::ustring defvalue; - Inkscape::CanvasItemText *canvas_text = nullptr; + CanvasItemPtr canvas_text; }; /* diff --git a/src/object/sp-grid.cpp b/src/object/sp-grid.cpp index 7693eaaabe0ab2f494e63692b656f580397fc40d..9371e02785580a53d450fe0f3206f570962e7a76 100644 --- a/src/object/sp-grid.cpp +++ b/src/object/sp-grid.cpp @@ -20,6 +20,7 @@ #include "sp-namedview.h" #include "display/control/canvas-item-grid.h" +#include "display/control/canvas-item-ptr.h" #include "attributes.h" #include "desktop.h" @@ -277,11 +278,11 @@ void SPGrid::_checkOldGrid(SPDocument *doc, Inkscape::XML::Node *repr) } } -static std::unique_ptr create_view(GridType grid_type, Inkscape::CanvasItemGroup *canvasgrids) +static CanvasItemPtr create_view(GridType grid_type, Inkscape::CanvasItemGroup *canvasgrids) { switch (grid_type) { - case GridType::RECTANGULAR: return std::make_unique (canvasgrids); break; - case GridType::AXONOMETRIC: return std::make_unique(canvasgrids); break; + case GridType::RECTANGULAR: return make_canvasitem (canvasgrids); break; + case GridType::AXONOMETRIC: return make_canvasitem(canvasgrids); break; default: g_assert_not_reached(); return {}; } } diff --git a/src/object/sp-grid.h b/src/object/sp-grid.h index 3ef1c3d66322bbde36e91c42f25726f0bf0ee66d..eb32147649c9702d6353f6ed7ace8de62081bee4 100644 --- a/src/object/sp-grid.h +++ b/src/object/sp-grid.h @@ -18,6 +18,7 @@ #ifndef SEEN_SP_GRID_H_ #define SEEN_SP_GRID_H_ +#include "display/control/canvas-item-ptr.h" #include "object/sp-object.h" #include "svg/svg-bool.h" #include "svg/svg-length.h" @@ -110,7 +111,7 @@ public: std::pair getEffectiveOriginAndSpacing() const; - std::vector> views; + std::vector> views; protected: void build(SPDocument *doc, Inkscape::XML::Node *repr) override; diff --git a/src/object/sp-guide.cpp b/src/object/sp-guide.cpp index 11d24bd860a1e9ffd10e354dc5e570ae9c8240bc..0a8cbf44ff3ac5df700de0d1b0c8661b83bf7679 100644 --- a/src/object/sp-guide.cpp +++ b/src/object/sp-guide.cpp @@ -58,7 +58,7 @@ SPGuide::SPGuide() void SPGuide::setColor(guint32 color) { this->color = color; - for (auto view : views) { + for (auto &view : views) { view->set_stroke(color); } } @@ -79,10 +79,7 @@ void SPGuide::build(SPDocument *document, Inkscape::XML::Node *repr) void SPGuide::release() { - for(auto view : views) { - delete view; - } - this->views.clear(); + views.clear(); if (this->document) { // Unregister ourselves @@ -313,12 +310,12 @@ void SPGuide::showSPGuide(Inkscape::CanvasItemGroup *group) auto dot_handler = [=](GdkEvent *ev) { return sp_dt_guide_event(ev, item, this); }; dot->connect_event(dot_handler); - views.push_back(item); + views.emplace_back(item); } void SPGuide::showSPGuide() { - for (auto view : views) { + for (auto &view : views) { view->show(); } } @@ -329,7 +326,6 @@ void SPGuide::hideSPGuide(Inkscape::UI::Widget::Canvas *canvas) g_assert(canvas != nullptr); for (auto it = views.begin(); it != views.end(); ++it) { if (canvas == (*it)->get_canvas()) { // A guide can be displayed on more than one desktop with the same document. - delete (*it); views.erase(it); return; } @@ -340,7 +336,7 @@ void SPGuide::hideSPGuide(Inkscape::UI::Widget::Canvas *canvas) void SPGuide::hideSPGuide() { - for(auto view : views) { + for (auto &view : views) { view->hide(); } } @@ -349,9 +345,9 @@ void SPGuide::sensitize(Inkscape::UI::Widget::Canvas *canvas, bool sensitive) { g_assert(canvas != nullptr); - for (auto view : views) { + for (auto &view : views) { if (canvas == view->get_canvas()) { - view->set_sensitive(sensitive); + view->set_pickable(sensitive); return; } } @@ -370,7 +366,7 @@ void SPGuide::moveto(Geom::Point const point_on_line, bool const commit) return; } - for(auto view : this->views) { + for (auto &view : views) { view->set_origin(point_on_line); } @@ -414,7 +410,7 @@ void SPGuide::set_normal(Geom::Point const normal_to_line, bool const commit) if(this->locked) { return; } - for(auto view : this->views) { + for (auto &view : views) { view->set_normal(normal_to_line); } diff --git a/src/object/sp-guide.h b/src/object/sp-guide.h index 700705f56a0ac5d354cbe195bcd992ea8e7f0d4d..a7f20a6204872df94728df1a10678daa1c8a6334 100644 --- a/src/object/sp-guide.h +++ b/src/object/sp-guide.h @@ -17,6 +17,7 @@ #include <2geom/point.h> #include +#include "display/control/canvas-item-ptr.h" #include "sp-object.h" typedef unsigned int guint32; @@ -86,7 +87,7 @@ protected: void set(SPAttr key, const char* value) override; char* label; - std::vector views; // See display/control/guideline.h. + std::vector> views; // See display/control/guideline.h. bool locked; Geom::Point normal_to_line; Geom::Point point_on_line; diff --git a/src/page-manager.cpp b/src/page-manager.cpp index 4ebbd304f8b5a8b26fa4ed24d45a44869248eef3..f7936a20d90238fbfe4fcfb07306feeb806bcca1 100644 --- a/src/page-manager.cpp +++ b/src/page-manager.cpp @@ -699,9 +699,9 @@ bool PageManager::setDefaultAttributes(Inkscape::CanvasPage *item) auto dkcolor = _document->getNamedView()->desk_color; bool ret = item->setOnTop(border_on_top); // fixed shadow size, not configurable; shadow changes size with zoom - ret = item->setShadow(border_show && shadow_show ? 2 : 0) || ret; - ret = item->setPageColor(border_show ? border_color : 0x0, bgcolor, dkcolor, margin_color, bleed_color) || ret; - ret = item->setLabelStyle(label_style) || ret; + ret |= item->setShadow(border_show && shadow_show ? 2 : 0); + ret |= item->setPageColor(border_show ? border_color : 0x0, bgcolor, dkcolor, margin_color, bleed_color); + ret |= item->setLabelStyle(label_style); return ret; } diff --git a/src/rubberband.cpp b/src/rubberband.cpp index 2b9ca23d823f9b1aeac9661225c9e44cfb16bd31..f24f24b6f6050f1c34bf82af5d4d6f7c7d0a6088 100644 --- a/src/rubberband.cpp +++ b/src/rubberband.cpp @@ -33,15 +33,8 @@ Inkscape::Rubberband::Rubberband(SPDesktop *dt) void Inkscape::Rubberband::delete_canvas_items() { - if (_rect) { - delete _rect; - _rect = nullptr; - } - - if (_touchpath) { - delete _touchpath; - _touchpath = nullptr; - } + _rect.reset(); + _touchpath.reset(); } Geom::Path Inkscape::Rubberband::getPath() const @@ -125,8 +118,8 @@ void Inkscape::Rubberband::move(Geom::Point const &p) switch (_mode) { case RUBBERBAND_MODE_RECT: - if (_rect == nullptr) { - _rect = new Inkscape::CanvasItemRect(_desktop->getCanvasControls()); + if (!_rect) { + _rect = make_canvasitem(_desktop->getCanvasControls()); _rect->set_stroke(_color.value_or(0x808080ff)); _rect->set_shadow(0xffffffff, 0); // Not a shadow _rect->set_dashed(false); @@ -136,8 +129,8 @@ void Inkscape::Rubberband::move(Geom::Point const &p) _rect->show(); break; case RUBBERBAND_MODE_TOUCHRECT: - if (_rect == nullptr) { - _rect = new Inkscape::CanvasItemRect(_desktop->getCanvasControls()); + if (!_rect) { + _rect = make_canvasitem(_desktop->getCanvasControls()); _rect->set_stroke(_color.value_or(0xff0000ff)); _rect->set_shadow(0xffffffff, 0); // Not a shadow _rect->set_dashed(false); @@ -147,8 +140,8 @@ void Inkscape::Rubberband::move(Geom::Point const &p) _rect->show(); break; case RUBBERBAND_MODE_TOUCHPATH: - if (_touchpath == nullptr) { - _touchpath = new Inkscape::CanvasItemBpath(_desktop->getCanvasControls()); // Should be sketch? + if (!_touchpath) { + _touchpath = make_canvasitem(_desktop->getCanvasControls()); // Should be sketch? _touchpath->set_stroke(_color.value_or(0xff0000ff)); _touchpath->set_fill(0x0, SP_WIND_RULE_NONZERO); } @@ -207,7 +200,7 @@ Geom::OptRect Inkscape::Rubberband::getRectangle() const Inkscape::Rubberband *Inkscape::Rubberband::get(SPDesktop *desktop) { - if (_instance == nullptr) { + if (!_instance) { _instance = new Inkscape::Rubberband(desktop); } diff --git a/src/rubberband.h b/src/rubberband.h index e47d94470f103407307134395233d9029b1e3cd5..b21499f720c2ccb2bf2343a9bfba67827d7a4d3d 100644 --- a/src/rubberband.h +++ b/src/rubberband.h @@ -17,6 +17,7 @@ #include <2geom/rect.h> #include #include +#include "display/control/canvas-item-ptr.h" /* fixme: do multidocument safe */ @@ -69,8 +70,8 @@ private: Geom::Point _end; Geom::Path _path; - Inkscape::CanvasItemRect *_rect = nullptr; - Inkscape::CanvasItemBpath *_touchpath = nullptr; + CanvasItemPtr _rect; + CanvasItemPtr _touchpath; SPCurve *_touchpath_curve = nullptr; void delete_canvas_items(); diff --git a/src/selcue.cpp b/src/selcue.cpp index c27ff0d25cb6ddbf19a77cb99cf794c125868b62..f84bc735548d492006cc4d6123e257fc38d5cb21 100644 --- a/src/selcue.cpp +++ b/src/selcue.cpp @@ -133,17 +133,16 @@ void SelCue::_newItemBboxes() Geom::OptRect const bbox = (prefs_bbox == 0) ? item->desktopVisualBounds() : item->desktopGeometricBounds(); if (bbox) { - std::unique_ptr canvas_item; + CanvasItemPtr canvas_item; if (mode == MARK) { - auto ctrl = - std::make_unique(_desktop->getCanvasControls(), CANVAS_ITEM_CTRL_TYPE_SHAPER, - Geom::Point(bbox->min().x(), bbox->max().y())); + auto ctrl = make_canvasitem(_desktop->getCanvasControls(), CANVAS_ITEM_CTRL_TYPE_SHAPER, + Geom::Point(bbox->min().x(), bbox->max().y())); ctrl->set_fill(0x000000ff); ctrl->set_stroke(0x0000000ff); canvas_item = std::move(ctrl); } else if (mode == BBOX) { - auto rect = std::make_unique(_desktop->getCanvasControls(), *bbox); + auto rect = make_canvasitem(_desktop->getCanvasControls(), *bbox); rect->set_stroke(0xffffffa0); rect->set_shadow(0x0000c0a0, 1); rect->set_dashed(true); @@ -153,7 +152,7 @@ void SelCue::_newItemBboxes() if (canvas_item) { canvas_item->set_pickable(false); - canvas_item->set_z_position(0); // Just low enough to not get in the way of other draggable knots. + canvas_item->lower_to_bottom(); // Just low enough to not get in the way of other draggable knots. canvas_item->show(); _item_bboxes.emplace_back(std::move(canvas_item)); } @@ -178,9 +177,8 @@ void SelCue::_newItemLines() auto anchor = Geom::Scale(_selection->anchor_x, _selection->anchor_y); auto point = bbox->min() + (bbox->dimensions() * anchor); for (bool horz : {false, true}) { - auto line = - std::make_unique(_desktop->getCanvasGuides(), "", point, Geom::Point(!horz, horz)); - line->set_z_position(0); + auto line = make_canvasitem(_desktop->getCanvasGuides(), "", point, Geom::Point(!horz, horz)); + line->lower_to_bottom(); line->show(); line->set_stroke(0xddddaa11); line->set_inverted(true); @@ -202,12 +200,11 @@ void SelCue::_newTextBaselines() pt = flow->getBaselinePoint(); } if (pt) { - auto canvas_item = std::make_unique( - _desktop->getCanvasControls(), CANVAS_ITEM_CTRL_SHAPE_SQUARE, (*pt) * item->i2dt_affine()); + auto canvas_item = make_canvasitem(_desktop->getCanvasControls(), CANVAS_ITEM_CTRL_SHAPE_SQUARE, (*pt) * item->i2dt_affine()); canvas_item->set_size(5); canvas_item->set_stroke(0x000000ff); canvas_item->set_fill(0x00000000); - canvas_item->set_z_position(0); + canvas_item->lower_to_bottom(); canvas_item->show(); _text_baselines.emplace_back(std::move(canvas_item)); } diff --git a/src/selcue.h b/src/selcue.h index aca46a0acfee1908eaff6fd070480c4f65ea5122..0cb55b486ba80eb0eb41f7d4cd4277aaf29cdf8b 100644 --- a/src/selcue.h +++ b/src/selcue.h @@ -15,11 +15,12 @@ */ #include -#include +#include #include #include +#include "display/control/canvas-item-ptr.h" #include "preferences.h" class SPDesktop; @@ -68,9 +69,9 @@ private: Selection *_selection; sigc::connection _sel_changed_connection; sigc::connection _sel_modified_connection; - std::vector> _item_bboxes; - std::vector> _text_baselines; - std::vector> _item_lines; + std::vector> _item_bboxes; + std::vector> _text_baselines; + std::vector> _item_lines; BoundingBoxPrefsObserver _bounding_box_prefs_observer; }; diff --git a/src/seltrans.cpp b/src/seltrans.cpp index 0afcbdde6baef47782b48106a7ed21152cdd703b..414659bab4b64e68cbc10f3dae808d3ada699916 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -127,18 +127,18 @@ Inkscape::SelTrans::SelTrans(SPDesktop *desktop) : _selection = desktop->getSelection(); - _norm = new CanvasItemCtrl(desktop->getCanvasControls(), Inkscape::CANVAS_ITEM_CTRL_TYPE_CENTER); + _norm = make_canvasitem(desktop->getCanvasControls(), Inkscape::CANVAS_ITEM_CTRL_TYPE_CENTER); _norm->set_fill(0x0); _norm->set_stroke(0xff0000b0); _norm->hide(); - _grip = new CanvasItemCtrl(desktop->getCanvasControls(), Inkscape::CANVAS_ITEM_CTRL_TYPE_POINT); + _grip = make_canvasitem(desktop->getCanvasControls(), Inkscape::CANVAS_ITEM_CTRL_TYPE_POINT); _grip->set_fill(0xffffff7f); _grip->set_stroke(0xff0000b0); _grip->hide(); - for (auto & i : _l) { - i = new Inkscape::CanvasItemCurve(desktop->getCanvasControls()); + for (auto &i : _l) { + i = make_canvasitem(desktop->getCanvasControls()); i->hide(); } @@ -165,23 +165,15 @@ Inkscape::SelTrans::~SelTrans() knot = nullptr; } - if (_norm) { - delete _norm; - } - - if (_grip) { - delete _grip; - } - - for (auto & i : _l) { - if (i) { - delete i; - } + _norm.reset(); + _grip.reset(); + for (auto &i : _l) { + i.reset(); } _clear_stamp(); - for (auto & _item : _items) { + for (auto &_item : _items) { sp_object_unref(_item, nullptr); } diff --git a/src/seltrans.h b/src/seltrans.h index cadcd71f4dd0b53a8c1c49c2f41720ab7d849f22..64695430fe96d7f96541b385c0a8f5b166b94ded 100644 --- a/src/seltrans.h +++ b/src/seltrans.h @@ -16,12 +16,13 @@ * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ +#include +#include #include <2geom/point.h> #include <2geom/affine.h> #include <2geom/rect.h> #include #include -#include #include "message-context.h" #include "seltrans-handles.h" @@ -180,9 +181,9 @@ private: bool _center_is_set; ///< we've already set _center, no need to reread it from items SPKnot *knots[NUMHANDS]; - Inkscape::CanvasItemCtrl *_norm; - Inkscape::CanvasItemCtrl *_grip; - Inkscape::CanvasItemCurve *_l[4]; + CanvasItemPtr _norm; + CanvasItemPtr _grip; + std::array, 4> _l; std::vector _stamp_cache; bool _stamped = false; Geom::Point _origin; ///< position of origin for transforms diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp index d3908a452b71316c5981e1833002fe0fc8be6f77..ad820ec499dd0296152373314413a0bacfdd62fe 100644 --- a/src/ui/dialog/inkscape-preferences.cpp +++ b/src/ui/dialog/inkscape-preferences.cpp @@ -426,16 +426,6 @@ int InkscapePreferences::num_widgets_in_grid(Glib::ustring const &key, Gtk::Widg return results; } - -bool InkscapePreferences::on_outline_overlay_changed(GdkEventFocus * /* focus_event */) -{ - if (auto *desktop = SP_ACTIVE_DESKTOP) { - desktop->getCanvas()->redraw_all(); - } - return false; - -} - /** * Implementation of the search functionality executes each time * search entry is changed @@ -2741,7 +2731,6 @@ void InkscapePreferences::initPageRendering() // rendering outline overlay opacity _rendering_outline_overlay_opacity.init("/options/rendering/outline-overlay-opacity", 1.0, 100.0, 1.0, 5.0, 50.0, true, false); - _rendering_outline_overlay_opacity.signal_focus_out_event().connect(sigc::mem_fun(*this, &InkscapePreferences::on_outline_overlay_changed)); _page_rendering.add_line( false, _("Outline overlay opacity:"), _rendering_outline_overlay_opacity, _("%"), _("Opacity of the color in outline overlay view mode"), false); // update strategy diff --git a/src/ui/dialog/inkscape-preferences.h b/src/ui/dialog/inkscape-preferences.h index 6357ed0e1a8115189366511503992800135b5a63..f73f3d74cdd20c282e9c4487fdd4024cb92e1a27 100644 --- a/src/ui/dialog/inkscape-preferences.h +++ b/src/ui/dialog/inkscape-preferences.h @@ -738,7 +738,6 @@ private: void get_highlight_colors(guint32 &colorsetbase, guint32 &colorsetsuccess, guint32 &colorsetwarning, guint32 &colorseterror); - bool on_outline_overlay_changed(GdkEventFocus * /* focus_event */); std::map dark_themes; bool _init; Inkscape::PrefObserver _theme_oberver; diff --git a/src/ui/dialog/spellcheck.cpp b/src/ui/dialog/spellcheck.cpp index 4ce6cfbddff66dc5d519889a51d21949ccea9814..a0089cf5a606e674c842c00056be94dc94804c3e 100644 --- a/src/ui/dialog/spellcheck.cpp +++ b/src/ui/dialog/spellcheck.cpp @@ -197,7 +197,6 @@ SpellCheck::SpellCheck() SpellCheck::~SpellCheck() { - clearRects(); disconnect(); } @@ -212,10 +211,6 @@ void SpellCheck::documentReplaced() void SpellCheck::clearRects() { - for(auto rect : _rects) { - rect->hide(); - delete rect; - } _rects.clear(); } @@ -519,7 +514,7 @@ SpellCheck::nextWord() auto rect = new Inkscape::CanvasItemRect(desktop->getCanvasSketch(), area); rect->set_stroke(0xff0000ff); rect->show(); - _rects.push_back(rect); + _rects.emplace_back(rect); // scroll to make it all visible Geom::Point const center = desktop->current_center(); @@ -592,14 +587,9 @@ SpellCheck::nextWord() return false; } - - -void -SpellCheck::deleteLastRect () +void SpellCheck::deleteLastRect() { if (!_rects.empty()) { - _rects.back()->hide(); - delete _rects.back(); _rects.pop_back(); } } diff --git a/src/ui/dialog/spellcheck.h b/src/ui/dialog/spellcheck.h index c25e7aac1734a824035e13b933d48a53886900d6..753eb80002078295b75fd1ea4108bb1a761c2d3e 100644 --- a/src/ui/dialog/spellcheck.h +++ b/src/ui/dialog/spellcheck.h @@ -31,6 +31,7 @@ #include "text-editing.h" #include "ui/dialog/dialog-base.h" #include "ui/widget/scrollprotected.h" +#include "display/control/canvas-item-ptr.h" #if WITH_GSPELL #include @@ -171,7 +172,7 @@ private: /** * list of canvasitems (currently just rects) that mark misspelled things on canvas */ - std::vector _rects; + std::vector> _rects; /** * list of text objects we have already checked in this session diff --git a/src/ui/draw-anchor.cpp b/src/ui/draw-anchor.cpp index 5aaba999396bee4c35f54a3c9d9f122774554784..b0d22e5ce3bdf761f05e67834f86a5c1ed5933a4 100644 --- a/src/ui/draw-anchor.cpp +++ b/src/ui/draw-anchor.cpp @@ -30,7 +30,7 @@ const guint32 FILL_COLOR_MOUSEOVER = 0xff0000ff; SPDrawAnchor::SPDrawAnchor(Inkscape::UI::Tools::FreehandBase *dc, std::shared_ptr curve, bool start, Geom::Point delta) : dc(dc), curve(std::move(curve)), start(start), active(FALSE), dp(delta), ctrl( - new Inkscape::CanvasItemCtrl( + make_canvasitem( dc->getDesktop()->getCanvasControls(), Inkscape::CANVAS_ITEM_CTRL_TYPE_ANCHOR ) @@ -42,12 +42,7 @@ SPDrawAnchor::SPDrawAnchor(Inkscape::UI::Tools::FreehandBase *dc, std::shared_pt ctrl->set_pickable(false); // We do our own checking. (TODO: Should be fixed!) } -SPDrawAnchor::~SPDrawAnchor() -{ - if (ctrl) { - delete (ctrl); - } -} +SPDrawAnchor::~SPDrawAnchor() = default; /** * Test if point is near anchor, if so fill anchor on canvas and return diff --git a/src/ui/draw-anchor.h b/src/ui/draw-anchor.h index cfd55accd552cc8d30b89e79e765010a32f988a8..6cff1514c43a5e8df8ecc410d2fb8cf3e8edea4f 100644 --- a/src/ui/draw-anchor.h +++ b/src/ui/draw-anchor.h @@ -16,7 +16,7 @@ #include <2geom/point.h> -#include +#include "display/control/canvas-item-ptr.h" namespace Inkscape { @@ -47,7 +47,7 @@ public: bool start : 1; bool active : 1; Geom::Point dp; - Inkscape::CanvasItemCtrl *ctrl = nullptr; + CanvasItemPtr ctrl; SPDrawAnchor(Inkscape::UI::Tools::FreehandBase *dc, std::shared_ptr curve, bool start, Geom::Point delta); diff --git a/src/ui/knot/knot-holder-entity.cpp b/src/ui/knot/knot-holder-entity.cpp index ea15e96e70fe48ce3afe945bc682ae47f20959b2..21d7b0ad2a5b63aeae9cafe2c9f3c48fc0c25304 100644 --- a/src/ui/knot/knot-holder-entity.cpp +++ b/src/ui/knot/knot-holder-entity.cpp @@ -213,7 +213,7 @@ SPPattern *PatternKnotHolderEntity::_pattern() const bool PatternKnotHolderEntity::knot_missing() const { - return (_pattern() == nullptr); + return !_pattern(); } /* Pattern X/Y knot */ @@ -222,8 +222,8 @@ void PatternKnotHolderEntityXY::on_created() { PatternKnotHolderEntity::on_created(); // TODO: Move to constructor when desktop is generally available - _quad = std::make_unique(desktop->getCanvasControls()); - _quad->set_z_position(0); + _quad = make_canvasitem(desktop->getCanvasControls()); + _quad->lower_to_bottom(); _quad->set_fill(0x00000000); _quad->set_stroke(0x808080ff); _quad->set_inverted(true); @@ -525,7 +525,7 @@ void BlurKnotHolderEntity::on_created() KnotHolderEntity::on_created(); // TODO: Move to constructor when desktop is generally available - _line = std::make_unique(desktop->getCanvasControls()); + _line = make_canvasitem(desktop->getCanvasControls()); _line->set_z_position(0); _line->set_stroke(0x0033cccc); _line->hide(); diff --git a/src/ui/knot/knot-holder-entity.h b/src/ui/knot/knot-holder-entity.h index 1383df06e08257bd19dfb91bd39a7ee543be48f2..7d5e434b13f02051c65c35d0ef837d0952ffa30b 100644 --- a/src/ui/knot/knot-holder-entity.h +++ b/src/ui/knot/knot-holder-entity.h @@ -24,6 +24,7 @@ #include "display/control/canvas-item-quad.h" #include "display/control/canvas-item-curve.h" #include "helper/auto-connection.h" +#include "display/control/canvas-item-ptr.h" class SPHatch; class SPItem; @@ -138,7 +139,7 @@ public: private: // Extra visual element to show the pattern editing area - std::unique_ptr _quad; + CanvasItemPtr _quad; }; class PatternKnotHolderEntityAngle : public PatternKnotHolderEntity { @@ -236,7 +237,7 @@ class BlurKnotHolderEntity : public KnotHolderEntity { Geom::Point _pos() const; int _dir; - std::unique_ptr _line; + CanvasItemPtr _line; Inkscape::auto_connection _watch_filter; Inkscape::auto_connection _watch_blur; }; diff --git a/src/ui/knot/knot.cpp b/src/ui/knot/knot.cpp index 061de9ed7f83910b4bcc4b1c177a232786bb3a74..f024a732e55373d4e18e8bebdc7535761bc0e61e 100644 --- a/src/ui/knot/knot.cpp +++ b/src/ui/knot/knot.cpp @@ -78,9 +78,8 @@ SPKnot::SPKnot(SPDesktop *desktop, gchar const *tip, Inkscape::CanvasItemCtrlTyp image[SP_KNOT_STATE_DRAGGING] = nullptr; image[SP_KNOT_STATE_SELECTED] = nullptr; - ctrl = new Inkscape::CanvasItemCtrl(desktop->getCanvasControls(), type); // Shape, mode set - Glib::ustring ctrl_name = "CanvasItemCtrl:Knot: " + name; - ctrl->set_name(ctrl_name); + ctrl = make_canvasitem(desktop->getCanvasControls(), type); // Shape, mode set + ctrl->set_name("CanvasItemCtrl:Knot:" + name); // Are these needed? ctrl->set_fill(0xffffff00); @@ -101,9 +100,7 @@ SPKnot::~SPKnot() { gdk_seat_ungrab(seat); } - if (ctrl) { - delete ctrl; - } + ctrl.reset(); if (this->tip) { g_free(this->tip); @@ -132,7 +129,8 @@ void SPKnot::startDragging(Geom::Point const &p, gint x, gint y, guint32 etime) grabbed = true; } -void SPKnot::selectKnot(bool select){ +void SPKnot::selectKnot(bool select) +{ setFlag(SP_KNOT_SELECTED, select); } @@ -431,7 +429,6 @@ void SPKnot::updateCtrl() { } ctrl->set_angle(angle); ctrl->set_anchor(anchor); - ctrl->set_pixbuf(static_cast(pixbuf)); } _setCtrlState(); @@ -472,10 +469,6 @@ void SPKnot::setMode(Inkscape::CanvasItemCtrlMode m) { mode = m; } -void SPKnot::setPixbuf(gpointer p) { - pixbuf = p; -} - void SPKnot::setAngle(double i) { angle = i; } diff --git a/src/ui/knot/knot.h b/src/ui/knot/knot.h index bee736a3dabce185b525a20cef76b2bd774bf582..e780d4e9ee88feac86c13e1c2add2ac6adbbdf61 100644 --- a/src/ui/knot/knot.h +++ b/src/ui/knot/knot.h @@ -23,6 +23,7 @@ #include "knot-enums.h" #include "display/control/canvas-item-enums.h" +#include "display/control/canvas-item-ptr.h" #include "enums.h" class SPDesktop; @@ -58,7 +59,7 @@ public: int ref_count; // FIXME encapsulation SPDesktop *desktop = nullptr; /**< Desktop we are on. */ - Inkscape::CanvasItemCtrl *ctrl = nullptr; /**< Our CanvasItemCtrl. */ + CanvasItemPtr ctrl; /**< Our CanvasItemCtrl. */ SPItem *owner = nullptr; /**< Optional Owner Item */ SPItem *sub_owner = nullptr; /**< Optional SubOwner Item */ unsigned int flags = SP_KNOT_VISIBLE; @@ -89,7 +90,6 @@ public: unsigned char *image[SP_KNOT_VISIBLE_STATES]; Glib::RefPtr _cursors[SP_KNOT_VISIBLE_STATES]; - void* pixbuf = nullptr; char *tip = nullptr; sigc::connection _event_connection; @@ -114,7 +114,6 @@ public: void setShape(Inkscape::CanvasItemCtrlShape s); void setAnchor(unsigned int i); void setMode(Inkscape::CanvasItemCtrlMode m); - void setPixbuf(void* p); void setAngle(double i); void setFill(guint32 normal, guint32 mouseover, guint32 dragging, guint32 selected); @@ -139,7 +138,7 @@ public: void setFlag(unsigned int flag, bool set); /** - * Update knot's pixbuf and set its control state. + * Update knot's control state. */ void updateCtrl(); diff --git a/src/ui/tool/control-point.cpp b/src/ui/tool/control-point.cpp index 710bdde1e2bcd2503044427ba653e6b7405931c4..32558d8bfbbbb76d9e57a1911ef388ae810094d9 100644 --- a/src/ui/tool/control-point.cpp +++ b/src/ui/tool/control-point.cpp @@ -79,10 +79,10 @@ ControlPoint::ControlPoint(SPDesktop *d, Geom::Point const &initial_pos, SPAncho , _cset(cset) , _position(initial_pos) { - _canvas_item_ctrl = new Inkscape::CanvasItemCtrl(group ? group : _desktop->getCanvasControls(), + _canvas_item_ctrl = make_canvasitem(group ? group : _desktop->getCanvasControls(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_BITMAP); _canvas_item_ctrl->set_name("CanvasItemCtrl:ControlPoint"); - _canvas_item_ctrl->set_pixbuf(pixbuf->gobj()); + _canvas_item_ctrl->set_pixbuf(std::move(pixbuf)); _canvas_item_ctrl->set_fill( _cset.normal.fill); _canvas_item_ctrl->set_stroke(_cset.normal.stroke); _canvas_item_ctrl->set_anchor(anchor); @@ -98,7 +98,7 @@ ControlPoint::ControlPoint(SPDesktop *d, Geom::Point const &initial_pos, SPAncho , _cset(cset) , _position(initial_pos) { - _canvas_item_ctrl = new Inkscape::CanvasItemCtrl(group ? group : _desktop->getCanvasControls(), type); + _canvas_item_ctrl = make_canvasitem(group ? group : _desktop->getCanvasControls(), type); _canvas_item_ctrl->set_name("CanvasItemCtrl:ControlPoint"); _canvas_item_ctrl->set_fill( _cset.normal.fill); _canvas_item_ctrl->set_stroke(_cset.normal.stroke); @@ -117,7 +117,6 @@ ControlPoint::~ControlPoint() //g_signal_handler_disconnect(G_OBJECT(_canvas_item_ctrl), _event_handler_connection); _event_handler_connection.disconnect(); _canvas_item_ctrl->hide(); - delete _canvas_item_ctrl; } void ControlPoint::_commonInit() @@ -187,11 +186,6 @@ void ControlPoint::_setAnchor(SPAnchorType anchor) // g_object_set(_canvas_item_ctrl, "anchor", anchor, nullptr); } -void ControlPoint::_setPixbuf(Glib::RefPtr p) -{ - _canvas_item_ctrl->set_pixbuf(Glib::unwrap(p)); -} - // re-routes events into the virtual function TODO: Refactor this nonsense. bool ControlPoint::_event_handler(GdkEvent *event, ControlPoint *point) { @@ -246,7 +240,7 @@ bool ControlPoint::_eventHandler(Inkscape::UI::Tools::ToolBase *event_context, G pointer_offset = _position - _desktop->w2d(_drag_event_origin); _drag_initiated = false; // route all events to this handler - _canvas_item_ctrl->grab(_grab_event_mask, nullptr); // cursor is null + _canvas_item_ctrl->grab(_grab_event_mask); // cursor is null _event_grab = true; _setState(STATE_CLICKED); return true; @@ -495,7 +489,7 @@ void ControlPoint::transferGrab(ControlPoint *prev_point, GdkEventMotion *event) grabbed(event); prev_point->_canvas_item_ctrl->ungrab(); - _canvas_item_ctrl->grab(_grab_event_mask, nullptr); // cursor is null + _canvas_item_ctrl->grab(_grab_event_mask); // cursor is null _drag_initiated = true; diff --git a/src/ui/tool/control-point.h b/src/ui/tool/control-point.h index 6ccd28024103a1e881dd95a4fb91ce6f4a74c4a6..345f918504bd13d4a166ddb03789625775c78d03 100644 --- a/src/ui/tool/control-point.h +++ b/src/ui/tool/control-point.h @@ -21,6 +21,7 @@ // #include "ui/control-types.h" #include "display/control/canvas-item-ctrl.h" #include "display/control/canvas-item-enums.h" +#include "display/control/canvas-item-ptr.h" #include "enums.h" // TEMP TEMP @@ -315,8 +316,6 @@ protected: void _setAnchor(SPAnchorType anchor); - void _setPixbuf(Glib::RefPtr); - /** * Determines if the control point is not visible yet still reacting to events. * @@ -340,7 +339,7 @@ protected: virtual bool _hasDragTips() const { return false; } - Inkscape::CanvasItemCtrl * _canvas_item_ctrl = nullptr; ///< Visual representation of the control point. + CanvasItemPtr _canvas_item_ctrl; ///< Visual representation of the control point. ColorSet const &_cset; ///< Colors used to represent the point diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp index a606e140b7ed872221578ddd314a8c9a4770fa33..6b40a774792e83943f7cb2e28d8366fd53699e55 100644 --- a/src/ui/tool/node.cpp +++ b/src/ui/tool/node.cpp @@ -183,17 +183,14 @@ Handle::Handle(NodeSharedData const &data, Geom::Point const &initial_pos, Node : ControlPoint(data.desktop, initial_pos, SP_ANCHOR_CENTER, Inkscape::CANVAS_ITEM_CTRL_TYPE_ROTATE, _handle_colors, data.handle_group) - , _handle_line(new Inkscape::CanvasItemCurve(data.handle_line_group)) + , _handle_line(make_canvasitem(data.handle_line_group)) , _parent(parent) , _degenerate(true) { setVisible(false); } -Handle::~Handle() -{ - delete _handle_line; -} +Handle::~Handle() = default; void Handle::setVisible(bool v) { @@ -1140,7 +1137,7 @@ bool Node::isEndNode() const void Node::sink() { - _canvas_item_ctrl->set_z_position(0); + _canvas_item_ctrl->lower_to_bottom(); } NodeType Node::parse_nodetype(char x) diff --git a/src/ui/tool/node.h b/src/ui/tool/node.h index 0630e4f0d5df0ec00c954fad95703044b9dd6b62..0a500d1587a91d96fd224aaa04ee916acb8a79fd 100644 --- a/src/ui/tool/node.h +++ b/src/ui/tool/node.h @@ -27,12 +27,6 @@ namespace Inkscape { class CanvasItemGroup; class CanvasItemCurve; -namespace UI { -template class NodeIterator; -} -} - -namespace Inkscape { namespace UI { class PathManipulator; @@ -46,20 +40,6 @@ template class NodeIterator; std::ostream &operator<<(std::ostream &, NodeType); -/* -template -struct ListMember { - T *next; - T *prev; -}; -struct SubpathMember : public ListMember { - Subpath *list; -}; -struct SubpathListMember : public ListMember { - SubpathList *list; -}; -*/ - struct ListNode { ListNode *ln_next; ListNode *ln_prev; @@ -117,7 +97,7 @@ private: inline PathManipulator &_pm() const; Node *_parent; // the handle's lifetime does not extend beyond that of the parent node, // so a naked pointer is OK and allows setting it during Node's construction - CanvasItemCurve *_handle_line; + CanvasItemPtr _handle_line; bool _degenerate; // True if the handle is retracted, i.e. has zero length. This is used often internally so it makes sense to cache this /** diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp index e5792ba12e1b8ec720d969c9cd940e5aa7d0a859..047b2ac9bbf3386c3bf28dde94d632724d087a29 100644 --- a/src/ui/tool/path-manipulator.cpp +++ b/src/ui/tool/path-manipulator.cpp @@ -127,7 +127,7 @@ PathManipulator::PathManipulator(MultiPathManipulator &mpm, SPObject *path, _getGeometry(); - _outline = new Inkscape::CanvasItemBpath(_multi_path_manipulator._path_data.outline_group); + _outline = make_canvasitem(_multi_path_manipulator._path_data.outline_group); _outline->hide(); _outline->set_stroke(outline_color); _outline->set_fill(0x0, SP_WIND_RULE_NONZERO); @@ -148,7 +148,7 @@ PathManipulator::~PathManipulator() { delete _dragpoint; delete _observer; - delete _outline; + _outline.reset(); clear(); } diff --git a/src/ui/tool/path-manipulator.h b/src/ui/tool/path-manipulator.h index 76defddd4488568cd0803fd73860a918f0d4bc85..4a658dfdd394e8d482dc296742a40d623f2aa4d6 100644 --- a/src/ui/tool/path-manipulator.h +++ b/src/ui/tool/path-manipulator.h @@ -150,7 +150,7 @@ private: MultiPathManipulator &_multi_path_manipulator; SPObject *_path; ///< can be an SPPath or an Inkscape::LivePathEffect::Effect !!! SPCurve _spcurve; // in item coordinates - Inkscape::CanvasItemBpath *_outline = nullptr; + CanvasItemPtr _outline; CurveDragPoint *_dragpoint; // an invisible control point hovering over curve PathManipulatorObserver *_observer; Geom::Affine _d2i_transform; ///< desktop-to-item transform diff --git a/src/ui/toolbar/eraser-toolbar.h b/src/ui/toolbar/eraser-toolbar.h index c993e46627d0c240234f31a83204dbc6eda66888..d03590f211c44056e701b3eb6f56fd35f5062155 100644 --- a/src/ui/toolbar/eraser-toolbar.h +++ b/src/ui/toolbar/eraser-toolbar.h @@ -44,7 +44,6 @@ class SimplePrefPusher; namespace Tools { enum class EraserToolMode; -extern EraserToolMode const DEFAULT_ERASER_MODE; } // namespace Tools namespace Widget { diff --git a/src/ui/tools/booleans-builder.cpp b/src/ui/tools/booleans-builder.cpp index d5388ac127c323838b252a05b6b62f142ef72a23..e4996f1fb2049b6fd7b538b3d8739b8318f049ea 100644 --- a/src/ui/tools/booleans-builder.cpp +++ b/src/ui/tools/booleans-builder.cpp @@ -33,7 +33,7 @@ BooleanBuilder::BooleanBuilder(ObjectSet *set) _work_items = SubItem::build_mosaic(set->items_vector()); auto root = _set->desktop()->getCanvas()->get_canvas_item_root(); - _group = std::make_unique(root); + _group = make_canvasitem(root); auto nv = _set->desktop()->getNamedView(); desk_modified_connection = nv->connectModified([=](SPObject *obj, guint flags) { @@ -51,8 +51,8 @@ void BooleanBuilder::redraw_item(CanvasItemBpath &bpath, bool selected, TaskType { int i = (int)task * 2 + (int)selected; bpath.set_fill(_dark ? fill_dark[i] : fill_lite[i], SP_WIND_RULE_POSITIVE); - bpath.set_stroke(task == TASKED_NONE ? 0x000000dd : 0xffffffff); - bpath.set_stroke_width(task == TASKED_NONE ? 1.0 : 3.0); + bpath.set_stroke(task == TaskType::NONE ? 0x000000dd : 0xffffffff); + bpath.set_stroke_width(task == TaskType::NONE ? 1.0 : 3.0); } /** @@ -67,22 +67,22 @@ void BooleanBuilder::redraw_items() for (auto &subitem : _work_items) { // Construct BPath from each subitem! - auto bpath = std::make_shared(_group.get(), subitem->get_pathv(), false); - redraw_item(*bpath, subitem->getSelected(), TASKED_NONE); - _screen_items.emplace_back(subitem, std::move(bpath)); + auto bpath = make_canvasitem(_group.get(), subitem->get_pathv(), false); + redraw_item(*bpath, subitem->getSelected(), TaskType::NONE); + _screen_items.push_back({ subitem, std::move(bpath), true }); } // Selectively handle the undo actions being enabled / disabled enable_undo_actions(_set->document(), _undo.size(), _redo.size()); } -std::optional BooleanBuilder::get_item(const Geom::Point &point) +ItemPair *BooleanBuilder::get_item(const Geom::Point &point) { for (auto &pair : _screen_items) { - if (pair.second->contains(point, 2.0)) - return pair; + if (pair.vis->contains(point, 2.0)) + return &pair; } - return {}; + return nullptr; } /** @@ -94,11 +94,11 @@ bool BooleanBuilder::highlight(const Geom::Point &point, bool add) return true; bool done = false; - for (auto &[work, vis] : _screen_items) { - bool hover = !done && vis->contains(point, 2.0); - redraw_item(*vis, work->getSelected(), hover ? (add ? TASKED_ADD : TASKED_DELETE) : TASKED_NONE); + for (auto &si : _screen_items) { + bool hover = !done && si.vis->contains(point, 2.0); + redraw_item(*si.vis, si.work->getSelected(), hover ? (add ? TaskType::ADD : TaskType::DELETE) : TaskType::NONE); if (hover) - vis->raise_to_top(); + si.vis->raise_to_top(); done = done || hover; } return done; @@ -111,15 +111,15 @@ bool BooleanBuilder::task_select(const Geom::Point &point, bool add_task) { if (has_task()) task_cancel(); - if (auto maybe = get_item(point)) { + if (auto si = get_item(point)) { _add_task = add_task; - auto &[work, vis] = maybe.value(); - _work_task = std::make_shared(*work); + _work_task = std::make_shared(*si->work); _work_task->setSelected(true); - _screen_task = std::make_shared(_group.get(), _work_task->get_pathv(), false); - redraw_item(*_screen_task, true, add_task ? TASKED_ADD : TASKED_DELETE); - vis->set_visible(false); - redraw_item(*vis, false, TASKED_NONE); + _screen_task = make_canvasitem(_group.get(), _work_task->get_pathv(), false); + redraw_item(*_screen_task, true, add_task ? TaskType::ADD : TaskType::DELETE); + si->vis->hide(); + si->visible = false; + redraw_item(*si->vis, false, TaskType::NONE); return true; } return false; @@ -129,12 +129,12 @@ bool BooleanBuilder::task_add(const Geom::Point &point) { if (!has_task()) return false; - if (auto maybe = get_item(point)) { - auto &[work, vis] = maybe.value(); + if (auto si = get_item(point)) { // Invisible items are already processed. - if (vis->is_visible()) { - vis->set_visible(false); - *_work_task += *work; + if (si->visible) { + si->vis->hide(); + si->visible = false; + *_work_task += *si->work; _screen_task->set_bpath(_work_task->get_pathv(), false); return true; } @@ -146,8 +146,9 @@ void BooleanBuilder::task_cancel() { _work_task.reset(); _screen_task.reset(); - for (auto &[work, vis] : _screen_items) { - vis->set_visible(true); + for (auto &si : _screen_items) { + si.vis->show(); + si.visible = true; } } @@ -162,9 +163,9 @@ void BooleanBuilder::task_commit() // A. Delete all items from _work_items that aren't visible _work_items.clear(); - for (auto &[work, vis] : _screen_items) { - if (vis->is_visible()) { - _work_items.emplace_back(work); + for (auto &si : _screen_items) { + if (si.visible) { + _work_items.emplace_back(si.work); } } if (_add_task) { diff --git a/src/ui/tools/booleans-builder.h b/src/ui/tools/booleans-builder.h index 637863c4f7750cebdf439d5d9f5684f144bfa361..b97289c10251655f811afb2b3dc8df41edb71ed3 100644 --- a/src/ui/tools/booleans-builder.h +++ b/src/ui/tools/booleans-builder.h @@ -13,10 +13,11 @@ #include #include -#include +#include "helper/auto-connection.h" #include "booleans-subitems.h" #include "helper/auto-connection.h" +#include "display/control/canvas-item-ptr.h" class SPDesktop; class SPDocument; @@ -28,14 +29,19 @@ class CanvasItemGroup; class CanvasItemBpath; class ObjectSet; -using VisualItem = std::shared_ptr; -using ItemPair = std::pair; +using VisualItem = CanvasItemPtr; +struct ItemPair +{ + WorkItem work; + VisualItem vis; + bool visible; +}; -using TaskType = int; -enum TaskTypes : TaskType { - TASKED_NONE, - TASKED_ADD, - TASKED_DELETE +enum class TaskType +{ + NONE, + ADD, + DELETE }; class BooleanBuilder @@ -44,12 +50,11 @@ public: BooleanBuilder(ObjectSet *obj); ~BooleanBuilder(); - void redraw_items(); void undo(); void redo(); std::vector shape_commit(bool all = false); - std::optional get_item(const Geom::Point &point); + ItemPair *get_item(const Geom::Point &point); bool task_select(const Geom::Point &point, bool add_task = true); bool task_add(const Geom::Point &point); void task_cancel(); @@ -58,9 +63,8 @@ public: bool highlight(const Geom::Point &point, bool add_task = true); private: - ObjectSet *_set; - std::unique_ptr _group; + CanvasItemPtr _group; std::vector _work_items; std::vector _screen_items; @@ -76,6 +80,7 @@ private: auto_connection desk_modified_connection; void redraw_item(CanvasItemBpath &bpath, bool selected, TaskType task); + void redraw_items(); }; } // namespace Inkscape diff --git a/src/ui/tools/calligraphic-tool.cpp b/src/ui/tools/calligraphic-tool.cpp index 8f027e8bbcbbcd89e685f28ba1bf9027dadb5947..7cb631fd0a8f90baa26d5387aad5ab0ab3108301 100644 --- a/src/ui/tools/calligraphic-tool.cpp +++ b/src/ui/tools/calligraphic-tool.cpp @@ -107,14 +107,14 @@ CalligraphicTool::CalligraphicTool(SPDesktop *desktop) this->cap_rounding = 0.0; this->abs_width = false; - currentshape = new Inkscape::CanvasItemBpath(desktop->getCanvasSketch()); + currentshape = make_canvasitem(desktop->getCanvasSketch()); currentshape->set_stroke(0x0); currentshape->set_fill(DDC_RED_RGBA, SP_WIND_RULE_EVENODD); /* fixme: Cannot we cascade it to root more clearly? */ currentshape->connect_event(sigc::bind(sigc::ptr_fun(sp_desktop_root_handler), desktop)); - hatch_area = new Inkscape::CanvasItemBpath(desktop->getCanvasControls()); + hatch_area = make_canvasitem(desktop->getCanvasControls()); hatch_area->set_fill(0x0, SP_WIND_RULE_EVENODD); hatch_area->set_stroke(0x0000007f); hatch_area->set_pickable(false); @@ -142,13 +142,7 @@ CalligraphicTool::CalligraphicTool(SPDesktop *desktop) } } -CalligraphicTool::~CalligraphicTool() -{ - if (hatch_area) { - delete hatch_area; - hatch_area = nullptr; - } -} +CalligraphicTool::~CalligraphicTool() = default; void CalligraphicTool::set(const Inkscape::Preferences::Entry& val) { Glib::ustring path = val.getEntryName(); @@ -403,9 +397,6 @@ void CalligraphicTool::cancel() { ungrabCanvasEvents(); /* Remove all temporary line segments */ - for (auto segment : segments) { - delete segment; - } segments.clear(); /* reset accumulated curve */ @@ -663,7 +654,7 @@ bool CalligraphicTool::root_handler(GdkEvent* event) { Geom::Affine const sm (Geom::Scale(hatch_dist, hatch_dist) * Geom::Translate(c)); path *= sm; - hatch_area->set_bpath(path, true); + hatch_area->set_bpath(std::move(path), true); hatch_area->set_stroke(0x7f7f7fff); hatch_area->show(); @@ -674,7 +665,7 @@ bool CalligraphicTool::root_handler(GdkEvent* event) { Geom::Affine const sm (Geom::Scale(this->hatch_spacing, this->hatch_spacing) * Geom::Translate(c)); path *= sm; - hatch_area->set_bpath(path, true); + hatch_area->set_bpath(std::move(path), true); hatch_area->set_stroke(0x00FF00ff); hatch_area->show(); @@ -685,7 +676,7 @@ bool CalligraphicTool::root_handler(GdkEvent* event) { Geom::Affine const sm (Geom::Scale(this->hatch_spacing, this->hatch_spacing) * Geom::Translate(c)); path *= sm; - hatch_area->set_bpath(path, true); + hatch_area->set_bpath(std::move(path), true); hatch_area->set_stroke(0xff0000ff); hatch_area->show(); @@ -697,7 +688,7 @@ bool CalligraphicTool::root_handler(GdkEvent* event) { Geom::Affine const sm (Geom::Scale(this->hatch_spacing, this->hatch_spacing) * Geom::Translate(c)); path *= sm; - hatch_area->set_bpath(path, true); + hatch_area->set_bpath(std::move(path), true); hatch_area->set_stroke(0x7f7f7fff); hatch_area->show(); } @@ -725,9 +716,6 @@ bool CalligraphicTool::root_handler(GdkEvent* event) { this->apply(motion_dt); /* Remove all temporary line segments */ - for (auto segment : segments) { - delete segment; - } segments.clear(); /* Create object */ @@ -1127,7 +1115,7 @@ void CalligraphicTool::fit_and_split(bool release) { /* fixme: Cannot we cascade it to root more clearly? */ cbp->connect_event(sigc::bind(sigc::ptr_fun(sp_desktop_root_handler), _desktop)); - segments.push_back(cbp); + segments.emplace_back(cbp); } this->point1[0] = this->point1[this->npoints - 1]; diff --git a/src/ui/tools/calligraphic-tool.h b/src/ui/tools/calligraphic-tool.h index 8f43a4f3f1a5c2b5afb70626b005783ad2f629fc..75b2a4a9291200f125cb797205392b427e865697 100644 --- a/src/ui/tools/calligraphic-tool.h +++ b/src/ui/tools/calligraphic-tool.h @@ -24,6 +24,7 @@ #include <2geom/point.h> +#include "display/control/canvas-item-ptr.h" #include "ui/tools/dynamic-base.h" class SPItem; @@ -66,7 +67,7 @@ private: Geom::Point hatch_last_nearest, hatch_last_pointer; std::list hatch_vectors; bool hatch_escaped; - Inkscape::CanvasItemBpath *hatch_area = nullptr; + CanvasItemPtr hatch_area; bool just_started_drawing; bool trace_bg; diff --git a/src/ui/tools/dropper-tool.cpp b/src/ui/tools/dropper-tool.cpp index 6d5ab8f23880ccca128f98377075d67f8bb5f3f7..6fdcd0c3f4eb3d011513c2f85680d2d4deef042c 100644 --- a/src/ui/tools/dropper-tool.cpp +++ b/src/ui/tools/dropper-tool.cpp @@ -53,7 +53,7 @@ namespace Tools { DropperTool::DropperTool(SPDesktop *desktop) : ToolBase(desktop, "/tools/dropper", "dropper-pick-fill.svg") { - area = new Inkscape::CanvasItemBpath(desktop->getCanvasControls()); + area = make_canvasitem(desktop->getCanvasControls()); area->set_stroke(0x0000007f); area->set_fill(0x0, SP_WIND_RULE_EVENODD); area->hide(); @@ -74,11 +74,6 @@ DropperTool::~DropperTool() this->enableGrDrag(false); ungrabCanvasEvents(); - - if (this->area) { - delete this->area; - this->area = nullptr; - } } /** @@ -217,7 +212,7 @@ bool DropperTool::root_handler(GdkEvent* event) { // Show circle on canvas Geom::PathVector path = Geom::Path(Geom::Circle(0, 0, 1)); // Unit circle centered at origin. path *= sm; - this->area->set_bpath(path); + this->area->set_bpath(std::move(path)); this->area->show(); /* Get buffer */ diff --git a/src/ui/tools/dropper-tool.h b/src/ui/tools/dropper-tool.h index e0398af2b43b298f7e90184f20986fc0d86f3cb7..5222ca3712354e8a4bd7463edd9dee7f8f532c12 100644 --- a/src/ui/tools/dropper-tool.h +++ b/src/ui/tools/dropper-tool.h @@ -16,6 +16,7 @@ #include <2geom/point.h> #include "color-rgba.h" +#include "display/control/canvas-item-ptr.h" #include "ui/tools/tool-base.h" struct SPCanvasItem; @@ -70,7 +71,7 @@ private: bool dragging = false; ///< When true, get average color for region on canvas, instead of a single point double radius = 0.0; ///< Size of region under dragging mode - Inkscape::CanvasItemBpath* area = nullptr; ///< Circle depicting region's borders in dragging mode + CanvasItemPtr area; ///< Circle depicting region's borders in dragging mode Geom::Point centre {0, 0}; ///< Center of region in dragging mode }; diff --git a/src/ui/tools/dynamic-base.cpp b/src/ui/tools/dynamic-base.cpp index 78dd40feb52e5c15b9a3cc204e6afadf872c4c6b..5f9de6a0f1dc8decb3031da530c89711d8000a9f 100644 --- a/src/ui/tools/dynamic-base.cpp +++ b/src/ui/tools/dynamic-base.cpp @@ -36,7 +36,6 @@ namespace Tools { DynamicBase::DynamicBase(SPDesktop *desktop, std::string prefs_path, const std::string &cursor_filename) : ToolBase(desktop, prefs_path, cursor_filename) - , currentshape(nullptr) , point1() , point2() , npoints(0) @@ -67,16 +66,7 @@ DynamicBase::DynamicBase(SPDesktop *desktop, std::string prefs_path, const std:: { } -DynamicBase::~DynamicBase() { - for (auto segment : segments) { - delete segment; - } - segments.clear(); - - if (currentshape) { - delete currentshape; - } -} +DynamicBase::~DynamicBase() = default; void DynamicBase::set(const Inkscape::Preferences::Entry& value) { Glib::ustring path = value.getEntryName(); diff --git a/src/ui/tools/dynamic-base.h b/src/ui/tools/dynamic-base.h index 9102a7d53abb748da0a6b9d0a2972f5b91b85a62..46fa5fd1129f2242fb104ac7b22f1ed9b4b35821 100644 --- a/src/ui/tools/dynamic-base.h +++ b/src/ui/tools/dynamic-base.h @@ -22,6 +22,7 @@ #include "ui/tools/tool-base.h" #include "display/curve.h" +#include "display/control/canvas-item-ptr.h" #include @@ -54,10 +55,10 @@ protected: SPCurve accumulated; /** canvas items for "committed" segments */ - std::vector segments; + std::vector> segments; /** canvas item for red "leading" segment */ - Inkscape::CanvasItemBpath *currentshape; + CanvasItemPtr currentshape; /** shape of red "leading" segment */ SPCurve currentcurve; diff --git a/src/ui/tools/eraser-tool.cpp b/src/ui/tools/eraser-tool.cpp index 3d0acca9e8ea4a385ecd3d3f61379c66593073e8..e1115331859a7ef9756b1006b0ae6521d3f65211 100644 --- a/src/ui/tools/eraser-tool.cpp +++ b/src/ui/tools/eraser-tool.cpp @@ -80,14 +80,12 @@ namespace Inkscape { namespace UI { namespace Tools { -extern EraserToolMode const DEFAULT_ERASER_MODE = EraserToolMode::CUT; - EraserTool::EraserTool(SPDesktop *desktop) : DynamicBase(desktop, "/tools/eraser", "eraser.svg") , _break_apart{"/tools/eraser/break_apart", false} , _mode_int{"/tools/eraser/mode", 1} // Cut mode is default { - currentshape = new Inkscape::CanvasItemBpath(desktop->getCanvasSketch()); + currentshape = make_canvasitem(desktop->getCanvasSketch()); currentshape->set_stroke(0x0); currentshape->set_fill(trace_color_rgba, trace_wind_rule); @@ -118,11 +116,7 @@ EraserTool::EraserTool(SPDesktop *desktop) enableSelectionCue(); } -EraserTool::~EraserTool() -{ - delete currentshape; - currentshape = nullptr; -} +EraserTool::~EraserTool() = default; /** Reads the current Eraser mode from Preferences and sets `mode` accordingly. */ void EraserTool::_updateMode() @@ -353,7 +347,7 @@ void EraserTool::_cancel() is_drawing = false; ungrabCanvasEvents(); - _removeTemporarySegments(); + segments.clear(); /* reset accumulated curve */ accumulated.reset(); @@ -361,15 +355,6 @@ void EraserTool::_cancel() repr = nullptr; } -/** Removes all temporary line segments */ -void EraserTool::_removeTemporarySegments() -{ - for (auto segment : segments) { - delete segment; - } - segments.clear(); -} - bool EraserTool::root_handler(GdkEvent* event) { bool ret = false; @@ -451,7 +436,7 @@ bool EraserTool::root_handler(GdkEvent* event) dragging = false; _apply(motion_dt); - _removeTemporarySegments(); + segments.clear(); // Create eraser stroke shape _fitAndSplit(true); @@ -1380,7 +1365,7 @@ void EraserTool::_fitDrawLastPoint() /* fixme: Cannot we cascade it to root more clearly? */ cbp->connect_event(sigc::bind(sigc::ptr_fun(sp_desktop_root_handler), _desktop)); - segments.push_back(cbp); + segments.emplace_back(cbp); if (mode == EraserToolMode::DELETE) { cbp->hide(); diff --git a/src/ui/tools/eraser-tool.h b/src/ui/tools/eraser-tool.h index e6cd0e774d8de9801c44b2c5f2d585a3dc5bd38f..5198ebd3dd2bd2e6b95a5ecde528ed0bcf3d4c7e 100644 --- a/src/ui/tools/eraser-tool.h +++ b/src/ui/tools/eraser-tool.h @@ -37,7 +37,7 @@ enum class EraserToolMode CUT, CLIP }; -extern EraserToolMode const DEFAULT_ERASER_MODE; +static inline constexpr auto DEFAULT_ERASER_MODE = EraserToolMode::CUT; /** Represents an item to erase */ struct EraseTarget @@ -65,26 +65,26 @@ private: Pref _mode_int; // static data: - inline static guint32 const trace_color_rgba = 0xff0000ff; // RGBA red - inline static SPWindRule const trace_wind_rule = SP_WIND_RULE_EVENODD; + static constexpr uint32_t trace_color_rgba = 0xff0000ff; // RGBA red + static constexpr SPWindRule trace_wind_rule = SP_WIND_RULE_EVENODD; - inline static double const tolerance = 0.1; + static constexpr double tolerance = 0.1; - inline static double const epsilon = 0.5e-6; - inline static double const epsilon_start = 0.5e-2; - inline static double const vel_start = 1e-5; + static constexpr double epsilon = 0.5e-6; + static constexpr double epsilon_start = 0.5e-2; + static constexpr double vel_start = 1e-5; - inline static double const drag_default = 1.0; - inline static double const drag_min = 0.0; - inline static double const drag_max = 1.0; + static constexpr double drag_default = 1.0; + static constexpr double drag_min = 0.0; + static constexpr double drag_max = 1.0; - inline static double const min_pressure = 0.0; - inline static double const max_pressure = 1.0; - inline static double const default_pressure = 1.0; + static constexpr double min_pressure = 0.0; + static constexpr double max_pressure = 1.0; + static constexpr double default_pressure = 1.0; - inline static double const min_tilt = -1.0; - inline static double const max_tilt = 1.0; - inline static double const default_tilt = 0.0; + static constexpr double min_tilt = -1.0; + static constexpr double max_tilt = 1.0; + static constexpr double default_tilt = 0.0; public: // public member functions @@ -93,11 +93,11 @@ public: bool root_handler(GdkEvent *event) final; using Error = std::uint64_t; - inline static Error const ALL_GOOD = 0x0; - inline static Error const NON_EXISTENT = 0x1 << 1; - inline static Error const NO_AREA_PATH = 0x1 << 2; - inline static Error const RASTER_IMAGE = 0x1 << 3; - inline static Error const ERROR_GROUP = 0x1 << 4; + static constexpr Error ALL_GOOD = 0x0; + static constexpr Error NON_EXISTENT = 0x1 << 1; + static constexpr Error NO_AREA_PATH = 0x1 << 2; + static constexpr Error RASTER_IMAGE = 0x1 << 3; + static constexpr Error ERROR_GROUP = 0x1 << 4; private: // private member functions @@ -124,7 +124,6 @@ private: void _handleStrokeStyle(SPItem *item) const; SPItem *_insertAcidIntoDocument(SPDocument *document); bool _performEraseOperation(std::vector const &items_to_erase, bool store_survivers); - void _removeTemporarySegments(); void _reset(Geom::Point p); void _setStatusBarMessage(char *message); void _updateMode(); diff --git a/src/ui/tools/freehand-base.cpp b/src/ui/tools/freehand-base.cpp index 04f7af8e91cc205cb78f489ad33524a54a8a1bd0..30768208e51d2e7f87979062019d5d9fe7c241f6 100644 --- a/src/ui/tools/freehand-base.cpp +++ b/src/ui/tools/freehand-base.cpp @@ -76,8 +76,6 @@ FreehandBase::FreehandBase(SPDesktop *desktop, std::string prefs_path, const std , blue_color(0x0000ff7f) , green_color(0x00ff007f) , highlight_color(0x0000007f) - , red_bpath(nullptr) - , blue_bpath(nullptr) , green_closed(false) , white_item(nullptr) , sa(nullptr) @@ -96,12 +94,12 @@ FreehandBase::FreehandBase(SPDesktop *desktop, std::string prefs_path, const std sel_modified_connection = selection->connectModified([=](Selection *, guint) { onSelectionModified(); }); // Create red bpath - this->red_bpath = new Inkscape::CanvasItemBpath(desktop->getCanvasSketch()); + this->red_bpath = make_canvasitem(desktop->getCanvasSketch()); this->red_bpath->set_stroke(this->red_color); this->red_bpath->set_fill(0x0, SP_WIND_RULE_NONZERO); // Create blue bpath - this->blue_bpath = new Inkscape::CanvasItemBpath(desktop->getCanvasSketch()); + this->blue_bpath = make_canvasitem(desktop->getCanvasSketch()); this->blue_bpath->set_stroke(this->blue_color); this->blue_bpath->set_fill(0x0, SP_WIND_RULE_NONZERO); @@ -693,9 +691,6 @@ void spdc_concat_colors_and_flush(FreehandBase *dc, gboolean forceclosed) // Green auto c = std::make_shared(); std::swap(c, dc->green_curve); - for (auto path : dc->green_bpaths) { - delete path; - } dc->green_bpaths.clear(); // Blue @@ -905,24 +900,15 @@ SPDrawAnchor *spdc_test_inside(FreehandBase *dc, Geom::Point p) static void spdc_free_colors(FreehandBase *dc) { // Red - if (dc->red_bpath) { - delete dc->red_bpath; - dc->red_bpath = nullptr; - } + dc->red_bpath.reset(); // Blue - if (dc->blue_bpath) { - delete dc->blue_bpath; - dc->blue_bpath = nullptr; - } + dc->blue_bpath.reset(); dc->blue_curve.reset(); // Overwrite start anchor curve dc->sa_overwrited.reset(); // Green - for (auto path : dc->green_bpaths) { - delete path; - } dc->green_bpaths.clear(); dc->green_curve.reset(); dc->green_anchor.reset(); diff --git a/src/ui/tools/freehand-base.h b/src/ui/tools/freehand-base.h index 2fe165eccd43721d596685427435f2b6f3224f0c..a803a74fa89d5281c0a4b2085fb2fb23f5decb9d 100644 --- a/src/ui/tools/freehand-base.h +++ b/src/ui/tools/freehand-base.h @@ -23,6 +23,7 @@ #include "ui/tools/tool-base.h" #include "live_effects/effect-enum.h" #include "display/curve.h" +#include "display/control/canvas-item-ptr.h" class SPCurve; class SPCanvasItem; @@ -55,16 +56,16 @@ protected: public: // Red - Last segment as it's drawn. - Inkscape::CanvasItemBpath *red_bpath; + CanvasItemPtr red_bpath; SPCurve red_curve; std::optional red_curve_get_last_point(); // Blue - New path after LPE as it's drawn. - Inkscape::CanvasItemBpath *blue_bpath; + CanvasItemPtr blue_bpath; SPCurve blue_curve; // Green - New path as it's drawn. - std::vector green_bpaths; + std::vector> green_bpaths; std::shared_ptr green_curve; std::unique_ptr green_anchor; bool green_closed; // a flag meaning we hit the green anchor, so close the path on itself diff --git a/src/ui/tools/gradient-tool.cpp b/src/ui/tools/gradient-tool.cpp index 4820ce30323b8a1e7da25f518d09345c5302aa54..969b0695c1069f64a9926efdf40360b210f38605 100644 --- a/src/ui/tools/gradient-tool.cpp +++ b/src/ui/tools/gradient-tool.cpp @@ -175,14 +175,15 @@ void GradientTool::select_prev() SPItem *GradientTool::is_over_curve(Geom::Point event_p) { - //Translate mouse point into proper coord system: needed later. + // Translate mouse point into proper coord system: needed later. mousepoint_doc = _desktop->w2d(event_p); - for (auto curve : _grdrag->item_curves) { - if (curve->contains(event_p, tolerance)) { - return curve->get_item(); + for (auto &it : _grdrag->item_curves) { + if (it.curve->contains(event_p, tolerance)) { + return it.item; } } + return nullptr; } diff --git a/src/ui/tools/lpe-tool.cpp b/src/ui/tools/lpe-tool.cpp index 062b85c9f7fc773b681b0cdcac8ba777a073d18a..5149afc609a281f9da517dd396e947728c2836bf 100644 --- a/src/ui/tools/lpe-tool.cpp +++ b/src/ui/tools/lpe-tool.cpp @@ -72,7 +72,7 @@ LpeTool::LpeTool(SPDesktop *desktop) this->sel_changed_connection = selection->connectChanged(sigc::bind(sigc::ptr_fun(&sp_lpetool_context_selection_changed), (gpointer)this)); - this->shape_editor = new ShapeEditor(desktop); + shape_editor = std::make_unique(desktop); lpetool_context_switch_mode(this, Inkscape::LivePathEffect::INVALID_LPE); lpetool_context_reset_limiting_bbox(this); @@ -94,16 +94,11 @@ LpeTool::LpeTool(SPDesktop *desktop) LpeTool::~LpeTool() { - delete this->shape_editor; - - if (canvas_bbox) { - delete canvas_bbox; - } - - lpetool_delete_measuring_items(this); + shape_editor.reset(); + canvas_bbox.reset(); measuring_items.clear(); - this->sel_changed_connection.disconnect(); + sel_changed_connection.disconnect(); } /** @@ -326,10 +321,7 @@ lpetool_get_limiting_bbox_corners(SPDocument *document, Geom::Point &A, Geom::Po void lpetool_context_reset_limiting_bbox(LpeTool *lc) { - if (lc->canvas_bbox) { - delete lc->canvas_bbox; - lc->canvas_bbox = nullptr; - } + lc->canvas_bbox.reset(); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (!prefs->getBool("/tools/lpetool/show_bbox", true)) @@ -344,7 +336,7 @@ lpetool_context_reset_limiting_bbox(LpeTool *lc) B *= doc2dt; Geom::Rect rect(A, B); - lc->canvas_bbox = new Inkscape::CanvasItemRect(lc->getDesktop()->getCanvasControls(), rect); + lc->canvas_bbox = make_canvasitem(lc->getDesktop()->getCanvasControls(), rect); lc->canvas_bbox->set_stroke(0x0000ffff); lc->canvas_bbox->set_dashed(true); } @@ -375,7 +367,6 @@ lpetool_create_measuring_items(LpeTool *lc, Inkscape::Selection *selection) Inkscape::Preferences *prefs = Inkscape::Preferences::get(); bool show = prefs->getBool("/tools/lpetool/show_measuring_info", true); - Inkscape::CanvasItemText *canvas_text; Inkscape::CanvasItemGroup *tmpgrp = lc->getDesktop()->getCanvasTemp(); Inkscape::Util::Unit const * unit = nullptr; @@ -399,23 +390,19 @@ lpetool_create_measuring_items(LpeTool *lc, Inkscape::Selection *selection) arc_length += " "; arc_length += unit->abbr; - canvas_text = new Inkscape::CanvasItemText(tmpgrp, Geom::Point(0,0), arc_length); - set_pos_and_anchor(canvas_text, pwd2, 0.5, 10); + auto canvas_text = make_canvasitem(tmpgrp, Geom::Point(0,0), arc_length); + set_pos_and_anchor(canvas_text.get(), pwd2, 0.5, 10); if (!show) { canvas_text->hide(); } - (lc->measuring_items)[path] = canvas_text; + lc->measuring_items[path] = std::move(canvas_text); } } } -void -lpetool_delete_measuring_items(LpeTool *lc) +void lpetool_delete_measuring_items(LpeTool *lc) { - for (auto& i : lc->measuring_items) { - delete i.second; - } lc->measuring_items.clear(); } @@ -442,8 +429,8 @@ lpetool_update_measuring_items(LpeTool *lc) arc_length += " "; arc_length += unit->abbr; - i.second->set_text(arc_length); - set_pos_and_anchor(i.second, pwd2, 0.5, 10); + i.second->set_text(std::move(arc_length)); + set_pos_and_anchor(i.second.get(), pwd2, 0.5, 10); } } diff --git a/src/ui/tools/lpe-tool.h b/src/ui/tools/lpe-tool.h index fd77a13ad4c514345ee41e35e3212b1c294b30b4..498031e73df430cb3f5fd4c2bced2fe525e221cf 100644 --- a/src/ui/tools/lpe-tool.h +++ b/src/ui/tools/lpe-tool.h @@ -55,11 +55,11 @@ public: LpeTool(SPDesktop *desktop); ~LpeTool() override; - ShapeEditor* shape_editor = nullptr; - Inkscape::CanvasItemRect *canvas_bbox = nullptr; + std::unique_ptr shape_editor; + CanvasItemPtr canvas_bbox; Inkscape::LivePathEffect::EffectType mode; - std::map measuring_items; + std::map> measuring_items; sigc::connection sel_changed_connection; sigc::connection sel_modified_connection; diff --git a/src/ui/tools/measure-tool.cpp b/src/ui/tools/measure-tool.cpp index b9faeebf1217497c3eb72d8439431c2fc59f6794..e3865ad76448d467c9ad0a6faf5c13e5c591e434 100644 --- a/src/ui/tools/measure-tool.cpp +++ b/src/ui/tools/measure-tool.cpp @@ -189,8 +189,6 @@ Geom::Point calcAngleDisplayAnchor(SPDesktop *desktop, double angle, double base */ void MeasureTool::createAngleDisplayCurve(Geom::Point const ¢er, Geom::Point const &end, Geom::Point const &anchor, double angle, bool to_phantom, - std::vector &measure_phantom_items, - std::vector &measure_tmp_items, Inkscape::XML::Node *measure_repr) { // Given that we have a point on the arc's edge and the angle of the arc, we need to get the two endpoints. @@ -261,7 +259,7 @@ void MeasureTool::createAngleDisplayCurve(Geom::Point const ¢er, Geom::Point auto *curve = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p1, p2, p3, p4); curve->set_name("CanvasItemCurve:MeasureToolCurve"); curve->set_stroke(Inkscape::CANVAS_ITEM_SECONDARY); - curve->set_z_position(0); + curve->lower_to_bottom(); curve->show(); if(to_phantom){ curve->set_stroke(0x8888887f); @@ -339,19 +337,8 @@ MeasureTool::~MeasureTool() knot_unref(this->knot_start); knot_unref(this->knot_end); - for (auto & measure_tmp_item : measure_tmp_items) { - delete measure_tmp_item; - } measure_tmp_items.clear(); - - for (auto & idx : measure_item) { - delete idx; - } measure_item.clear(); - - for (auto & measure_phantom_item : measure_phantom_items) { - delete measure_phantom_item; - } measure_phantom_items.clear(); } @@ -537,9 +524,6 @@ bool MeasureTool::root_handler(GdkEvent* event) } } else { // Inkscape::Util::Unit const * unit = _desktop->getNamedView()->getDisplayUnit(); - for (auto & idx : measure_item) { - delete idx; - } measure_item.clear(); ret = TRUE; @@ -699,14 +683,7 @@ void MeasureTool::toPhantom() } SPDocument *doc = _desktop->getDocument(); - for (auto & measure_phantom_item : measure_phantom_items) { - delete measure_phantom_item; - } measure_phantom_items.clear(); - - for (auto & measure_tmp_item : measure_tmp_items) { - delete measure_tmp_item; - } measure_tmp_items.clear(); showCanvasItems(false, false, true); @@ -974,9 +951,6 @@ void MeasureTool::reset() this->knot_start->hide(); this->knot_end->hide(); - for (auto & measure_tmp_item : measure_tmp_items) { - delete measure_tmp_item; - } measure_tmp_items.clear(); } @@ -1000,9 +974,9 @@ void MeasureTool::setMeasureCanvasText(bool is_angle, double precision, double a if (to_phantom){ canvas_tooltip->set_background(0x4444447f); - measure_phantom_items.push_back(canvas_tooltip); + measure_phantom_items.emplace_back(canvas_tooltip); } else { - measure_tmp_items.push_back(canvas_tooltip); + measure_tmp_items.emplace_back(canvas_tooltip); } if (to_item) { @@ -1021,7 +995,7 @@ void MeasureTool::setMeasureCanvasItem(Geom::Point position, bool to_item, bool auto canvas_item = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_TYPE_POINT, position); canvas_item->set_stroke(color); - canvas_item->set_z_position(0); + canvas_item->lower_to_bottom(); canvas_item->set_pickable(false); canvas_item->show(); @@ -1046,7 +1020,7 @@ void MeasureTool::setMeasureCanvasControlLine(Geom::Point start, Geom::Point end auto control_line = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), start, end); control_line->set_stroke(color); - control_line->set_z_position(0); + control_line->lower_to_bottom(); control_line->show(); if (to_phantom) { @@ -1070,16 +1044,13 @@ void MeasureTool::showItemInfoText(Geom::Point pos, Glib::ustring const &measure canvas_tooltip->set_anchor(Geom::Point(0, 0)); canvas_tooltip->set_fixed_line(true); canvas_tooltip->show(); - measure_item.push_back(canvas_tooltip); + measure_item.emplace_back(canvas_tooltip); } void MeasureTool::showInfoBox(Geom::Point cursor, bool into_groups) { using Inkscape::Util::Quantity; - for (auto & idx : measure_item) { - delete(idx); - } measure_item.clear(); SPItem *newover = _desktop->getItemAtPoint(cursor, into_groups); @@ -1188,9 +1159,6 @@ void MeasureTool::showCanvasItems(bool to_guides, bool to_item, bool to_phantom, writeMeasurePoint(end_p, false); //clear previous canvas items, we'll draw new ones - for (auto & measure_tmp_item : measure_tmp_items) { - delete measure_tmp_item; - } measure_tmp_items.clear(); //TODO:Calculate the measure area for current length and origin @@ -1367,7 +1335,7 @@ void MeasureTool::showCanvasItems(bool to_guides, bool to_item, bool to_phantom, * Geom::Affine(Geom::Translate(start_p))); } setMeasureCanvasControlLine(start_p, anchorEnd, to_item, to_phantom, Inkscape::CANVAS_ITEM_SECONDARY, measure_repr); - createAngleDisplayCurve(start_p, end_p, angleDisplayPt, angle, to_phantom, measure_phantom_items, measure_tmp_items, measure_repr); + createAngleDisplayCurve(start_p, end_p, angleDisplayPt, angle, to_phantom, measure_repr); } if (intersections.size() > 2) { diff --git a/src/ui/tools/measure-tool.h b/src/ui/tools/measure-tool.h index bdaf53a6e696d6785481ee98379a5731477d791d..f8f19201302ae8814dff0f6d2e439ce99692bf1b 100644 --- a/src/ui/tools/measure-tool.h +++ b/src/ui/tools/measure-tool.h @@ -25,6 +25,7 @@ #include "display/control/canvas-temporary-item.h" #include "display/control/canvas-item-enums.h" +#include "display/control/canvas-item-ptr.h" class SPKnot; @@ -78,8 +79,6 @@ public: void setMeasureItem(Geom::PathVector pathv, bool is_curve, bool markers, guint32 color, Inkscape::XML::Node *measure_repr); void createAngleDisplayCurve(Geom::Point const ¢er, Geom::Point const &end, Geom::Point const &anchor, double angle, bool to_phantom, - std::vector &measure_phantom_items, - std::vector &measure_tmp_items, Inkscape::XML::Node *measure_repr = nullptr); private: @@ -92,9 +91,9 @@ private: Geom::Point end_p; Geom::Point last_pos; - std::vector measure_tmp_items; - std::vector measure_phantom_items; - std::vector measure_item; + std::vector> measure_tmp_items; + std::vector> measure_phantom_items; + std::vector> measure_item; double item_width; double item_height; diff --git a/src/ui/tools/mesh-tool.cpp b/src/ui/tools/mesh-tool.cpp index 605f7368616357bc2e6d470013dbb977ee711d8e..e623d6b7c19c3ef79865b2635281b4a28b8827f7 100644 --- a/src/ui/tools/mesh-tool.cpp +++ b/src/ui/tools/mesh-tool.cpp @@ -210,15 +210,15 @@ void MeshTool::select_prev() * Returns vector of control curves mouse is over. Returns only first if 'first' is true. * event_p is in canvas (world) units. */ -std::vector MeshTool::over_curve(Geom::Point event_p, bool first) +std::vector MeshTool::over_curve(Geom::Point event_p, bool first) { - //Translate mouse point into proper coord system: needed later. + // Translate mouse point into proper coord system: needed later. mousepoint_doc = _desktop->w2d(event_p); - std::vector selected; + std::vector selected; - for (auto curve : _grdrag->item_curves) { - if (curve->contains(event_p, tolerance)) { - selected.push_back(&*curve); + for (auto &it : _grdrag->item_curves) { + if (it.curve->contains(event_p, tolerance)) { + selected.emplace_back(&it); if (first) { break; } @@ -227,7 +227,6 @@ std::vector MeshTool::over_curve(Geom::Point event_p, bool fi return selected; } - /** Split row/column near the mouse point. */ @@ -501,11 +500,9 @@ bool MeshTool::root_handler(GdkEvent* event) { if (!over_curve.empty()) { for (auto it : over_curve) { - SPItem *item = it->get_item(); - Inkscape::PaintTarget fill_or_stroke = - it->get_is_fill() ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE; - GrDragger* dragger0 = _grdrag->getDraggerFor(item, POINT_MG_CORNER, it->get_corner0(), fill_or_stroke); - GrDragger* dragger1 = _grdrag->getDraggerFor(item, POINT_MG_CORNER, it->get_corner1(), fill_or_stroke); + Inkscape::PaintTarget fill_or_stroke = it->is_fill ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE; + GrDragger *dragger0 = _grdrag->getDraggerFor(it->item, POINT_MG_CORNER, it->corner0, fill_or_stroke); + GrDragger *dragger1 = _grdrag->getDraggerFor(it->item, POINT_MG_CORNER, it->corner1, fill_or_stroke); bool add = (event->button.state & GDK_SHIFT_MASK); bool toggle = (event->button.state & GDK_CONTROL_MASK); if ( !add && !toggle ) { @@ -649,7 +646,7 @@ bool MeshTool::root_handler(GdkEvent* event) { if ( (event->button.state & GDK_CONTROL_MASK) && (event->button.state & GDK_MOD1_MASK ) ) { if (!over_curve.empty()) { - split_near_point(over_curve[0]->get_item(), this->mousepoint_doc, 0); + split_near_point(over_curve[0]->item, mousepoint_doc, 0); ret = TRUE; } } else { diff --git a/src/ui/tools/mesh-tool.h b/src/ui/tools/mesh-tool.h index de13eb1488e0ecc8491bc493f0e13c67b93266bc..8fcf1639877715e8ce467b614453a3593acead13 100644 --- a/src/ui/tools/mesh-tool.h +++ b/src/ui/tools/mesh-tool.h @@ -20,6 +20,7 @@ #include #include +#include "gradient-drag.h" #include "ui/tools/tool-base.h" #include "object/sp-mesh-array.h" @@ -27,8 +28,6 @@ #define SP_MESH_CONTEXT(obj) (dynamic_cast((Inkscape::UI::Tools::ToolBase*)obj)) #define SP_IS_MESH_CONTEXT(obj) (dynamic_cast((const Inkscape::UI::Tools::ToolBase*)obj) != NULL) -class GrDrag; - namespace Inkscape { class Selection; @@ -65,7 +64,7 @@ private: void select_prev(); void new_default(); void split_near_point(SPItem *item, Geom::Point mouse_p, guint32 /*etime*/); - std::vector over_curve(Geom::Point event_p, bool first = true); + std::vector over_curve(Geom::Point event_p, bool first = true); }; } diff --git a/src/ui/tools/node-tool.cpp b/src/ui/tools/node-tool.cpp index d24fbec4982336a78183d415761418e7b8c1d06c..fc1c09509d64378f68d2e155828a168d8b1c7cfa 100644 --- a/src/ui/tools/node-tool.cpp +++ b/src/ui/tools/node-tool.cpp @@ -229,13 +229,12 @@ NodeTool::~NodeTool() delete this->_multipath; delete this->_selected_nodes; - Inkscape::UI::PathSharedData &data = *this->_path_data; - delete data.node_data.node_group; - delete data.node_data.handle_group; - delete data.node_data.handle_line_group; - delete data.outline_group; - delete data.dragpoint_group; - delete _transform_handle_group; + _path_data->node_data.node_group->unlink(); + _path_data->node_data.handle_group->unlink(); + _path_data->node_data.handle_line_group->unlink(); + _path_data->outline_group->unlink(); + _path_data->dragpoint_group->unlink(); + _transform_handle_group->unlink(); } Inkscape::Rubberband *NodeTool::get_rubberband() const diff --git a/src/ui/tools/pages-tool.cpp b/src/ui/tools/pages-tool.cpp index 95705e8032e9e7b28733e832adfe5367e35aef5f..90b0d72642234f03d7dbdd2dc4500a78f62c4478 100644 --- a/src/ui/tools/pages-tool.cpp +++ b/src/ui/tools/pages-tool.cpp @@ -88,12 +88,12 @@ PagesTool::PagesTool(SPDesktop *desktop) } if (!visual_box) { - visual_box = new Inkscape::CanvasItemRect(desktop->getCanvasControls()); + visual_box = make_canvasitem(desktop->getCanvasControls()); visual_box->set_stroke(0x0000ff7f); visual_box->hide(); } if (!drag_group) { - drag_group = new Inkscape::CanvasItemGroup(desktop->getCanvasTemp()); + drag_group = make_canvasitem(desktop->getCanvasTemp()); drag_group->set_name("CanvasItemGroup:PagesDragShapes"); } @@ -120,10 +120,7 @@ PagesTool::~PagesTool() _desktop->getSelection()->restoreBackup(); - if (visual_box) { - delete visual_box; - visual_box = nullptr; - } + visual_box.reset(); for (auto knot : resize_knots) { delete knot; @@ -131,8 +128,7 @@ PagesTool::~PagesTool() resize_knots.clear(); if (drag_group) { - delete drag_group; - drag_group = nullptr; + drag_group.reset(); drag_shapes.clear(); // Already deleted by group } @@ -531,7 +527,7 @@ void PagesTool::addDragShape(SPItem *item, Geom::Affine tr) */ void PagesTool::addDragShape(Geom::PathVector &&pth, Geom::Affine tr) { - auto shape = new CanvasItemBpath(drag_group, pth * tr, false); + auto shape = new CanvasItemBpath(drag_group.get(), pth * tr, false); shape->set_stroke(0x00ff007f); shape->set_fill(0x00000000, SP_WIND_RULE_EVENODD); drag_shapes.push_back(shape); @@ -543,7 +539,7 @@ void PagesTool::addDragShape(Geom::PathVector &&pth, Geom::Affine tr) void PagesTool::clearDragShapes() { for (auto &shape : drag_shapes) { - delete shape; + shape->unlink(); } drag_shapes.clear(); } diff --git a/src/ui/tools/pages-tool.h b/src/ui/tools/pages-tool.h index 76a04d13f26708338be5e1f7ab5db002ae697920..30887b1e871ad73079ec067a0a08edb9ea069c44 100644 --- a/src/ui/tools/pages-tool.h +++ b/src/ui/tools/pages-tool.h @@ -15,6 +15,7 @@ #include "ui/tools/tool-base.h" #include "2geom/rect.h" +#include "display/control/canvas-item-ptr.h" #define SP_PAGES_CONTEXT(obj) (dynamic_cast((Inkscape::UI::Tools::ToolBase *)obj)) #define SP_IS_PAGES_CONTEXT(obj) \ @@ -83,8 +84,8 @@ private: SPPage *highlight_item = nullptr; SPPage *dragging_item = nullptr; std::optional on_screen_rect; ///< On-screen rectangle, in desktop coordinates. - Inkscape::CanvasItemRect *visual_box = nullptr; - Inkscape::CanvasItemGroup *drag_group = nullptr; + CanvasItemPtr visual_box; + CanvasItemPtr drag_group; std::vector drag_shapes; std::vector _bbox_points; diff --git a/src/ui/tools/pen-tool.cpp b/src/ui/tools/pen-tool.cpp index 1dbaafc59e173f242af2f350e9bfd7cb4c599498..2b90df8416164207ad0bee7703c283b5d3832b9e 100644 --- a/src/ui/tools/pen-tool.cpp +++ b/src/ui/tools/pen-tool.cpp @@ -93,13 +93,13 @@ PenTool::PenTool(SPDesktop *desktop, std::string prefs_path, const std::string & // Pen indicators (temporary handles shown when adding a new node). auto canvas = desktop->getCanvasControls(); for (int i = 0; i < 4; i++) { - ctrl[i] = new Inkscape::CanvasItemCtrl(canvas, ctrl_types[i]); + ctrl[i] = make_canvasitem(canvas, ctrl_types[i]); ctrl[i]->set_fill(0x0); ctrl[i]->hide(); } - cl0 = new Inkscape::CanvasItemCurve(canvas); - cl1 = new Inkscape::CanvasItemCurve(canvas); + cl0 = make_canvasitem(canvas); + cl1 = make_canvasitem(canvas); cl0->hide(); cl1->hide(); @@ -130,16 +130,10 @@ PenTool::~PenTool() { } for (auto &c : ctrl) { - delete c; - c = nullptr; - } - - if (this->cl0) { - delete cl0; - } - if (this->cl1) { - delete cl1; + c.reset(); } + cl0.reset(); + cl1.reset(); if (this->waiting_item && this->expecting_clicks_for_LPE > 0) { // we received too few clicks to sanely set the parameter path so we remove the LPE from the item @@ -165,7 +159,7 @@ void PenTool::setPolylineMode() { void PenTool::_cancel() { this->state = PenTool::STOP; this->_resetColors(); - for (auto c : ctrl) { + for (auto &c : ctrl) { c->hide(); } cl0->hide(); @@ -787,16 +781,13 @@ void PenTool::_redrawAll() { // green if (! this->green_bpaths.empty()) { // remove old piecewise green canvasitems - for (auto path : this->green_bpaths) { - delete path; - } this->green_bpaths.clear(); // one canvas bpath for all of green_curve auto canvas_shape = new Inkscape::CanvasItemBpath(_desktop->getCanvasSketch(), copy_pathvector_optional(green_curve), true); canvas_shape->set_stroke(green_color); canvas_shape->set_fill(0x0, SP_WIND_RULE_NONZERO); - this->green_bpaths.push_back(canvas_shape); + this->green_bpaths.emplace_back(canvas_shape); } if (this->green_anchor) { this->green_anchor->ctrl->set_position(this->green_anchor->dp); @@ -807,7 +798,7 @@ void PenTool::_redrawAll() { red_curve.curveto(p[1], p[2], p[3]); red_bpath->set_bpath(&red_curve, true); - for (auto c : ctrl) { + for (auto &c : ctrl) { c->hide(); } // handles @@ -1185,9 +1176,6 @@ void PenTool::_resetColors() { blue_bpath->set_bpath(nullptr); // Green - for (auto path : this->green_bpaths) { - delete path; - } this->green_bpaths.clear(); this->green_curve->reset(); this->green_anchor.reset(); @@ -1273,16 +1261,13 @@ void PenTool::_bsplineSpiroColor() //transparency recently modified if (!this->green_bpaths.empty()) { // remove old piecewise green canvasitems - for (auto path : this->green_bpaths) { - delete path; - } this->green_bpaths.clear(); // one canvas bpath for all of green_curve auto canvas_shape = new Inkscape::CanvasItemBpath(_desktop->getCanvasSketch(), copy_pathvector_optional(green_curve), true); canvas_shape->set_stroke(green_color); canvas_shape->set_fill(0x0, SP_WIND_RULE_NONZERO); - this->green_bpaths.push_back(canvas_shape); + green_bpaths.emplace_back(canvas_shape); } this->red_bpath->set_stroke(red_color); @@ -1513,16 +1498,13 @@ void PenTool::_bsplineSpiroMotion(guint const state){ } // remove old piecewise green canvasitems - for (auto path: this->green_bpaths) { - delete path; - } - this->green_bpaths.clear(); + green_bpaths.clear(); // one canvas bpath for all of green_curve auto canvas_shape = new Inkscape::CanvasItemBpath(_desktop->getCanvasSketch(), copy_pathvector_optional(green_curve), true); canvas_shape->set_stroke(green_color); canvas_shape->set_fill(0x0, SP_WIND_RULE_NONZERO); - this->green_bpaths.push_back(canvas_shape); + green_bpaths.emplace_back(canvas_shape); this->_bsplineSpiroBuild(); } @@ -1676,7 +1658,7 @@ void PenTool::_bsplineSpiroBuild() blue_curve.reset(); //We hide the holders that doesn't contribute anything - for (auto c : ctrl) { + for (auto &c : ctrl) { c->hide(); } if (spiro){ @@ -1748,7 +1730,7 @@ void PenTool::_setSubsequentPoint(Geom::Point const p, bool statusbar, guint sta void PenTool::_setCtrl(Geom::Point const q, guint const state) { // use 'q' as 'p' shadows member variable. - for (auto c : ctrl) { + for (auto &c : ctrl) { c->hide(); } @@ -1826,7 +1808,7 @@ void PenTool::_finishSegment(Geom::Point const q, guint const state) { // use 'q auto canvas_shape = new Inkscape::CanvasItemBpath(_desktop->getCanvasSketch(), curve.get_pathvector(), true); canvas_shape->set_stroke(green_color); canvas_shape->set_fill(0x0, SP_WIND_RULE_NONZERO); - this->green_bpaths.push_back(canvas_shape); + green_bpaths.emplace_back(canvas_shape); this->p[0] = this->p[3]; this->p[1] = this->p[4]; @@ -1877,14 +1859,12 @@ bool PenTool::_undoLastPoint(bool user_undo) { if (this->green_curve->get_segment_count() == 1) { this->npoints = 5; if (!this->green_bpaths.empty()) { - delete this->green_bpaths.back(); this->green_bpaths.pop_back(); } this->green_curve->reset(); } else { this->green_curve->backspace(); if (this->green_bpaths.size() > 1) { - delete this->green_bpaths.back(); this->green_bpaths.pop_back(); } else if (this->green_bpaths.size() == 1) { green_bpaths.back()->set_bpath(green_curve.get(), true); @@ -1902,7 +1882,7 @@ bool PenTool::_undoLastPoint(bool user_undo) { } } - for (auto c : ctrl) { + for (auto &c : ctrl) { c->hide(); } cl0->hide(); @@ -1943,7 +1923,7 @@ bool PenTool::_redoLastPoint() if (auto const *last_seg = green_curve->last_segment()) { Geom::Path freshly_added; freshly_added.append(*last_seg); - green_bpaths.push_back(new CanvasItemBpath(_desktop->getCanvasSketch(), freshly_added, true)); + green_bpaths.emplace_back(make_canvasitem(_desktop->getCanvasSketch(), freshly_added, true)); } green_bpaths.back()->set_stroke(green_color); green_bpaths.back()->set_fill(0x0, SP_WIND_RULE_NONZERO); @@ -1980,7 +1960,7 @@ void PenTool::_finish(gboolean const closed) { this->npoints = 0; this->state = PenTool::POINT; - for (auto c : ctrl) { + for (auto &c : ctrl) { c->hide(); } diff --git a/src/ui/tools/pen-tool.h b/src/ui/tools/pen-tool.h index db35b248d6457d5e21a7768e4901d3f84cbd08ae..a7053e8c4a939b4016fcbe390d6b2950b1ea3a70 100644 --- a/src/ui/tools/pen-tool.h +++ b/src/ui/tools/pen-tool.h @@ -10,6 +10,7 @@ #ifndef SEEN_PEN_CONTEXT_H #define SEEN_PEN_CONTEXT_H +#include #include #include "display/control/canvas-item-enums.h" @@ -70,13 +71,13 @@ public: Inkscape::LivePathEffect::Effect *waiting_LPE = nullptr; // if NULL, waiting_LPE_type in SPDrawContext is taken into account SPLPEItem *waiting_item = nullptr; - Inkscape::CanvasItemCtrl *ctrl[4]; // Origin, Start, Center, End point of path. - Inkscape::CanvasItemCtrlType ctrl_types[4] = { - Inkscape::CANVAS_ITEM_CTRL_TYPE_NODE_SMOOTH, Inkscape::CANVAS_ITEM_CTRL_TYPE_ROTATE, - Inkscape::CANVAS_ITEM_CTRL_TYPE_ROTATE, Inkscape::CANVAS_ITEM_CTRL_TYPE_NODE_SMOOTH}; + CanvasItemPtr ctrl[4]; // Origin, Start, Center, End point of path. + static constexpr std::array ctrl_types = { + CANVAS_ITEM_CTRL_TYPE_NODE_SMOOTH, CANVAS_ITEM_CTRL_TYPE_ROTATE, + CANVAS_ITEM_CTRL_TYPE_ROTATE, CANVAS_ITEM_CTRL_TYPE_NODE_SMOOTH}; - Inkscape::CanvasItemCurve *cl0 = nullptr; - Inkscape::CanvasItemCurve *cl1 = nullptr; + CanvasItemPtr cl0; + CanvasItemPtr cl1; bool events_disabled = false; diff --git a/src/ui/tools/pencil-tool.cpp b/src/ui/tools/pencil-tool.cpp index 993421eb753ab63e8050f4e76f6fb96c5e8f9ad2..a61de9209f4def75052cfff4e0aec637b305db73 100644 --- a/src/ui/tools/pencil-tool.cpp +++ b/src/ui/tools/pencil-tool.cpp @@ -504,9 +504,6 @@ void PencilTool::_cancel() { this->red_curve.reset(); this->red_bpath->set_bpath(&red_curve); - for (auto path : this->green_bpaths) { - delete path; - } this->green_bpaths.clear(); this->green_curve->reset(); this->green_anchor.reset(); @@ -1163,7 +1160,7 @@ void PencilTool::_fitAndSplit() { cshape->set_stroke(green_color); cshape->set_fill(0x0, SP_WIND_RULE_NONZERO); - this->green_bpaths.push_back(cshape); + this->green_bpaths.emplace_back(cshape); this->red_curve_is_valid = false; } diff --git a/src/ui/tools/spray-tool.cpp b/src/ui/tools/spray-tool.cpp index 707a9010dbdd8bab297c01955e221d846ef0c198..3396d36a65fff55cdca16312f5389938398c5df0 100644 --- a/src/ui/tools/spray-tool.cpp +++ b/src/ui/tools/spray-tool.cpp @@ -146,7 +146,6 @@ SprayTool::SprayTool(SPDesktop *desktop) , is_drawing(false) , is_dilating(false) , has_dilated(false) - , dilate_area(nullptr) , no_overlap(false) , picker(false) , pick_center(true) @@ -167,7 +166,7 @@ SprayTool::SprayTool(SPDesktop *desktop) , gamma_picked(0) , rand_picked(0) { - dilate_area = new Inkscape::CanvasItemBpath(desktop->getCanvasControls()); + dilate_area = make_canvasitem(desktop->getCanvasControls()); dilate_area->set_stroke(0xff9900ff); dilate_area->set_fill(0x0, SP_WIND_RULE_EVENODD); dilate_area->hide(); @@ -216,11 +215,6 @@ SprayTool::~SprayTool() { _desktop->getSelection()->restoreBackup(); this->enableGrDrag(false); this->style_set_connection.disconnect(); - - if (this->dilate_area) { - delete this->dilate_area; - this->dilate_area = nullptr; - } } void SprayTool::update_cursor(bool /*with_shift*/) { diff --git a/src/ui/tools/spray-tool.h b/src/ui/tools/spray-tool.h index 8216e2da13f6d668df0071e4c815e12ac7843b49..f8bda365a15f37ace3e1ee5f41bb1bb832546609 100644 --- a/src/ui/tools/spray-tool.h +++ b/src/ui/tools/spray-tool.h @@ -24,6 +24,7 @@ #include <2geom/point.h> #include "ui/tools/tool-base.h" #include "object/object-set.h" +#include "display/control/canvas-item-ptr.h" #define SP_SPRAY_CONTEXT(obj) (dynamic_cast((Inkscape::UI::Tools::ToolBase*)obj)) #define SP_IS_SPRAY_CONTEXT(obj) (dynamic_cast((const Inkscape::UI::Tools::ToolBase*)obj) != NULL) @@ -92,7 +93,7 @@ public: bool is_dilating; bool has_dilated; Geom::Point last_push; - Inkscape::CanvasItemBpath *dilate_area; + CanvasItemPtr dilate_area; bool no_overlap; bool picker; bool pick_center; diff --git a/src/ui/tools/text-tool.cpp b/src/ui/tools/text-tool.cpp index 0330a2a1657783dbaf1dc8f9532bbf374e01367b..fbf08d3add2a82162d1d6cd0cebe2bdd841440ae 100644 --- a/src/ui/tools/text-tool.cpp +++ b/src/ui/tools/text-tool.cpp @@ -92,24 +92,24 @@ TextTool::TextTool(SPDesktop *desktop) timeout /= 2; } - cursor = new Inkscape::CanvasItemCurve(desktop->getCanvasControls()); + cursor = make_canvasitem(desktop->getCanvasControls()); cursor->set_stroke(0x000000ff); cursor->hide(); // The rectangle box tightly wrapping text object when selected or under cursor. - indicator = new Inkscape::CanvasItemRect(desktop->getCanvasControls()); + indicator = make_canvasitem(desktop->getCanvasControls()); indicator->set_stroke(0x0000ff7f); indicator->set_shadow(0xffffff7f, 1); indicator->hide(); // The shape that the text is flowing into - frame = new Inkscape::CanvasItemBpath(desktop->getCanvasControls()); + frame = make_canvasitem(desktop->getCanvasControls()); frame->set_fill(0x00 /* zero alpha */, SP_WIND_RULE_NONZERO); frame->set_stroke(0x0000ff7f); frame->hide(); // A second frame for showing the padding of the above frame - padding_frame = new Inkscape::CanvasItemBpath(desktop->getCanvasControls()); + padding_frame = make_canvasitem(desktop->getCanvasControls()); padding_frame->set_fill(0x00 /* zero alpha */, SP_WIND_RULE_NONZERO); padding_frame->set_stroke(0xccccccdf); padding_frame->hide(); @@ -195,30 +195,10 @@ TextTool::~TextTool() this->timeout = 0; } - if (cursor) { - delete cursor; - cursor = nullptr; - } - - if (this->indicator) { - delete indicator; - this->indicator = nullptr; - } - - if (this->frame) { - delete frame; - this->frame = nullptr; - } - - if (this->padding_frame) { - delete padding_frame; - this->padding_frame = nullptr; - } - - for (auto & text_selection_quad : text_selection_quads) { - text_selection_quad->hide(); - delete text_selection_quad; - } + cursor.reset(); + indicator.reset(); + frame.reset(); + padding_frame.reset(); text_selection_quads.clear(); delete this->shape_editor; @@ -1801,10 +1781,6 @@ static void sp_text_context_update_text_selection(TextTool *tc) // the selection update (can't do both atomically, alas) if (!tc->getDesktop()) return; - for (auto & text_selection_quad : tc->text_selection_quads) { - text_selection_quad->hide(); - delete text_selection_quad; - } tc->text_selection_quads.clear(); std::vector quads; @@ -1814,10 +1790,10 @@ static void sp_text_context_update_text_selection(TextTool *tc) auto quad = new CanvasItemQuad(tc->getDesktop()->getCanvasControls(), quads[i], quads[i+1], quads[i+2], quads[i+3]); quad->set_fill(0x00777777); // Semi-transparent blue as Cairo cannot do inversion. quad->show(); - tc->text_selection_quads.push_back(quad); + tc->text_selection_quads.emplace_back(quad); } - if (tc->shape_editor != nullptr) { + if (tc->shape_editor) { if (tc->shape_editor->knotholder) { tc->shape_editor->knotholder->update_knots(); } diff --git a/src/ui/tools/text-tool.h b/src/ui/tools/text-tool.h index 12a4ceed4688254a0805f0d8f2722654ccc1a791..c87431e68b101eadb8c5222e83938dc2c34d86a1 100644 --- a/src/ui/tools/text-tool.h +++ b/src/ui/tools/text-tool.h @@ -20,6 +20,7 @@ #include "ui/tools/tool-base.h" #include <2geom/point.h> #include "libnrtype/Layout-TNG.h" +#include "display/control/canvas-item-ptr.h" #define SP_TEXT_CONTEXT(obj) (dynamic_cast((Inkscape::UI::Tools::ToolBase*)obj)) #define SP_IS_TEXT_CONTEXT(obj) (dynamic_cast((const Inkscape::UI::Tools::ToolBase*)obj) != NULL) @@ -62,11 +63,11 @@ public: guint unipos = 0; // ---- On canvas editing --- - Inkscape::CanvasItemCurve *cursor = nullptr; - Inkscape::CanvasItemRect *indicator = nullptr; - Inkscape::CanvasItemBpath *frame = nullptr; // Highlighting flowtext shapes or textpath path - Inkscape::CanvasItemBpath *padding_frame = nullptr; // Highlighting flowtext padding - std::vector text_selection_quads; + CanvasItemPtr cursor; + CanvasItemPtr indicator; + CanvasItemPtr frame; // Highlighting flowtext shapes or textpath path + CanvasItemPtr padding_frame; // Highlighting flowtext padding + std::vector> text_selection_quads; gint timeout = 0; bool show = false; diff --git a/src/ui/tools/tool-base.cpp b/src/ui/tools/tool-base.cpp index 1b727d922bf4f1b7c6ef39a80897f9dca3c897ce..42da4d8dde4da348b97527d513d81915285c5216 100644 --- a/src/ui/tools/tool-base.cpp +++ b/src/ui/tools/tool-base.cpp @@ -1085,7 +1085,7 @@ bool ToolBase::hasGradientDrag() const */ void ToolBase::grabCanvasEvents(Gdk::EventMask mask) { - _desktop->getCanvasCatchall()->grab(mask, nullptr); // Cursor is null. + _desktop->getCanvasCatchall()->grab(mask); // Cursor is null. } /** diff --git a/src/ui/tools/tweak-tool.cpp b/src/ui/tools/tweak-tool.cpp index bf0ca996e4b639a8d5b376cc0e25aaa91c1eb167..808a4b47199a3fed5cab7343f5f7cc9c5e0ea486 100644 --- a/src/ui/tools/tweak-tool.cpp +++ b/src/ui/tools/tweak-tool.cpp @@ -85,13 +85,12 @@ TweakTool::TweakTool(SPDesktop *desktop) , is_drawing(false) , is_dilating(false) , has_dilated(false) - , dilate_area(nullptr) , do_h(true) , do_s(true) , do_l(true) , do_o(false) { - dilate_area = new Inkscape::CanvasItemBpath(desktop->getCanvasSketch()); + dilate_area = make_canvasitem(desktop->getCanvasSketch()); dilate_area->set_stroke(0xff9900ff); dilate_area->set_fill(0x0, SP_WIND_RULE_EVENODD); dilate_area->hide(); @@ -108,7 +107,7 @@ TweakTool::TweakTool(SPDesktop *desktop) sp_event_context_read(this, "dos"); sp_event_context_read(this, "doo"); - this->style_set_connection = desktop->connectSetStyle( // catch style-setting signal in this tool + style_set_connection = desktop->connectSetStyle( // catch style-setting signal in this tool //sigc::bind(sigc::ptr_fun(&sp_tweak_context_style_set), this) sigc::mem_fun(*this, &TweakTool::set_style) ); @@ -122,15 +121,9 @@ TweakTool::TweakTool(SPDesktop *desktop) } } -TweakTool::~TweakTool() { - this->enableGrDrag(false); - - this->style_set_connection.disconnect(); - - if (this->dilate_area) { - delete this->dilate_area; - this->dilate_area = nullptr; - } +TweakTool::~TweakTool() +{ + enableGrDrag(false); } static bool is_transform_mode (gint mode) diff --git a/src/ui/tools/tweak-tool.h b/src/ui/tools/tweak-tool.h index d1856667a7389c070f1141038e388ffea30851a3..77bfb1ffeaa889f721c190ec48ba6657da7fa17a 100644 --- a/src/ui/tools/tweak-tool.h +++ b/src/ui/tools/tweak-tool.h @@ -13,8 +13,10 @@ * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ -#include "ui/tools/tool-base.h" #include <2geom/point.h> +#include "ui/tools/tool-base.h" +#include "display/control/canvas-item-ptr.h" +#include "helper/auto-connection.h" #define SAMPLING_SIZE 8 /* fixme: ?? */ @@ -45,13 +47,14 @@ enum { TWEAK_MODE_BLUR }; -class TweakTool : public ToolBase { +class TweakTool : public ToolBase +{ public: TweakTool(SPDesktop *desktop); ~TweakTool() override; /* extended input data */ - gdouble pressure; + double pressure; /* attributes */ bool dragging; /* mouse state: mouse is dragging */ @@ -62,21 +65,21 @@ public: double force; double fidelity; - gint mode; + int mode; bool is_drawing; bool is_dilating; bool has_dilated; Geom::Point last_push; - Inkscape::CanvasItemBpath *dilate_area; + CanvasItemPtr dilate_area; bool do_h; bool do_s; bool do_l; bool do_o; - sigc::connection style_set_connection; + auto_connection style_set_connection; void set(const Inkscape::Preferences::Entry &val) override; bool root_handler(GdkEvent *event) override; diff --git a/src/ui/widget/canvas.cpp b/src/ui/widget/canvas.cpp index f228b4c0754713eeeb11f12a3c42c42861c8c1a0..b152bda3f166caff4fb59bac7b08bb4f98f14ed0 100644 --- a/src/ui/widget/canvas.cpp +++ b/src/ui/widget/canvas.cpp @@ -28,10 +28,8 @@ #include "helper/geom.h" #include "display/drawing.h" -#include "display/cairo-utils.h" #include "display/control/canvas-item-drawing.h" #include "display/control/canvas-item-group.h" -#include "display/control/canvas-item-rect.h" #include "display/control/snap-indicator.h" #include "ui/tools/tool-base.h" // Default cursor @@ -129,6 +127,9 @@ public: void activate(); void deactivate(); + // CanvasItem tree + std::optional canvasitem_ctx; + // Preferences Prefs prefs; @@ -195,7 +196,6 @@ public: bool outlines_enabled = false; int scale_factor = 1; // The device scale the stores are drawn at. - Geom::Affine geom_affine; // The affine the geometry was last imbued with. PageInfo pi; bool background_in_stores = false; @@ -243,7 +243,7 @@ Canvas::Canvas() d->updater->reset(); // Preferences - d->prefs.grabsize.action = [=] { _canvas_item_root->update_canvas_item_ctrl_sizes(d->prefs.grabsize); }; + d->prefs.grabsize.action = [=] { d->canvasitem_ctx->root()->update_canvas_item_ctrl_sizes(d->prefs.grabsize); }; d->prefs.debug_show_unclean.action = [=] { queue_draw(); }; d->prefs.debug_show_clean.action = [=] { queue_draw(); }; d->prefs.debug_disable_redraw.action = [=] { d->add_idle(); }; @@ -277,10 +277,8 @@ Canvas::Canvas() }; d->prefs.debug_idle_starvation.action = [=] { d->sample_begin = d->wait_begin = d->wait_accumulated = 0; }; - // Cavas item root - _canvas_item_root = new Inkscape::CanvasItemGroup(nullptr); - _canvas_item_root->set_name("CanvasItemGroup:Root"); - _canvas_item_root->set_canvas(this); + // Canvas item tree + d->canvasitem_ctx.emplace(this); // Split view. _split_direction = Inkscape::SplitDirection::EAST; @@ -365,7 +363,7 @@ Canvas::~Canvas() d->eventprocessor->canvasprivate = nullptr; // Remove entire CanvasItem tree. - delete _canvas_item_root; + d->canvasitem_ctx.reset(); } void Canvas::set_drawing(Drawing *drawing) @@ -380,6 +378,11 @@ void Canvas::set_drawing(Drawing *drawing) if (!d->active && get_realized() && drawing) d->activate(); } +CanvasItemGroup *Canvas::get_canvas_item_root() const +{ + return d->canvasitem_ctx->root(); +} + void Canvas::on_realize() { parent_type::on_realize(); @@ -922,12 +925,6 @@ bool CanvasPrivate::process_bucketed_event(const GdkEvent *event) // canvas_catchall->connect_event(sigc::bind(sigc::ptr_fun(sp_desktop_root_handler), this)); bool CanvasPrivate::pick_current_item(const GdkEvent *event) { - // Ensure requested geometry updates are performed first. - if (q->_need_update) { - q->_canvas_item_root->update(geom_affine); - q->_need_update = false; - } - int button_down = 0; if (!q->_all_enter_events) { // Only set true in connector-tool.cpp. @@ -997,7 +994,7 @@ bool CanvasPrivate::pick_current_item(const GdkEvent *event) // Find new item q->_current_canvas_item_new = nullptr; - if (q->_pick_event.type != GDK_LEAVE_NOTIFY && q->_canvas_item_root->is_visible()) { + if (q->_pick_event.type != GDK_LEAVE_NOTIFY && canvasitem_ctx->root()->is_visible()) { // Leave notify means there is no current item. // Find closest item. double x = 0.0; @@ -1028,11 +1025,11 @@ bool CanvasPrivate::pick_current_item(const GdkEvent *event) // Convert to world coordinates. auto p = Geom::Point(x, y) + q->_pos; if (stores.mode() == Stores::Mode::Decoupled) { - p *= q->_affine.inverse() * geom_affine; + p *= q->_affine.inverse() * canvasitem_ctx->affine(); } q->_drawing->getCanvasItemDrawing()->set_pick_outline(outline); - q->_current_canvas_item_new = q->_canvas_item_root->pick_item(p); + q->_current_canvas_item_new = canvasitem_ctx->root()->pick_item(p); // if (q->_current_canvas_item_new) { // std::cout << " PICKING: FOUND ITEM: " << q->_current_canvas_item_new->get_name() << std::endl; // } else { @@ -1133,7 +1130,7 @@ bool CanvasPrivate::emit_event(const GdkEvent *event) auto conv = [&, this] (double &x, double &y) { auto p = Geom::Point(x, y) + q->_pos; if (stores.mode() == Stores::Mode::Decoupled) { - p *= q->_affine.inverse() * geom_affine; + p *= q->_affine.inverse() * canvasitem_ctx->affine(); } x = p.x(); y = p.y(); @@ -1244,7 +1241,7 @@ void Canvas::set_affine(Geom::Affine const &affine) const Geom::Affine &Canvas::get_geom_affine() const { - return d->geom_affine; + return d->canvasitem_ctx->affine(); } void CanvasPrivate::queue_draw_area(const Geom::IntRect &rect) @@ -1545,7 +1542,7 @@ void Canvas::on_size_allocate(Gtk::Allocation &allocation) assert(allocation == get_allocation()); // Necessary as GTK seems to somehow invalidate the current pipeline state upon resize. - if (d->active && get_opengl_enabled()) { + if (d->active) { d->graphics->invalidated_glstate(); } @@ -1585,7 +1582,7 @@ void Canvas::paint_widget(const Cairo::RefPtr &cr) return; } - // canvas_item_print_tree(_canvas_item_root); + // _canvas_item_root->canvas_item_print_tree(); // Although hipri_idle is scheduled at a priority higher than draw, and should therefore always be called first if // asked, there are times when GTK simply decides to call on_draw anyway. Here we ensure that that call has taken @@ -1883,7 +1880,7 @@ bool CanvasPrivate::on_idle() framecheck_whole_function(this) assert(active); // Guaranteed since already checked by both callers. - assert(q->_canvas_item_root); + assert(canvasitem_ctx->root()); // Quit idle process if not supposed to be drawing. if (q->_drawing_disabled) { @@ -1901,7 +1898,7 @@ bool CanvasPrivate::on_idle() scale_factor = q->get_scale_factor(); pi.pages.clear(); - q->_canvas_item_root->visit_page_rects([this] (auto &rect) { + canvasitem_ctx->root()->visit_page_rects([this] (auto &rect) { pi.pages.emplace_back(rect); }); @@ -1932,10 +1929,11 @@ bool CanvasPrivate::on_idle() // Ensure the geometry is up-to-date and in the right place. auto const &affine = stores.store().affine; - if (q->_need_update || geom_affine != affine) { - q->_canvas_item_root->update(affine); - geom_affine = affine; + bool const affine_changed = canvasitem_ctx->affine() != stores.store().affine; + if (q->_need_update || affine_changed) { q->_need_update = false; + canvasitem_ctx->setAffine(affine); + canvasitem_ctx->root()->update(affine_changed); } // If asked to, don't paint anything and instead halt the idle process. @@ -2090,7 +2088,7 @@ bool CanvasPrivate::on_idle() // Another high priority to redraw is the grabbed canvas item, if the user has requested block updates. if (q->_grabbed_canvas_item && prefs.block_updates) { - if (auto grabbed = regularised(q->_grabbed_canvas_item->get_bounds().roundOutwards() & *vis_store)) { + if (auto grabbed = regularised(roundedOutwards(q->_grabbed_canvas_item->get_bounds()) & *vis_store)) { process_redraw(*grabbed, updater->clean_region, false, false); // non-interruptible, non-preemptible // Reset timeout to leave the normal amount of time for clearing up artifacts. start_time = g_get_monotonic_time(); @@ -2139,7 +2137,7 @@ void CanvasPrivate::paint_rect(const Geom::IntRect &rect) }; Fragment fragment; - fragment.affine = geom_affine; + fragment.affine = stores.store().affine; fragment.rect = rect; Cairo::RefPtr surface, outline_surface; @@ -2159,7 +2157,7 @@ void CanvasPrivate::paint_single_buffer(const Cairo::RefPtr // Clear background. cr->save(); if (need_background) { - Graphics::paint_background(Fragment{ geom_affine, rect }, pi, page, desk, cr); + Graphics::paint_background(Fragment{ stores.store().affine, rect }, pi, page, desk, cr); } else { cr->set_operator(Cairo::OPERATOR_CLEAR); cr->paint(); @@ -2167,10 +2165,8 @@ void CanvasPrivate::paint_single_buffer(const Cairo::RefPtr cr->restore(); // Render drawing on top of background. - if (q->_canvas_item_root->is_visible()) { - auto buf = Inkscape::CanvasItemBuffer{ rect, scale_factor, cr, outline_pass }; - q->_canvas_item_root->render(&buf); - } + auto buf = Inkscape::CanvasItemBuffer{ rect, scale_factor, cr, outline_pass }; + canvasitem_ctx->root()->render(buf); // Paint over newly drawn content with a translucent random colour. if (prefs.debug_show_redraw) { diff --git a/src/ui/widget/canvas.h b/src/ui/widget/canvas.h index ec7da3ca93b26881dbd997b86ce390d022748b53..24ef9a98dc2e87ced3f17ed47828ed8693b62e81 100644 --- a/src/ui/widget/canvas.h +++ b/src/ui/widget/canvas.h @@ -57,7 +57,7 @@ public: void set_drawing(Inkscape::Drawing *drawing); // Canvas item root - CanvasItemGroup *get_canvas_item_root() const { return _canvas_item_root; } + CanvasItemGroup *get_canvas_item_root() const; // Geometry void set_pos (const Geom::IntPoint &pos); @@ -164,9 +164,6 @@ private: // Drawing Inkscape::Drawing *_drawing = nullptr; - // Canvas item root - CanvasItemGroup *_canvas_item_root = nullptr; - // Geometry Geom::IntPoint _pos = {0, 0}; ///< Coordinates of top-left pixel of canvas view within canvas. Geom::Affine _affine; ///< The affine that we have been requested to draw at. diff --git a/src/vanishing-point.cpp b/src/vanishing-point.cpp index e02528b52a65b2aec013b6b89fda75aeec8e31ef..17534d2b05aba8a51ef1082fab49a45cf4bd568f 100644 --- a/src/vanishing-point.cpp +++ b/src/vanishing-point.cpp @@ -504,9 +504,6 @@ VPDrag::~VPDrag() } this->draggers.clear(); - for (auto item_curve : item_curves) { - delete item_curve; - } item_curves.clear(); } @@ -572,9 +569,6 @@ of a dragger, so that lines are always in sync with the actual perspective void VPDrag::updateLines() { // Delete old lines - for (auto curve : item_curves) { - delete curve; - } item_curves.clear(); // do nothing if perspective lines are currently disabled @@ -746,7 +740,7 @@ void VPDrag::addCurve(Geom::Point const &p1, Geom::Point const &p2, Inkscape::Ca auto item_curve = new Inkscape::CanvasItemCurve(SP_ACTIVE_DESKTOP->getCanvasControls(), p1, p2); item_curve->set_name("3DBoxCurve"); item_curve->set_stroke(color); - item_curves.push_back(item_curve); + item_curves.emplace_back(item_curve); } } // namespace Box3D diff --git a/src/vanishing-point.h b/src/vanishing-point.h index c6c280da34cd9de5d17f2fdb9d950738e7cb5165..1b536ced2aacfd9fad501422029b979a97e77cee 100644 --- a/src/vanishing-point.h +++ b/src/vanishing-point.h @@ -20,6 +20,7 @@ #include "selection.h" #include "display/control/canvas-item-enums.h" +#include "display/control/canvas-item-ptr.h" #include "object/persp3d.h" @@ -168,7 +169,7 @@ public: SPDocument *document; std::vector draggers; - std::vector item_curves; + std::vector> item_curves; void printDraggers(); // convenience for debugging /* diff --git a/src/widgets/desktop-widget.cpp b/src/widgets/desktop-widget.cpp index 52f21aaee1410931f5998cb6303fc892fce27bd3..412edb0c01342a91900025474b79fd68e5da7bac 100644 --- a/src/widgets/desktop-widget.cpp +++ b/src/widgets/desktop-widget.cpp @@ -1800,8 +1800,7 @@ SPDesktopWidget::on_ruler_box_button_release_event(GdkEventButton *event, Gtk::W ruler_snap_new_guide(desktop, event_dt, normal); } - delete _active_guide; - _active_guide = nullptr; + _active_guide.reset(); if ((horiz ? wy : wx) >= 0) { Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); Inkscape::XML::Node *repr = xml_doc->createElement("sodipodi:guide"); @@ -1908,7 +1907,7 @@ SPDesktopWidget::on_ruler_box_button_press_event(GdkEventButton *event, Gtk::Wid } } - _active_guide = new Inkscape::CanvasItemGuideLine(desktop->getCanvasGuides(), Glib::ustring(), event_dt, _normal); + _active_guide = make_canvasitem(desktop->getCanvasGuides(), Glib::ustring(), event_dt, _normal); _active_guide->set_stroke(desktop->namedview->guidehicolor); // Ruler grabs all events until button release. diff --git a/src/widgets/desktop-widget.h b/src/widgets/desktop-widget.h index f815cf7ba0e2464695dd9cdcf430bbb4848000dd..4a7739e8eaae0ca118e46b45d0ac3c1004fa09a0 100644 --- a/src/widgets/desktop-widget.h +++ b/src/widgets/desktop-widget.h @@ -19,16 +19,15 @@ # include "config.h" // only include where actually required! #endif +#include +#include <2geom/point.h> +#include #include #include "message.h" #include "preferences.h" #include "ui/view/view-widget.h" -#include "preferences.h" - -#include -#include -#include <2geom/point.h> +#include "display/control/canvas-item-ptr.h" // forward declaration typedef struct _EgeColorProfTracker EgeColorProfTracker; @@ -104,7 +103,7 @@ private: bool update = false; - Inkscape::CanvasItemGuideLine *_active_guide = nullptr; ///< The guide being handled during a ruler event + CanvasItemPtr _active_guide; ///< The guide being handled during a ruler event Geom::Point _normal; ///< Normal to the guide currently being handled during ruler event int _xp = 0; ///< x coordinate for start of drag int _yp = 0; ///< y coordinate for start of drag