comparison demos/shared/hoverpoints.d @ 41:691e68637348

non-working deform example
author maxter
date Sun, 17 May 2009 12:41:14 +0000
parents
children 4bbd9f3d9add
comparison
equal deleted inserted replaced
40:a5cc4ada07f5 41:691e68637348
1 /****************************************************************************
2 **
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: Qt Software Information (qt-info@nokia.com)
5 **
6 ** This file is part of the demonstration applications of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial Usage
10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 ** accordance with the Qt Commercial License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Nokia.
14 **
15 ** GNU Lesser General Public License Usage
16 ** Alternatively, this file may be used under the terms of the GNU Lesser
17 ** General Public License version 2.1 as published by the Free Software
18 ** Foundation and appearing in the file LICENSE.LGPL included in the
19 ** packaging of this file. Please review the following information to
20 ** ensure the GNU Lesser General Public License version 2.1 requirements
21 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22 **
23 ** In addition, as a special exception, Nokia gives you certain
24 ** additional rights. These rights are described in the Nokia Qt LGPL
25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26 ** package.
27 **
28 ** GNU General Public License Usage
29 ** Alternatively, this file may be used under the terms of the GNU
30 ** General Public License version 3.0 as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL included in the
32 ** packaging of this file. Please review the following information to
33 ** ensure the GNU General Public License version 3.0 requirements will be
34 ** met: http://www.gnu.org/copyleft/gpl.html.
35 **
36 ** If you are unsure which license is appropriate for your use, please
37 ** contact the sales department at qt-sales@nokia.com.
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 version (QT_OPENGL_SUPPORT)
43 import qt.opengl.QGLWidget;
44
45 version (D_Version2) {}
46 else
47 import tango.core.Array : sort;
48
49 import
50 qt.gui.QWidget,
51 qt.qtd.Array,
52 arthurwidgets;
53
54 final class HoverPoints : QObject
55 {
56 public:
57 enum PointShape {
58 CircleShape,
59 RectangleShape
60 }
61
62 enum LockType {
63 LockToLeft = 0x01,
64 LockToRight = 0x02,
65 LockToTop = 0x04,
66 LockToBottom = 0x08
67 }
68
69 enum SortType {
70 NoSort,
71 XSort,
72 YSort
73 }
74
75 enum ConnectionType {
76 NoConnection,
77 LineConnection,
78 CurveConnection
79 }
80
81 private:
82 QWidget m_widget;
83
84 QPolygonF m_points;
85 QRectF m_bounds;
86 PointShape m_shape;
87 SortType m_sortType;
88 ConnectionType m_connectionType;
89
90 uint[] m_locks;
91
92 QSizeF m_pointSize;
93 int m_currentIndex;
94 bool m_editable;
95 bool m_enabled;
96
97 QPen m_pointPen;
98 QBrush m_pointBrush;
99 QPen m_connectionPen;
100
101 public:
102 mixin Signal!("pointsChanged", QPolygonF /*points*/);
103
104 this(QWidget widget, PointShape shape)
105 {
106 super(widget);
107
108 m_widget = widget;
109 widget.installEventFilter(this);
110
111 m_connectionType = ConnectionType.CurveConnection;
112 m_sortType = SortType.NoSort;
113 m_shape = shape;
114 m_pointPen = new QPen(new QBrush(new QColor(255, 255, 255, 191)), 1);
115 m_connectionPen = new QPen(new QBrush(new QColor(255, 255, 255, 127)), 2);
116 m_pointBrush = new QBrush(new QColor(191, 191, 191, 127));
117 m_pointSize = QSizeF(11, 11);
118 m_currentIndex = -1;
119 m_editable = true;
120 m_enabled = true;
121
122 pointsChanged.connect(&m_widget.update);
123 }
124
125 void setBoundingRect(QRectF boundingRect) { m_bounds = boundingRect; }
126
127
128 QRectF pointBoundingRect(int i)
129 {
130 QPointF p = m_points.at(i);
131 qreal w = m_pointSize.width();
132 qreal h = m_pointSize.height();
133 qreal x = p.x() - w / 2;
134 qreal y = p.y() - h / 2;
135 return new QRectF(x, y, w, h);
136 }
137
138 QRectF boundingRect()
139 {
140 if (m_bounds.isEmpty())
141 return new QRectF(m_widget.rect());
142 else
143 return m_bounds;
144 }
145
146 QPolygonF points() { return m_points; }
147
148 QSizeF pointSize() { return m_pointSize; }
149 void setPointSize(QSizeF size) { m_pointSize = size; }
150
151 SortType sortType() { return m_sortType; }
152 void setSortType(SortType sortType) { m_sortType = sortType; }
153
154 ConnectionType connectionType() { return m_connectionType; }
155 void setConnectionType(ConnectionType connectionType) { m_connectionType = connectionType; }
156
157 void setConnectionPen(QPen pen) { m_connectionPen = pen; }
158 void setShapePen(QPen pen) { m_pointPen = pen; }
159 void setShapeBrush(QBrush brush) { m_pointBrush = brush; }
160
161 void setPointLock(int pos, LockType lock) { m_locks[pos] = lock; }
162
163 void setEditable(bool editable) { m_editable = editable; }
164 bool editable() { return m_editable; }
165
166 void setEnabled(bool enabled)
167 {
168 if (m_enabled != enabled) {
169 m_enabled = enabled;
170 m_widget.update();
171 }
172 }
173
174
175 override bool eventFilter(QObject object, QEvent event)
176 {
177 if ((object == m_widget) && m_enabled) {
178 switch (event.type()) {
179
180 case QEvent.MouseButtonPress:
181 {
182 QMouseEvent me = cast(QMouseEvent) event;
183
184 QPointF clickPos = me.pos();
185 int index = -1;
186 for (int i=0; i<m_points.size(); ++i) {
187 auto path = new QPainterPath;
188 if (m_shape == PointShape.CircleShape)
189 path.addEllipse(pointBoundingRect(i));
190 else
191 path.addRect(pointBoundingRect(i));
192
193 if (path.contains(clickPos)) {
194 index = i;
195 break;
196 }
197 }
198
199 if (me.button() == Qt.LeftButton) {
200 if (index == -1) {
201 if (!m_editable)
202 return false;
203 int pos = 0;
204 // Insert sort for x or y
205 if (m_sortType == SortType.XSort) {
206 for (int i=0; i<m_points.size(); ++i)
207 if (m_points.at(i).x() > clickPos.x()) {
208 pos = i;
209 break;
210 }
211 } else if (m_sortType == SortType.YSort) {
212 for (int i=0; i<m_points.size(); ++i)
213 if (m_points.at(i).y() > clickPos.y()) {
214 pos = i;
215 break;
216 }
217 }
218
219 // TODO: implement QPoligon(F).insert
220 auto tmpPoints = m_points.toList;
221 tmpPoints.insert(pos, clickPos);
222 m_points = new QPolygonF(tmpPoints);
223
224 m_locks.insert(pos, 0u);
225 m_currentIndex = pos;
226 firePointChange();
227 } else {
228 m_currentIndex = index;
229 }
230 return true;
231
232 } else if (me.button() == Qt.RightButton) {
233 if ((index >= 0) && m_editable) {
234 if (m_locks[index] == 0) {
235 m_locks.removeAt(index);
236 m_points.remove(index);
237 }
238 firePointChange();
239 return true;
240 }
241 }
242
243 }
244 break;
245
246 case QEvent.MouseButtonRelease:
247 m_currentIndex = -1;
248 break;
249
250 case QEvent.MouseMove:
251 if (m_currentIndex >= 0)
252 movePoint(m_currentIndex, QPointF((cast(QMouseEvent)event).pos));
253 break;
254
255 case QEvent.Resize:
256 {
257 QResizeEvent e = cast(QResizeEvent) event;
258 if (e.oldSize().width() == 0 || e.oldSize().height() == 0)
259 break;
260 qreal stretch_x = e.size().width() / cast(qreal)e.oldSize.width;
261 qreal stretch_y = e.size().height() / cast(qreal)e.oldSize.height;
262 for (int i=0; i<m_points.size(); ++i) {
263 QPointF p = m_points.at(i);
264 movePoint(i, QPointF(p.x() * stretch_x, p.y() * stretch_y), false);
265 }
266
267 firePointChange();
268 break;
269 }
270
271 case QEvent.Paint:
272 {
273 QWidget that_widget = m_widget;
274 m_widget = null;
275 QApplication.sendEvent(object, event);
276 m_widget = that_widget;
277 paintPoints();
278 version (QT_OPENGL_SUPPORT)
279 {
280 ArthurFrame af = cast(ArthurFrame)(that_widget);
281 if (af && af.usesOpenGL())
282 af.glWidget().swapBuffers();
283 }
284
285 return true;
286 }
287 default:
288 break;
289 }
290 }
291
292 return false;
293 }
294
295
296 void paintPoints()
297 {
298 scope p = new QPainter;
299 version (QT_OPENGL_SUPPORT)
300 {
301 ArthurFrame af = cast(ArthurFrame)(m_widget);
302 if (af && af.usesOpenGL())
303 p.begin(af.glWidget());
304 else
305 p.begin(m_widget);
306 }
307 else
308 p.begin(m_widget);
309
310 p.setRenderHint(QPainter.Antialiasing);
311
312 if (m_connectionPen.style() != Qt.NoPen && m_connectionType != ConnectionType.NoConnection) {
313 p.setPen(m_connectionPen);
314
315 if (m_connectionType == ConnectionType.CurveConnection) {
316 auto path = new QPainterPath;
317 path.moveTo(m_points.at(0));
318 for (int i=1; i<m_points.size(); ++i) {
319 QPointF p1 = m_points.at(i-1);
320 QPointF p2 = m_points.at(i);
321 qreal distance = p2.x() - p1.x();
322
323 path.cubicTo(p1.x() + distance / 2, p1.y(),
324 p1.x() + distance / 2, p2.y(),
325 p2.x(), p2.y());
326 }
327 p.drawPath(path);
328 } else {
329 p.drawPolyline(m_points);
330 }
331 }
332
333 p.setPen(m_pointPen);
334 p.setBrush(m_pointBrush);
335
336 for (int i=0; i<m_points.size(); ++i) {
337 QRectF bounds = pointBoundingRect(i);
338 if (m_shape == PointShape.CircleShape)
339 p.drawEllipse(bounds);
340 else
341 p.drawRect(bounds);
342 }
343 }
344
345
346 void setPoints(QPolygonF points)
347 {
348 delete m_points;
349 for (int i=0; i<points.size; ++i)
350 m_points.append(bound_point(points.at(i), boundingRect(), 0));
351
352 delete m_locks;
353 if (m_points.size > 0) {
354 m_locks.length = m_points.size;
355
356 m_locks[] = 0;
357 }
358 }
359
360 void movePoint(int index, QPointF point, bool emitUpdate = true)
361 {
362 m_points.replace(index, bound_point(point, boundingRect(), m_locks[index]));
363 if (emitUpdate)
364 firePointChange();
365 }
366
367 void firePointChange()
368 {
369 // printf("HoverPoints.firePointChange(), current=%d\n", m_currentIndex);
370
371 if (m_sortType != SortType.NoSort) {
372
373 QPointF oldCurrent;
374 if (m_currentIndex != -1) {
375 oldCurrent = m_points.at(m_currentIndex);
376 }
377
378 if (m_sortType == SortType.XSort)
379 {
380 auto tmpPoints = m_points.toList;
381 sort(tmpPoints, &x_less_than);
382 m_points = new QPolygonF(tmpPoints);
383 }
384 else if (m_sortType == SortType.YSort)
385 {
386 auto tmpPoints = m_points.toList;
387 sort(tmpPoints, &y_less_than);
388 m_points = new QPolygonF(tmpPoints);
389 }
390
391 // Compensate for changed order...
392 if (m_currentIndex != -1) {
393 for (int i=0; i<m_points.size; ++i) {
394 if (m_points.at(i) == oldCurrent) {
395 m_currentIndex = i;
396 break;
397 }
398 }
399 }
400
401 // printf(" - firePointChange(), current=%d\n", m_currentIndex);
402 }
403
404 // for (int i=0; i<m_points.size(); ++i) {
405 // printf(" - point(%2d)=[%.2f, %.2f], lock=%d\n",
406 // i, m_points.at(i).x(), m_points.at(i).y(), m_locks.at(i));
407 // }
408
409 pointsChanged.emit(m_points);
410 }
411 }
412
413 private QPointF bound_point(QPointF point, QRectF bounds, int lock)
414 {
415 QPointF p = point;
416
417 qreal left = bounds.left();
418 qreal right = bounds.right();
419 qreal top = bounds.top();
420 qreal bottom = bounds.bottom();
421
422 if (p.x() < left || (lock & HoverPoints.LockType.LockToLeft)) p.x = left;
423 else if (p.x() > right || (lock & HoverPoints.LockType.LockToRight)) p.x = right;
424
425 if (p.y() < top || (lock & HoverPoints.LockType.LockToTop)) p.y = top;
426 else if (p.y() > bottom || (lock & HoverPoints.LockType.LockToBottom)) p.y = bottom;
427
428 return p;
429 }
430
431 private bool x_less_than(QPointF p1, QPointF p2)
432 {
433 return p1.x() < p2.x();
434 }
435
436 private bool y_less_than(QPointF p1, QPointF p2)
437 {
438 return p1.y() < p2.y();
439 }