FlowVis 1.0
|
00001 /**************************************************************************** 00002 ** 00003 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). 00004 ** All rights reserved. 00005 ** Contact: Nokia Corporation (qt-info@nokia.com) 00006 ** 00007 ** This file is part of the demonstration applications of the Qt Toolkit. 00008 ** 00009 ** $QT_BEGIN_LICENSE:LGPL$ 00010 ** Commercial Usage 00011 ** Licensees holding valid Qt Commercial licenses may use this file in 00012 ** accordance with the Qt Commercial License Agreement provided with the 00013 ** Software or, alternatively, in accordance with the terms contained in 00014 ** a written agreement between you and Nokia. 00015 ** 00016 ** GNU Lesser General Public License Usage 00017 ** Alternatively, this file may be used under the terms of the GNU Lesser 00018 ** General Public License version 2.1 as published by the Free Software 00019 ** Foundation and appearing in the file LICENSE.LGPL included in the 00020 ** packaging of this file. Please review the following information to 00021 ** ensure the GNU Lesser General Public License version 2.1 requirements 00022 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 00023 ** 00024 ** In addition, as a special exception, Nokia gives you certain additional 00025 ** rights. These rights are described in the Nokia Qt LGPL Exception 00026 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 00027 ** 00028 ** GNU General Public License Usage 00029 ** Alternatively, this file may be used under the terms of the GNU 00030 ** General Public License version 3.0 as published by the Free Software 00031 ** Foundation and appearing in the file LICENSE.GPL included in the 00032 ** packaging of this file. Please review the following information to 00033 ** ensure the GNU General Public License version 3.0 requirements will be 00034 ** met: http://www.gnu.org/copyleft/gpl.html. 00035 ** 00036 ** If you have questions regarding the use of this file, please contact 00037 ** Nokia at qt-info@nokia.com. 00038 ** $QT_END_LICENSE$ 00039 ** 00040 ****************************************************************************/ 00041 00042 #ifdef QT_OPENGL_SUPPORT 00043 #include <QGLWidget> 00044 #endif 00045 00046 //#include "arthurwidgets.h" 00047 #include "hoverpoints.h" 00048 00049 #define printf 00050 00051 HoverPoints::HoverPoints(QWidget *widget, PointShape shape) 00052 : QObject(widget) 00053 { 00054 m_widget = widget; 00055 widget->installEventFilter(this); 00056 widget->setAttribute(Qt::WA_AcceptTouchEvents); 00057 00058 m_connectionType = CurveConnection; 00059 m_sortType = NoSort; 00060 m_shape = shape; 00061 m_pointPen = QPen(QColor(255, 255, 255, 191), 1); 00062 m_connectionPen = QPen(QColor(255, 255, 255, 127), 2); 00063 m_pointBrush = QBrush(QColor(191, 191, 191, 127)); 00064 m_pointSize = QSize(11, 11); 00065 m_currentIndex = -1; 00066 m_currentColorIndex = 0; 00067 m_editable = true; 00068 m_enabled = true; 00069 m_currentColor = Qt::white; 00070 m_selectedPointPen = QPen(QColor(255,255,255,255),3); 00071 00072 connect(this, SIGNAL(pointsChanged(QPolygonF)), 00073 m_widget, SLOT(update())); 00074 } 00075 00076 00077 void HoverPoints::setEnabled(bool enabled) 00078 { 00079 if (m_enabled != enabled) { 00080 m_enabled = enabled; 00081 m_widget->update(); 00082 } 00083 } 00084 00085 00086 bool HoverPoints::eventFilter(QObject *object, QEvent *event) 00087 { 00088 if (object == m_widget && m_enabled) { 00089 switch (event->type()) { 00090 00091 case QEvent::MouseButtonPress: 00092 { 00093 if (!m_fingerPointMapping.isEmpty()) 00094 return true; 00095 QMouseEvent *me = (QMouseEvent *) event; 00096 00097 QPointF clickPos = me->pos(); 00098 int index = -1; 00099 for (int i=0; i<m_points.size(); ++i) { 00100 QPainterPath path; 00101 if (m_shape == CircleShape) 00102 path.addEllipse(pointBoundingRect(i)); 00103 else 00104 path.addRect(pointBoundingRect(i)); 00105 00106 if (path.contains(clickPos)) { 00107 index = i; 00108 m_currentColorIndex = i; 00109 firePointChange(); 00110 break; 00111 } 00112 } 00113 00114 if (me->button() == Qt::LeftButton) { 00115 if (index == -1) { 00116 if (!m_editable) 00117 return false; 00118 int pos = 0; 00119 // Insert sort for x or y 00120 if (m_sortType == XSort) { 00121 for (int i=0; i<m_points.size(); ++i) 00122 if (m_points.at(i).x() > clickPos.x()) { 00123 pos = i; 00124 break; 00125 } 00126 } else if (m_sortType == YSort) { 00127 for (int i=0; i<m_points.size(); ++i) 00128 if (m_points.at(i).y() > clickPos.y()) { 00129 pos = i; 00130 break; 00131 } 00132 } 00133 00134 m_colors.insert(pos,m_currentColor); 00135 m_points.insert(pos, clickPos); 00136 m_locks.insert(pos, 0); 00137 m_currentIndex = pos; 00138 m_currentColorIndex = pos; 00139 firePointChange(); 00140 } else { 00141 m_currentIndex = index; 00142 } 00143 return true; 00144 00145 } else if (me->button() == Qt::RightButton) { 00146 if (index >= 0 && m_editable) { 00147 if (m_locks[index] == 0) { 00148 m_locks.remove(index); 00149 m_points.remove(index); 00150 m_colors.remove(index); 00151 } 00152 firePointChange(); 00153 m_currentColorIndex = index-1; 00154 return true; 00155 } 00156 } 00157 00158 } 00159 break; 00160 00161 case QEvent::MouseButtonRelease: 00162 if (!m_fingerPointMapping.isEmpty()) 00163 return true; 00164 m_currentIndex = -1; 00165 break; 00166 00167 case QEvent::MouseMove: 00168 if (!m_fingerPointMapping.isEmpty()) 00169 return true; 00170 if (m_currentIndex >= 0) 00171 movePoint(m_currentIndex, ((QMouseEvent *)event)->pos()); 00172 break; 00173 case QEvent::TouchBegin: 00174 case QEvent::TouchUpdate: 00175 { 00176 const QTouchEvent *const touchEvent = static_cast<const QTouchEvent*>(event); 00177 const QList<QTouchEvent::TouchPoint> points = touchEvent->touchPoints(); 00178 const qreal pointSize = qMax(m_pointSize.width(), m_pointSize.height()); 00179 foreach (const QTouchEvent::TouchPoint &touchPoint, points) { 00180 const int id = touchPoint.id(); 00181 switch (touchPoint.state()) { 00182 case Qt::TouchPointPressed: 00183 { 00184 // find the point, move it 00185 QSet<int> activePoints = QSet<int>::fromList(m_fingerPointMapping.values()); 00186 int activePoint = -1; 00187 qreal distance = -1; 00188 const int pointsCount = m_points.size(); 00189 const int activePointCount = activePoints.size(); 00190 if (pointsCount == 2 && activePointCount == 1) { // only two points 00191 activePoint = activePoints.contains(0) ? 1 : 0; 00192 } else { 00193 for (int i=0; i<pointsCount; ++i) { 00194 if (activePoints.contains(i)) 00195 continue; 00196 00197 qreal d = QLineF(touchPoint.pos(), m_points.at(i)).length(); 00198 if ((distance < 0 && d < 12 * pointSize) || d < distance) { 00199 distance = d; 00200 activePoint = i; 00201 } 00202 00203 } 00204 } 00205 if (activePoint != -1) { 00206 m_fingerPointMapping.insert(touchPoint.id(), activePoint); 00207 movePoint(activePoint, touchPoint.pos()); 00208 } 00209 } 00210 break; 00211 case Qt::TouchPointReleased: 00212 { 00213 // move the point and release 00214 QHash<int,int>::iterator it = m_fingerPointMapping.find(id); 00215 movePoint(it.value(), touchPoint.pos()); 00216 m_fingerPointMapping.erase(it); 00217 } 00218 break; 00219 case Qt::TouchPointMoved: 00220 { 00221 // move the point 00222 const int pointIdx = m_fingerPointMapping.value(id, -1); 00223 if (pointIdx >= 0) // do we track this point? 00224 movePoint(pointIdx, touchPoint.pos()); 00225 } 00226 break; 00227 default: 00228 break; 00229 } 00230 } 00231 if (m_fingerPointMapping.isEmpty()) { 00232 event->ignore(); 00233 return false; 00234 } else { 00235 return true; 00236 } 00237 } 00238 break; 00239 case QEvent::TouchEnd: 00240 if (m_fingerPointMapping.isEmpty()) { 00241 event->ignore(); 00242 return false; 00243 } 00244 return true; 00245 break; 00246 00247 case QEvent::Resize: 00248 { 00249 //QResizeEvent *e = (QResizeEvent *) event; 00250 //if (e->oldSize().width() == 0 || e->oldSize().height() == 0) 00251 // break; 00252 //qreal stretch_x = e->size().width() / qreal(e->oldSize().width()); 00253 //qreal stretch_y = e->size().height() / qreal(e->oldSize().height()); 00254 //for (int i=0; i<m_points.size(); ++i) { 00255 // QPointF p = m_points[i]; 00256 // movePoint(i, QPointF(p.x() * stretch_x, p.y() * stretch_y), false); 00257 //} 00258 00259 firePointChange(); 00260 break; 00261 } 00262 00263 case QEvent::Paint: 00264 { 00265 QWidget *that_widget = m_widget; 00266 m_widget = 0; 00267 QApplication::sendEvent(object, event); 00268 m_widget = that_widget; 00269 paintPoints(); 00270 /*#ifdef QT_OPENGL_SUPPORT 00271 ArthurFrame *af = qobject_cast<ArthurFrame *>(that_widget); 00272 if (af && af->usesOpenGL()) 00273 af->glWidget()->swapBuffers(); 00274 #endif*/ 00275 return true; 00276 } 00277 default: 00278 break; 00279 } 00280 } 00281 00282 return false; 00283 } 00284 00285 00286 void HoverPoints::paintPoints() 00287 { 00288 QPainter p; 00289 //#ifdef QT_OPENGL_SUPPORT 00290 // ArthurFrame *af = qobject_cast<ArthurFrame *>(m_widget); 00291 // if (af && af->usesOpenGL()) 00292 // p.begin(af->glWidget()); 00293 // else 00294 // p.begin(m_widget); 00295 //#else 00296 p.begin(m_widget); 00297 //#endif 00298 00299 p.setRenderHint(QPainter::Antialiasing); 00300 00301 if (m_connectionPen.style() != Qt::NoPen && m_connectionType != NoConnection) { 00302 p.setPen(m_connectionPen); 00303 00304 if (m_connectionType == CurveConnection) { 00305 QPainterPath path; 00306 path.moveTo(m_points.at(0)); 00307 for (int i=1; i<m_points.size(); ++i) { 00308 QPointF p1 = m_points.at(i-1); 00309 QPointF p2 = m_points.at(i); 00310 qreal distance = p2.x() - p1.x(); 00311 00312 path.cubicTo(p1.x() + distance / 2, p1.y(), 00313 p1.x() + distance / 2, p2.y(), 00314 p2.x(), p2.y()); 00315 } 00316 p.drawPath(path); 00317 } else { 00318 p.drawPolyline(m_points); 00319 } 00320 } 00321 00322 p.setPen(m_pointPen); 00323 p.setBrush(m_pointBrush); 00324 00325 for (int i=0; i<m_points.size(); ++i) { 00326 QRectF bounds = pointBoundingRect(i); 00327 if(i == m_currentColorIndex) 00328 p.setPen(m_selectedPointPen); 00329 00330 if (m_shape == CircleShape) 00331 p.drawEllipse(bounds); 00332 else 00333 p.drawRect(bounds); 00334 00335 if(i == m_currentColorIndex) 00336 p.setPen(m_pointPen); 00337 } 00338 } 00339 00340 static QPointF bound_point(const QPointF &point, const QRectF &bounds, int lock) 00341 { 00342 QPointF p = point; 00343 00344 qreal left = bounds.left(); 00345 qreal right = bounds.right(); 00346 qreal top = bounds.top(); 00347 qreal bottom = bounds.bottom(); 00348 00349 if (p.x() < left || (lock & HoverPoints::LockToLeft)) p.setX(left); 00350 else if (p.x() > right || (lock & HoverPoints::LockToRight)) p.setX(right); 00351 00352 if (p.y() < top || (lock & HoverPoints::LockToTop)) p.setY(top); 00353 else if (p.y() > bottom || (lock & HoverPoints::LockToBottom)) p.setY(bottom); 00354 00355 return p; 00356 } 00357 00358 void HoverPoints::setPoints(const QPolygonF &points, const QVector<QColor> &colors) 00359 { 00360 if (points.size() != m_points.size()) 00361 m_fingerPointMapping.clear(); 00362 m_points.clear(); 00363 m_colors.clear(); 00364 for (int i=0; i<points.size(); ++i){ 00365 m_points << bound_point(points.at(i), boundingRect(), 0); 00366 QPointF p = m_points[i]; 00367 m_colors << colors.at(i); 00368 } 00369 m_locks.clear(); 00370 if (m_points.size() > 0) { 00371 m_locks.resize(m_points.size()); 00372 00373 m_locks.fill(0); 00374 } 00375 } 00376 00377 00378 void HoverPoints::movePoint(int index, const QPointF &point, bool emitUpdate) 00379 { 00380 m_points[index] = bound_point(point, boundingRect(), m_locks.at(index)); 00381 QPointF p = m_points[index]; 00382 if (emitUpdate) 00383 firePointChange(); 00384 } 00385 00386 00387 inline static bool x_less_than(const QPointF &p1, const QPointF &p2) 00388 { 00389 return p1.x() < p2.x(); 00390 } 00391 00392 00393 inline static bool y_less_than(const QPointF &p1, const QPointF &p2) 00394 { 00395 return p1.y() < p2.y(); 00396 } 00397 00398 void HoverPoints::firePointChange() 00399 { 00400 // printf("HoverPoints::firePointChange(), current=%d\n", m_currentIndex); 00401 00402 if (m_sortType != NoSort) { 00403 00404 QPointF oldCurrent; 00405 if (m_currentIndex != -1) { 00406 oldCurrent = m_points[m_currentIndex]; 00407 } 00408 00409 if (m_sortType == XSort) 00410 qSort(m_points.begin(), m_points.end(), x_less_than); 00411 else if (m_sortType == YSort) 00412 qSort(m_points.begin(), m_points.end(), y_less_than); 00413 00414 // Compensate for changed order... 00415 if (m_currentIndex != -1) { 00416 for (int i=0; i<m_points.size(); ++i) { 00417 if (m_points[i] == oldCurrent) { 00418 m_currentIndex = i; 00419 break; 00420 } 00421 } 00422 } 00423 00424 // printf(" - firePointChange(), current=%d\n", m_currentIndex); 00425 00426 } 00427 00428 // for (int i=0; i<m_points.size(); ++i) { 00429 // printf(" - point(%2d)=[%.2f, %.2f], lock=%d\n", 00430 // i, m_points.at(i).x(), m_points.at(i).y(), m_locks.at(i)); 00431 // } 00432 00433 emit pointsChanged(m_points); 00434 }