]> sigrok.org Git - pulseview.git/blame - pv/widgets/popup.cpp
QWellArray: removed unused destructor
[pulseview.git] / pv / widgets / popup.cpp
CommitLineData
6e3f046e
JH
1/*
2 * This file is part of the PulseView project.
3 *
4 * Copyright (C) 2013 Joel Holdsworth <joel@airwebreathe.org.uk>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include <algorithm>
22
b213ef09
JH
23#include <assert.h>
24
6e3f046e
JH
25#include <QtGui>
26
27#include "popup.h"
28
819f4c25
JH
29using std::max;
30using std::min;
6e3f046e
JH
31
32namespace pv {
33namespace widgets {
34
b6a2899a 35const unsigned int Popup::ArrowLength = 10;
6e3f046e 36const unsigned int Popup::ArrowOverlap = 3;
b6a2899a 37const unsigned int Popup::MarginWidth = 6;
6e3f046e
JH
38
39Popup::Popup(QWidget *parent) :
40 QWidget(parent, Qt::Popup | Qt::FramelessWindowHint),
41 _point(),
42 _pos(Left)
43{
44}
45
46const QPoint& Popup::point() const
47{
48 return _point;
49}
50
51Popup::Position Popup::position() const
52{
53 return _pos;
54}
55
56void Popup::set_position(const QPoint point, Position pos)
57{
58 _point = point, _pos = pos;
59
60 setContentsMargins(
61 MarginWidth + ((pos == Right) ? ArrowLength : 0),
62 MarginWidth + ((pos == Bottom) ? ArrowLength : 0),
63 MarginWidth + ((pos == Left) ? ArrowLength : 0),
64 MarginWidth + ((pos == Top) ? ArrowLength : 0));
65
66}
67
092e2a0a
JH
68bool Popup::space_for_arrow() const
69{
70 // Check if there is room for the arrow
71 switch (_pos) {
72 case Right:
73 if (_point.x() > x())
74 return false;
75 return true;
76
77 case Bottom:
78 if (_point.y() > y())
79 return false;
80 return true;
81
82 case Left:
83 if (_point.x() < (x() + width()))
84 return false;
85 return true;
86
87 case Top:
88 if (_point.y() < (y() + height()))
89 return false;
90 return true;
91 }
92
93 return true;
94}
95
6e3f046e
JH
96QPolygon Popup::arrow_polygon() const
97{
98 QPolygon poly;
99
100 const QPoint p = mapFromGlobal(_point);
101 const int l = ArrowLength + ArrowOverlap;
102
103 switch (_pos)
104 {
105 case Right:
106 poly << QPoint(p.x() + l, p.y() - l);
107 break;
108
109 case Bottom:
110 poly << QPoint(p.x() - l, p.y() + l);
111 break;
112
113 case Left:
114 case Top:
115 poly << QPoint(p.x() - l, p.y() - l);
116 break;
117 }
118
119 poly << p;
120
121 switch (_pos)
122 {
123 case Right:
124 case Bottom:
125 poly << QPoint(p.x() + l, p.y() + l);
126 break;
127
128 case Left:
129 poly << QPoint(p.x() - l, p.y() + l);
130 break;
131
132 case Top:
133 poly << QPoint(p.x() + l, p.y() - l);
134 break;
135 }
136
137 return poly;
138}
139
140QRegion Popup::arrow_region() const
141{
142 return QRegion(arrow_polygon());
143}
144
145QRect Popup::bubble_rect() const
146{
147 return QRect(
148 QPoint((_pos == Right) ? ArrowLength : 0,
149 (_pos == Bottom) ? ArrowLength : 0),
150 QSize(width() - ((_pos == Left || _pos == Right) ?
151 ArrowLength : 0),
152 height() - ((_pos == Top || _pos == Bottom) ?
153 ArrowLength : 0)));
154}
155
156QRegion Popup::bubble_region() const
157{
158 const QRect rect(bubble_rect());
159
160 const unsigned int r = MarginWidth;
161 const unsigned int d = 2 * r;
162 return QRegion(rect.adjusted(r, 0, -r, 0)).united(
163 QRegion(rect.adjusted(0, r, 0, -r))).united(
164 QRegion(rect.left(), rect.top(), d, d,
165 QRegion::Ellipse)).united(
166 QRegion(rect.right() - d, rect.top(), d, d,
167 QRegion::Ellipse)).united(
168 QRegion(rect.left(), rect.bottom() - d, d, d,
169 QRegion::Ellipse)).united(
170 QRegion(rect.right() - d, rect.bottom() - d, d, d,
171 QRegion::Ellipse));
172}
173
174QRegion Popup::popup_region() const
175{
092e2a0a
JH
176 if (space_for_arrow())
177 return arrow_region().united(bubble_region());
178 else
179 return bubble_region();
6e3f046e
JH
180}
181
182void Popup::reposition_widget()
183{
184 QPoint o;
185
092e2a0a
JH
186 const QRect screen_rect = QApplication::desktop()->availableGeometry(
187 QApplication::desktop()->screenNumber(_point));
188
6e3f046e
JH
189 if (_pos == Right || _pos == Left)
190 o.ry() = -height() / 2;
191 else
192 o.rx() = -width() / 2;
193
194 if (_pos == Left)
195 o.rx() = -width();
196 else if(_pos == Top)
197 o.ry() = -height();
198
092e2a0a
JH
199 o += _point;
200 move(max(min(o.x(), screen_rect.right() - width()),
201 screen_rect.left()),
202 max(min(o.y(), screen_rect.bottom() - height()),
203 screen_rect.top()));
6e3f046e
JH
204}
205
0bce8609
JH
206void Popup::closeEvent(QCloseEvent*)
207{
208 closed();
209}
210
6e3f046e
JH
211void Popup::paintEvent(QPaintEvent*)
212{
213 QPainter painter(this);
214 painter.setRenderHint(QPainter::Antialiasing);
215
216 const QColor outline_color(QApplication::palette().color(
217 QPalette::Dark));
218
092e2a0a 219 // Draw the bubble
6e3f046e
JH
220 const QRegion b = bubble_region();
221 const QRegion bubble_outline = QRegion(rect()).subtracted(
222 b.translated(1, 0).intersected(b.translated(0, 1).intersected(
223 b.translated(-1, 0).intersected(b.translated(0, -1)))));
224
225 painter.setPen(Qt::NoPen);
226 painter.setBrush(QApplication::palette().brush(QPalette::Window));
227 painter.drawRect(rect());
228
092e2a0a
JH
229 // Draw the arrow
230 if (!space_for_arrow())
231 return;
232
6e3f046e
JH
233 const QPoint ArrowOffsets[] = {
234 QPoint(1, 0), QPoint(0, -1), QPoint(-1, 0), QPoint(0, 1)};
235
236 const QRegion a(arrow_region());
237 const QRegion arrow_outline = a.subtracted(
238 a.translated(ArrowOffsets[_pos]));
239
240 painter.setClipRegion(bubble_outline.subtracted(a).united(
241 arrow_outline));
242 painter.setBrush(outline_color);
243 painter.drawRect(rect());
244}
245
246void Popup::resizeEvent(QResizeEvent*)
247{
248 reposition_widget();
249 setMask(popup_region());
250}
251
6e3f046e
JH
252void Popup::mouseReleaseEvent(QMouseEvent *e)
253{
254 assert(e);
255
256 // We need our own out-of-bounds click handler because QWidget counts
257 // the drop-shadow region as inside the widget
258 if(!bubble_rect().contains(e->pos()))
259 close();
260}
261
b7b659aa
JH
262void Popup::showEvent(QShowEvent*)
263{
264 reposition_widget();
265}
266
6e3f046e
JH
267} // namespace widgets
268} // namespace pv
269