1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /** 3 * A CanvasItem that contains other CanvasItem's. 4 */ 5 6 /* 7 * Author: 8 * Tavmjong Bah 9 * 10 * Copyright (C) 2020 Tavmjong Bah 11 * 12 * Rewrite of SPCanvasGroup 13 * 14 * Released under GNU GPL v2+, read the file 'COPYING' for more information. 15 */ 16 17 #include "canvas-item-group.h" 18 #include "canvas-item-ctrl.h" // Update sizes 19 20 namespace Inkscape { 21 CanvasItemGroup(CanvasItemGroup * group)22CanvasItemGroup::CanvasItemGroup(CanvasItemGroup *group) 23 : CanvasItem(group) 24 { 25 _name = "CanvasItemGroup"; 26 _pickable = true; // For now all groups are pickable... look into turning this off for some groups (e.g. temp). 27 } 28 ~CanvasItemGroup()29CanvasItemGroup::~CanvasItemGroup() 30 { 31 while (!items.empty()) { 32 CanvasItem & item = items.front(); 33 remove(&item); 34 } 35 36 if (_parent) { 37 _parent->remove(this, false); // remove() should not delete this or we'll double delete! 38 } 39 } 40 add(CanvasItem * item)41void CanvasItemGroup::add(CanvasItem *item) 42 { 43 #ifdef CANVAS_ITEM_DEBUG 44 std::cout << "CanvasItemGroup::add: " << item->get_name() << " to " << _name << " " << items.size() << std::endl; 45 #endif 46 items.push_back(*item); 47 // canvas request update 48 } 49 remove(CanvasItem * item,bool Delete)50void CanvasItemGroup::remove(CanvasItem *item, bool Delete) 51 { 52 #ifdef CANVAS_ITEM_DEBUG 53 std::cout << "CanvasItemGroup::remove: " << item->get_name() << " from " << _name << " " << items.size() << std::endl; 54 #endif 55 auto position = items.iterator_to(*item); 56 if (position != items.end()) { 57 position->set_parent(nullptr); 58 items.erase(position); 59 if (Delete) { 60 delete (&*position); // An item directly deleted should not be deleted here. 61 } 62 } 63 } 64 update(Geom::Affine const & affine)65void CanvasItemGroup::update(Geom::Affine const &affine) 66 { 67 if (_affine == affine && !_need_update) { 68 // Nothing to do. 69 return; 70 } 71 72 _affine = affine; 73 _need_update = false; 74 75 _bounds = Geom::Rect(); // Zero 76 77 // Update all children and calculate new bounds. 78 for (auto & item : items) { 79 item.update(_affine); 80 _bounds.unionWith(item.get_bounds()); 81 } 82 } 83 render(Inkscape::CanvasItemBuffer * buf)84void CanvasItemGroup::render(Inkscape::CanvasItemBuffer *buf) 85 { 86 if (_visible) { 87 if (_bounds.interiorIntersects(buf->rect)) { 88 for (auto & item : items) { 89 item.render(buf); 90 } 91 } 92 } 93 } 94 95 // Return last visible and pickable item that contains point. 96 // SPCanvasGroup returned distance but it was not used. pick_item(Geom::Point & p)97CanvasItem* CanvasItemGroup::pick_item(Geom::Point& p) 98 { 99 #ifdef CANVAS_ITEM_DEBUG 100 std::cout << "CanvasItemGroup::pick_item:" << std::endl; 101 std::cout << " PICKING: In group: " << _name << " bounds: " << _bounds << std::endl; 102 #endif 103 for (auto item = items.rbegin(); item != items.rend(); ++item) { // C++20 will allow us to loop in reverse. 104 #ifdef CANVAS_ITEM_DEBUG 105 std::cout << " PICKING: Checking: " << item->get_name() << " bounds: " << item->get_bounds() << std::endl; 106 #endif 107 CanvasItem* picked_item = nullptr; 108 if (item->is_visible() && 109 item->is_pickable() && 110 item->contains(p) ) { 111 112 auto group = dynamic_cast<CanvasItemGroup *>(&*item); 113 if (group) { 114 picked_item = group->pick_item(p); 115 } else { 116 picked_item = &*item; 117 } 118 } 119 120 if (picked_item != nullptr) { 121 #ifdef CANVAS_ITEM_DEBUG 122 std::cout << " PICKING: pick_item: " << picked_item->get_name() << std::endl; 123 #endif 124 return picked_item; 125 } 126 } 127 128 return nullptr; 129 } 130 update_canvas_item_ctrl_sizes(int size_index)131void CanvasItemGroup::update_canvas_item_ctrl_sizes(int size_index) 132 { 133 for (auto & item : items) { 134 auto ctrl = dynamic_cast<CanvasItemCtrl *>(&item); 135 if (ctrl) { 136 // We can't use set_size_default as the preference file is updated ->after<- the signal is emitted! 137 ctrl->set_size_via_index(size_index); 138 } 139 auto group = dynamic_cast<CanvasItemGroup *>(&item); 140 if (group) { 141 group->update_canvas_item_ctrl_sizes(size_index); 142 } 143 } 144 } 145 146 } // Namespace Inkscape 147 /* 148 Local Variables: 149 mode:c++ 150 c-file-style:"stroustrup" 151 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) 152 indent-tabs-mode:nil 153 fill-column:99 154 End: 155 */ 156 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : 157