1 // SPDX-License-Identifier: GPL-3.0-or-later
2 // SPDX-FileCopyrightText: 2021 Yurii Puchkov & Contributors
3
4 #include "capturetoolobjects.h"
5
6 #define SEARCH_RADIUS_NEAR 3
7 #define SEARCH_RADIUS_FAR 5
8 #define SEARCH_RADIUS_TEXT_HANDICAP 5
9
CaptureToolObjects(QObject * parent)10 CaptureToolObjects::CaptureToolObjects(QObject* parent)
11 : QObject(parent)
12 {}
13
append(const QPointer<CaptureTool> & captureTool)14 void CaptureToolObjects::append(const QPointer<CaptureTool>& captureTool)
15 {
16 if (!captureTool.isNull()) {
17 m_captureToolObjects.append(captureTool->copy(captureTool->parent()));
18 m_imageCache.clear();
19 }
20 }
21
at(int index)22 QPointer<CaptureTool> CaptureToolObjects::at(int index)
23 {
24 if (index >= 0 && index < m_captureToolObjects.size()) {
25 return m_captureToolObjects[index];
26 }
27 return nullptr;
28 }
29
clear()30 void CaptureToolObjects::clear()
31 {
32 m_captureToolObjects.clear();
33 }
34
captureToolObjects()35 QList<QPointer<CaptureTool>> CaptureToolObjects::captureToolObjects()
36 {
37 return m_captureToolObjects;
38 }
39
size()40 int CaptureToolObjects::size()
41 {
42 return m_captureToolObjects.size();
43 }
44
removeAt(int index)45 void CaptureToolObjects::removeAt(int index)
46 {
47 if (index >= 0 && index < m_captureToolObjects.size()) {
48 m_captureToolObjects.removeAt(index);
49 m_imageCache.clear();
50 }
51 }
52
find(const QPoint & pos,const QSize & captureSize)53 int CaptureToolObjects::find(const QPoint& pos, const QSize& captureSize)
54 {
55 if (m_captureToolObjects.empty()) {
56 return -1;
57 }
58 QPixmap pixmap(captureSize);
59 pixmap.fill(Qt::transparent);
60 QPainter painter(&pixmap);
61 // first attempt to find at exact position
62 int radius = SEARCH_RADIUS_NEAR;
63 int index = findWithRadius(painter, pixmap, pos, radius);
64 if (-1 == index) {
65 // second attempt to find at position with radius
66 radius = SEARCH_RADIUS_FAR;
67 pixmap.fill(Qt::transparent);
68 index = findWithRadius(painter, pixmap, pos, radius);
69 }
70 return index;
71 }
72
findWithRadius(QPainter & painter,QPixmap & pixmap,const QPoint & pos,int radius)73 int CaptureToolObjects::findWithRadius(QPainter& painter,
74 QPixmap& pixmap,
75 const QPoint& pos,
76 int radius)
77 {
78 int index = m_captureToolObjects.size() - 1;
79 bool useCache = true;
80 m_imageCache.clear();
81 if (m_imageCache.size() != m_captureToolObjects.size() && index >= 0) {
82 // TODO - is not optimal and cache will be used just after first tool
83 // object selecting
84 m_imageCache.clear();
85 useCache = false;
86 }
87 for (; index >= 0; --index) {
88 int currentRadius = radius;
89 QImage image;
90 auto toolItem = m_captureToolObjects.at(index);
91 if (useCache) {
92 image = m_imageCache.at(index);
93 } else {
94 // create transparent image in memory and draw toolItem on it
95 toolItem->drawSearchArea(painter, pixmap);
96
97 // get color at mouse clicked position in area +/- currentRadius
98 image = pixmap.toImage();
99 m_imageCache.insert(0, image);
100 }
101
102 if (toolItem->nameID() == ToolType::TEXT) {
103 if (currentRadius > SEARCH_RADIUS_NEAR) {
104 // Text already has a big currentRadius and no need to search
105 // with a bit bigger currentRadius than
106 // SEARCH_RADIUS_TEXT_HANDICAP + SEARCH_RADIUS_NEAR
107 continue;
108 }
109
110 // Text has spaces inside to need to take a bigger currentRadius for
111 // text objects search
112 currentRadius += SEARCH_RADIUS_TEXT_HANDICAP;
113 }
114
115 for (int x = pos.x() - currentRadius; x <= pos.x() + currentRadius;
116 ++x) {
117 for (int y = pos.y() - currentRadius; y <= pos.y() + currentRadius;
118 ++y) {
119 QRgb rgb = image.pixel(x, y);
120 if (rgb != 0) {
121 // object was found, return it index (layer index)
122 return index;
123 }
124 }
125 }
126 }
127 // no object at current pos found
128 return -1;
129 }
130
operator =(const CaptureToolObjects & other)131 CaptureToolObjects& CaptureToolObjects::operator=(
132 const CaptureToolObjects& other)
133 {
134 // remove extra items for this if size is bigger
135 while (this->m_captureToolObjects.size() >
136 other.m_captureToolObjects.size()) {
137 this->m_captureToolObjects.removeLast();
138 }
139
140 int count = 0;
141 for (const auto& item : other.m_captureToolObjects) {
142 QPointer<CaptureTool> itemCopy = item->copy(item->parent());
143 if (count < this->m_captureToolObjects.size()) {
144 this->m_captureToolObjects[count] = itemCopy;
145 } else {
146 this->m_captureToolObjects.append(itemCopy);
147 }
148 count++;
149 }
150 return *this;
151 }