summaryrefslogtreecommitdiffstats
path: root/src/display/control/canvas-item-group.cpp
blob: 8e53857616d67b3cfba4d8d36b0efd92758e7a93 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// SPDX-License-Identifier: GPL-2.0-or-later
/**
 * A CanvasItem that contains other CanvasItem's.
 */

/*
 * Author:
 *   Tavmjong Bah
 *
 * Copyright (C) 2020 Tavmjong Bah
 *
 * Rewrite of SPCanvasGroup
 *
 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
 */

#include "canvas-item-group.h"
#include "canvas-item-ctrl.h"  // Update sizes

namespace Inkscape {

CanvasItemGroup::CanvasItemGroup(CanvasItemGroup *group)
    : CanvasItem(group)
{
    _name = "CanvasItemGroup";
    _pickable = true; // For now all groups are pickable... look into turning this off for some groups (e.g. temp).
}

CanvasItemGroup::~CanvasItemGroup()
{
    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!
    }
}

void CanvasItemGroup::add(CanvasItem *item)
{
#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
}

void CanvasItemGroup::remove(CanvasItem *item, bool Delete)
{
#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.
        }
    }
}

void CanvasItemGroup::update(Geom::Affine const &affine)
{
    if (_affine == affine && !_need_update) {
        // Nothing to do.
        return;
    }

    _affine = affine;
    _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());
    }
}

void CanvasItemGroup::render(Inkscape::CanvasItemBuffer *buf)
{
    if (_visible) {
        if (_bounds.interiorIntersects(buf->rect)) {
            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)
{
#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<CanvasItemGroup *>(&*item);
            if (group) {
                picked_item = group->pick_item(p);
            } else {
                picked_item = &*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;   
}

void CanvasItemGroup::update_canvas_item_ctrl_sizes(int size_index)
{
    for (auto & item : items) {
        auto ctrl = dynamic_cast<CanvasItemCtrl *>(&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<CanvasItemGroup *>(&item);
        if (group) {
            group->update_canvas_item_ctrl_sizes(size_index);
        }
    }
}

} // 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 :