GOFIGURE2  0.9.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
hoverpoints.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the demonstration applications of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** Commercial Usage
11 ** Licensees holding valid Qt Commercial licenses may use this file in
12 ** accordance with the Qt Commercial License Agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and Nokia.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this 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 have questions regarding the use of this file, please contact
37 ** Nokia at qt-info@nokia.com.
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 /*=========================================================================
43  Modifications were made by the GoFigure Dev. Team.
44  while at Megason Lab, Systems biology, Harvard Medical school, 2009-11
45 
46  Copyright (c) 2009-11, President and Fellows of Harvard College.
47  All rights reserved.
48 
49  Redistribution and use in source and binary forms, with or without
50  modification, are permitted provided that the following conditions are met:
51 
52  Redistributions of source code must retain the above copyright notice,
53  this list of conditions and the following disclaimer.
54  Redistributions in binary form must reproduce the above copyright notice,
55  this list of conditions and the following disclaimer in the documentation
56 // and/or other materials provided with the distribution.
57  Neither the name of the President and Fellows of Harvard College
58  nor the names of its contributors may be used to endorse or promote
59  products derived from this software without specific prior written
60  permission.
61 
62  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
63  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
64  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
65  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
66  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
67  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
68  OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
69  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
70  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
71  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
72  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
73 
74  =========================================================================*/
75 
76 #ifdef QT_OPENGL_SUPPORT
77 #include <QGLWidget>
78 #endif
79 
80 #include "hoverpoints.h"
81 
82 #define printf
83 
85  : QObject(widget)
86 {
87  m_widget = widget;
88  widget->installEventFilter(this);
89  widget->setAttribute(Qt::WA_AcceptTouchEvents);
90 
91  m_oldSize[0] = -1;
92  m_oldSize[1] = -1;
95  m_shape = shape;
96  m_pointPen = QPen(QColor(255, 255, 255, 191), 1);
97  m_connectionPen = QPen(QColor(255, 255, 255, 127), 2);
98  m_pointBrush = QBrush(QColor(191, 191, 191, 127));
99  m_pointSize = QSize(11, 11);
100  m_currentIndex = -1;
101  m_editable = true;
102  m_enabled = true;
103 
104  if(shape == HoverPoints::CircleShape){
105  m_pointPen = QPen(QColor(50, 50, 50, 191), 1);
106  m_connectionPen = QPen(QColor(0, 0, 0, 127), 2);
107  m_enabled = false;
108  }
109 
110  connect(this, SIGNAL(pointsChanged(QPolygonF)),
111  m_widget, SLOT(update()));
112 }
113 
114 
115 void HoverPoints::setEnabled(bool enabled)
116 {
117  if (m_enabled != enabled) {
118  m_enabled = enabled;
119  m_widget->update();
120  }
121 }
122 
123 
125 {
126  if (object == m_widget) {
127  switch (event->type()) {
128 
129  case QEvent::MouseButtonPress:
130  {
131  if(m_shape != CircleShape || !m_enabled)
132  break;
133 
135  return true;
136  QMouseEvent *me = (QMouseEvent *) event;
137 
138  QPointF clickPos = me->pos();
139  int index = -1;
140  for (int i=0; i<m_points.size(); ++i) {
141  QPainterPath path;
142  path.addEllipse(pointBoundingRect(i));
143 
144  if (path.contains(clickPos)) {
145  index = i;
146  break;
147  }
148  }
149 
150  if (me->button() == Qt::LeftButton) {
151  if (index == -1) {
152  if (!m_editable)
153  return false;
154  int pos = 0;
155  // Insert sort for x or y
156  if (m_sortType == XSort) {
157  for (int i=0; i<m_points.size(); ++i)
158  if (m_points.at(i).x() > clickPos.x()) {
159  pos = i;
160  break;
161  }
162  } else if (m_sortType == YSort) {
163  for (int i=0; i<m_points.size(); ++i)
164  if (m_points.at(i).y() > clickPos.y()) {
165  pos = i;
166  break;
167  }
168  }
169 
170  m_points.insert(pos, clickPos);
171  m_locks.insert(pos, 0);
172  m_currentIndex = pos;
173  firePointChange();
174  } else {
175  m_currentIndex = index;
176  }
177  return true;
178 
179  } else if (me->button() == Qt::RightButton) {
180  if (index >= 0 && m_editable) {
181  if (m_locks[index] == 0) {
182  m_locks.remove(index);
183  m_points.remove(index);
184  }
185  firePointChange();
186  return true;
187  }
188  }
189 
190  }
191  break;
192 
193  case QEvent::MouseButtonRelease:
194 
195  if(m_shape != CircleShape || !m_enabled)
196  break;
197 
199  return true;
200  m_currentIndex = -1;
201  break;
202 
203  case QEvent::MouseMove:
204 
205  if(m_shape != CircleShape || !m_enabled)
206  break;
207 
209  return true;
210  if (m_currentIndex >= 0)
211  movePoint(m_currentIndex, ((QMouseEvent *)event)->pos());
212  break;
213  case QEvent::TouchBegin:
214  case QEvent::TouchUpdate:
215  {
216  if(m_shape != CircleShape || !m_enabled)
217  break;
218 
219  const QTouchEvent *const touchEvent = static_cast<const QTouchEvent*>(event);
220  const QList<QTouchEvent::TouchPoint> points = touchEvent->touchPoints();
221  const qreal pointSize = qMax(m_pointSize.width(), m_pointSize.height());
222  foreach (const QTouchEvent::TouchPoint &touchPoint, points) {
223  const int id = touchPoint.id();
224  switch (touchPoint.state()) {
225  case Qt::TouchPointPressed:
226  {
227  // find the point, move it
229  int activePoint = -1;
230  qreal distance = -1;
231  const int pointsCount = m_points.size();
232  const int activePointCount = activePoints.size();
233  if (pointsCount == 2 && activePointCount == 1) { // only two points
234  activePoint = activePoints.contains(0) ? 1 : 0;
235  } else {
236  for (int i=0; i<pointsCount; ++i) {
237  if (activePoints.contains(i))
238  continue;
239 
240  qreal d = QLineF(touchPoint.pos(), m_points.at(i)).length();
241  if ((distance < 0 && d < 12 * pointSize) || d < distance) {
242  distance = d;
243  activePoint = i;
244  }
245 
246  }
247  }
248  if (activePoint != -1) {
249  m_fingerPointMapping.insert(touchPoint.id(), activePoint);
250  movePoint(activePoint, touchPoint.pos());
251  }
252  }
253  break;
254  case Qt::TouchPointReleased:
255  {
256  // move the point and release
258  movePoint(it.value(), touchPoint.pos());
260  }
261  break;
262  case Qt::TouchPointMoved:
263  {
264  // move the point
265  const int pointIdx = m_fingerPointMapping.value(id, -1);
266  if (pointIdx >= 0) // do we track this point?
267  movePoint(pointIdx, touchPoint.pos());
268  }
269  break;
270  default:
271  break;
272  }
273  }
275  event->ignore();
276  return false;
277  } else {
278  return true;
279  }
280  }
281  break;
282  case QEvent::TouchEnd:
283 
284  if(m_shape != CircleShape || !m_enabled)
285  break;
286 
288  event->ignore();
289  return false;
290  }
291  return true;
292  break;
293 
294  // even if !enable, we should update the position of the points on
295  // resize event
296  case QEvent::Resize:
297  {
298  QResizeEvent *e = (QResizeEvent *) event;
299  if (m_oldSize[0] == 0 || m_oldSize[1] == 0)
300  break;
301 
302  qreal stretch_x = e->size().width() / qreal(m_oldSize[0]);
303  qreal stretch_y = e->size().height() / qreal(m_oldSize[1]);
304 
305  for (int i=0; i<m_points.size(); ++i) {
306  QPointF p = m_points[i];
307  movePoint(i, QPointF(p.x() * stretch_x, p.y() * stretch_y), false);
308  }
309 
310  this->m_oldSize[0] = e->size().width();
311  m_oldSize[1] = e->size().height();
312  break;
313  }
314 
315  case QEvent::Paint:
316  {
317  if(!m_enabled)
318  break;
319 
320  QWidget *that_widget = m_widget;
321  m_widget = 0;
322  QApplication::sendEvent(object, event);
323  m_widget = that_widget;
324  paintPoints();
325  return true;
326  }
327  default:
328  break;
329  }
330  }
331 
332  return false;
333 }
334 
335 
337 {
338  QPainter p;
339  p.begin(m_widget);
340 
341  p.setRenderHint(QPainter::Antialiasing);
342 
343  if (m_connectionPen.style() != Qt::NoPen && m_connectionType != NoConnection)
344  {
347  }
348 
349  if(m_shape != CircleShape)
350  return;
351 
352  p.setPen(m_pointPen);
354 
355  for (int i=0; i<m_points.size(); ++i) {
356  QRectF bounds = pointBoundingRect(i);
357  p.drawEllipse(bounds);
358  }
359 }
360 
361 static QPointF bound_point(const QPointF &point, const QRectF &bounds, int lock)
362 {
363  QPointF p = point;
364 
365  qreal left = bounds.left();
366  qreal right = bounds.right();
367  qreal top = bounds.top();
368  qreal bottom = bounds.bottom();
369 
370  if (p.x() < left || (lock & HoverPoints::LockToLeft)) p.setX(left);
371  else if (p.x() > right || (lock & HoverPoints::LockToRight)) p.setX(right);
372 
373  if (p.y() < top || (lock & HoverPoints::LockToTop)) p.setY(top);
374  else if (p.y() > bottom || (lock & HoverPoints::LockToBottom)) p.setY(bottom);
375 
376  return p;
377 }
378 
380 {
381  if (points.size() != m_points.size())
383  m_points.clear();
384  for (int i=0; i<points.size(); ++i)
385  m_points << bound_point(points.at(i), boundingRect(), 0);
386 
387  m_locks.clear();
388  if (m_points.size() > 0) {
390 
391  m_locks.fill(0);
392  }
393 }
394 
395 
396 void HoverPoints::movePoint(int index, const QPointF &point, bool emitUpdate)
397 {
398  m_points[index] = bound_point(point, boundingRect(), m_locks.at(index));
399  if (emitUpdate)
400  firePointChange();
401 }
402 
403 
404 inline static bool x_less_than(const QPointF &p1, const QPointF &p2)
405 {
406  return p1.x() < p2.x();
407 }
408 
409 
410 inline static bool y_less_than(const QPointF &p1, const QPointF &p2)
411 {
412  return p1.y() < p2.y();
413 }
414 
416 {
417  if (m_sortType != NoSort) {
418 
419  QPointF oldCurrent;
420  if (m_currentIndex != -1) {
421  oldCurrent = m_points[m_currentIndex];
422  }
423 
424  if (m_sortType == XSort)
425  qSort(m_points.begin(), m_points.end(), x_less_than);
426  else if (m_sortType == YSort)
427  qSort(m_points.begin(), m_points.end(), y_less_than);
428 
429  // Compensate for changed order...
430  if (m_currentIndex != -1) {
431  for (int i=0; i<m_points.size(); ++i) {
432  if (m_points[i] == oldCurrent) {
433  m_currentIndex = i;
434  break;
435  }
436  }
437  }
438  }
439 
440  emit pointsChanged(m_points);
441 }
void addEllipse(const QRectF &boundingRectangle)
const QList< QTouchEvent::TouchPoint > & touchPoints() const
Qt::PenStyle style() const
Type type() const
iterator insert(const Key &key, const T &value)
int width() const
QVector< uint > m_locks
Definition: hoverpoints.h:162
QPointF pos() const
void setRenderHint(RenderHint hint, bool on)
void pointsChanged(const QPolygonF &points)
iterator begin()
QPolygonF points() const
Definition: hoverpoints.h:120
SortType m_sortType
Definition: hoverpoints.h:159
int size() const
QVector< T > & fill(const T &value, int size)
void drawPolyline(const QPointF *points, int pointCount)
Qt::TouchPointState state() const
bool contains(const QPointF &point) const
PointShape m_shape
Definition: hoverpoints.h:158
QSizeF pointSize() const
Definition: hoverpoints.h:123
void insert(int i, const T &value)
void setAttribute(Qt::WidgetAttribute attribute, bool on)
bool m_enabled
Definition: hoverpoints.h:167
qreal top() const
QPen m_pointPen
Definition: hoverpoints.h:171
bool m_editable
Definition: hoverpoints.h:166
qreal left() const
void update()
virtual bool event(QEvent *e)
static bool y_less_than(const QPointF &p1, const QPointF &p2)
HoverPoints(QWidget *widget, PointShape shape)
Definition: hoverpoints.cpp:84
qreal bottom() const
void clear()
qreal x() const
qreal y() const
QRectF pointBoundingRect(int i) const
Definition: hoverpoints.h:179
void resize(int size)
void installEventFilter(QObject *filterObj)
void setPen(const QColor &color)
void drawEllipse(const QRectF &rectangle)
Qt::MouseButton button() const
QRectF boundingRect() const
Definition: hoverpoints.h:189
void remove(int i)
bool sendEvent(QObject *receiver, QEvent *event)
static bool x_less_than(const QPointF &p1, const QPointF &p2)
QBrush m_pointBrush
Definition: hoverpoints.h:172
void setBrush(const QBrush &brush)
ConnectionType m_connectionType
Definition: hoverpoints.h:160
QWidget * m_widget
Definition: hoverpoints.h:154
iterator erase(iterator pos)
QPolygonF m_points
Definition: hoverpoints.h:156
void clear()
const T value(const Key &key) const
iterator find(const Key &key)
void paintPoints()
qreal right() const
const QSize & size() const
void setEnabled(bool enabled)
QSizeF m_pointSize
Definition: hoverpoints.h:164
bool contains(const T &value) const
const T & at(int i) const
QPen m_connectionPen
Definition: hoverpoints.h:173
bool isEmpty() const
int m_currentIndex
Definition: hoverpoints.h:165
void setX(qreal x)
void setY(qreal y)
void setPoints(const QPolygonF &points)
int height() const
QSet< T > fromList(const QList< T > &list)
QList< T > values() const
void firePointChange()
const QPoint & pos() const
static QPointF bound_point(const QPointF &point, const QRectF &bounds, int lock)
qreal height() const
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
int size() const
bool begin(QPaintDevice *device)
void movePoint(int i, const QPointF &newPos, bool emitChange=true)
QHash< int, int > m_fingerPointMapping
Definition: hoverpoints.h:169
iterator end()
qreal width() const
double m_oldSize[2]
Definition: hoverpoints.h:175
bool eventFilter(QObject *object, QEvent *event)