00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 #ifdef QT_OPENGL_SUPPORT
00045 #include <QGLWidget>
00046 #endif
00047
00048 #include "arthurwidgets.h"
00049 #include "hoverpoints.h"
00050
00051 #define printf
00052
00053 HoverPoints::HoverPoints(QWidget *widget, PointShape shape)
00054 : QObject(widget)
00055 {
00056 m_widget = widget;
00057 widget->installEventFilter(this);
00058
00059 m_connectionType = CurveConnection;
00060 m_sortType = NoSort;
00061 m_shape = shape;
00062 m_pointPen = QPen(QColor(255, 255, 255, 191), 1);
00063 m_connectionPen = QPen(QColor(255, 255, 255, 127), 2);
00064 m_pointBrush = QBrush(QColor(191, 191, 191, 127));
00065 m_pointSize = QSize(11, 11);
00066 m_currentIndex = -1;
00067 m_editable = true;
00068 m_enabled = true;
00069
00070 connect(this, SIGNAL(pointsChanged(const QPolygonF &)),
00071 m_widget, SLOT(update()));
00072 }
00073
00074
00075 void HoverPoints::setEnabled(bool enabled)
00076 {
00077 if (m_enabled != enabled) {
00078 m_enabled = enabled;
00079 m_widget->update();
00080 }
00081 }
00082
00083
00084 bool HoverPoints::eventFilter(QObject *object, QEvent *event)
00085 {
00086 if (object == m_widget && m_enabled) {
00087 switch (event->type()) {
00088
00089 case QEvent::MouseButtonPress:
00090 {
00091 QMouseEvent *me = (QMouseEvent *) event;
00092
00093 QPointF clickPos = me->pos();
00094 int index = -1;
00095 for (int i=0; i<m_points.size(); ++i) {
00096 QPainterPath path;
00097 if (m_shape == CircleShape)
00098 path.addEllipse(pointBoundingRect(i));
00099 else
00100 path.addRect(pointBoundingRect(i));
00101
00102 if (path.contains(clickPos)) {
00103 index = i;
00104 break;
00105 }
00106 }
00107
00108 if (me->button() == Qt::LeftButton) {
00109 if (index == -1) {
00110 if (!m_editable)
00111 return false;
00112 int pos = 0;
00113
00114 if (m_sortType == XSort) {
00115 for (int i=0; i<m_points.size(); ++i)
00116 if (m_points.at(i).x() > clickPos.x()) {
00117 pos = i;
00118 break;
00119 }
00120 } else if (m_sortType == YSort) {
00121 for (int i=0; i<m_points.size(); ++i)
00122 if (m_points.at(i).y() > clickPos.y()) {
00123 pos = i;
00124 break;
00125 }
00126 }
00127
00128 m_points.insert(pos, clickPos);
00129 m_locks.insert(pos, 0);
00130 m_currentIndex = pos;
00131 firePointChange();
00132 } else {
00133 m_currentIndex = index;
00134 }
00135 return true;
00136
00137 } else if (me->button() == Qt::RightButton) {
00138 if (index >= 0 && m_editable) {
00139 if (m_locks[index] == 0) {
00140 m_locks.remove(index);
00141 m_points.remove(index);
00142 }
00143 firePointChange();
00144 return true;
00145 }
00146 }
00147
00148 }
00149 break;
00150
00151 case QEvent::MouseButtonRelease:
00152 m_currentIndex = -1;
00153 break;
00154
00155 case QEvent::MouseMove:
00156 if (m_currentIndex >= 0)
00157 movePoint(m_currentIndex, ((QMouseEvent *)event)->pos());
00158 break;
00159
00160 case QEvent::Resize:
00161 {
00162 QResizeEvent *e = (QResizeEvent *) event;
00163 if (e->oldSize().width() == 0 || e->oldSize().height() == 0)
00164 break;
00165 double stretch_x = e->size().width() / double(e->oldSize().width());
00166 double stretch_y = e->size().height() / double(e->oldSize().height());
00167 for (int i=0; i<m_points.size(); ++i) {
00168 QPointF p = m_points[i];
00169 movePoint(i, QPointF(p.x() * stretch_x, p.y() * stretch_y), false);
00170 }
00171
00172 firePointChange();
00173 break;
00174 }
00175
00176 case QEvent::Paint:
00177 {
00178 QWidget *that_widget = m_widget;
00179 m_widget = 0;
00180 QApplication::sendEvent(object, event);
00181 m_widget = that_widget;
00182 paintPoints();
00183 #ifdef QT_OPENGL_SUPPORT
00184 ArthurFrame *af = qobject_cast<ArthurFrame *>(that_widget);
00185 if (af && af->usesOpenGL())
00186 af->glWidget()->swapBuffers();
00187 #endif
00188 return true;
00189 }
00190 default:
00191 break;
00192 }
00193 }
00194
00195 return false;
00196 }
00197
00198
00199 void HoverPoints::paintPoints()
00200 {
00201 QPainter p;
00202 #ifdef QT_OPENGL_SUPPORT
00203 ArthurFrame *af = qobject_cast<ArthurFrame *>(m_widget);
00204 if (af && af->usesOpenGL())
00205 p.begin(af->glWidget());
00206 else
00207 p.begin(m_widget);
00208 #else
00209 p.begin(m_widget);
00210 #endif
00211
00212 p.setRenderHint(QPainter::Antialiasing);
00213
00214 if (m_connectionPen.style() != Qt::NoPen && m_connectionType != NoConnection) {
00215 p.setPen(m_connectionPen);
00216
00217 if (m_connectionType == CurveConnection) {
00218 QPainterPath path;
00219 path.moveTo(m_points.at(0));
00220 for (int i=1; i<m_points.size(); ++i) {
00221 QPointF p1 = m_points.at(i-1);
00222 QPointF p2 = m_points.at(i);
00223 double distance = p2.x() - p1.x();
00224
00225 path.cubicTo(p1.x() + distance / 2, p1.y(),
00226 p1.x() + distance / 2, p2.y(),
00227 p2.x(), p2.y());
00228 }
00229 p.drawPath(path);
00230 } else {
00231 p.drawPolyline(m_points);
00232 }
00233 }
00234
00235 p.setPen(m_pointPen);
00236 p.setBrush(m_pointBrush);
00237
00238 for (int i=0; i<m_points.size(); ++i) {
00239 QRectF bounds = pointBoundingRect(i);
00240 if (m_shape == CircleShape)
00241 p.drawEllipse(bounds);
00242 else
00243 p.drawRect(bounds);
00244 }
00245 }
00246
00247 static QPointF bound_point(const QPointF &point, const QRectF &bounds, int lock)
00248 {
00249 QPointF p = point;
00250
00251 double left = bounds.left();
00252 double right = bounds.right();
00253 double top = bounds.top();
00254 double bottom = bounds.bottom();
00255
00256 if (p.x() < left || (lock & HoverPoints::LockToLeft)) p.setX(left);
00257 else if (p.x() > right || (lock & HoverPoints::LockToRight)) p.setX(right);
00258
00259 if (p.y() < top || (lock & HoverPoints::LockToTop)) p.setY(top);
00260 else if (p.y() > bottom || (lock & HoverPoints::LockToBottom)) p.setY(bottom);
00261
00262 return p;
00263 }
00264
00265 void HoverPoints::setPoints(const QPolygonF &points)
00266 {
00267 m_points.clear();
00268 for (int i=0; i<points.size(); ++i)
00269 m_points << bound_point(points.at(i), boundingRect(), 0);
00270
00271 m_locks.clear();
00272 if (m_points.size() > 0) {
00273 m_locks.resize(m_points.size());
00274
00275 m_locks.fill(0);
00276 }
00277 }
00278
00279
00280 void HoverPoints::movePoint(int index, const QPointF &point, bool emitUpdate)
00281 {
00282 m_points[index] = bound_point(point, boundingRect(), m_locks.at(index));
00283 if (emitUpdate)
00284 firePointChange();
00285 }
00286
00287
00288 inline static bool x_less_than(const QPointF &p1, const QPointF &p2)
00289 {
00290 return p1.x() < p2.x();
00291 }
00292
00293
00294 inline static bool y_less_than(const QPointF &p1, const QPointF &p2)
00295 {
00296 return p1.y() < p2.y();
00297 }
00298
00299 void HoverPoints::firePointChange()
00300 {
00301
00302
00303 if (m_sortType != NoSort) {
00304
00305 QPointF oldCurrent;
00306 if (m_currentIndex != -1) {
00307 oldCurrent = m_points[m_currentIndex];
00308 }
00309
00310 if (m_sortType == XSort)
00311 qSort(m_points.begin(), m_points.end(), x_less_than);
00312 else if (m_sortType == YSort)
00313 qSort(m_points.begin(), m_points.end(), y_less_than);
00314
00315
00316 if (m_currentIndex != -1) {
00317 for (int i=0; i<m_points.size(); ++i) {
00318 if (m_points[i] == oldCurrent) {
00319 m_currentIndex = i;
00320 break;
00321 }
00322 }
00323 }
00324
00325
00326
00327 }
00328
00329
00330
00331
00332
00333
00334 emit pointsChanged(m_points);
00335 }