00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <qapplication.h>
00011 #include <qevent.h>
00012 #include <qpainter.h>
00013 #include <qframe.h>
00014 #include <qcursor.h>
00015 #include "qwt_text.h"
00016 #include "qwt_painter.h"
00017 #include "qwt_picker_machine.h"
00018 #include "qwt_picker.h"
00019
00030 QwtPicker::QwtPicker(QWidget *parent, const char *name):
00031 QObject(parent, name)
00032 {
00033 init(parent, NoSelection, NoRubberBand, AlwaysOff);
00034 }
00035
00046 QwtPicker::QwtPicker(int selectionFlags, RubberBand rubberBand,
00047 DisplayMode cursorLabelMode, QWidget *parent, const char *name):
00048 QObject(parent, name)
00049 {
00050 init(parent, selectionFlags, rubberBand, cursorLabelMode);
00051 }
00052
00054 QwtPicker::~QwtPicker()
00055 {
00056 setMouseTracking(FALSE);
00057 delete d_stateMachine;
00058 }
00059
00061 void QwtPicker::init(QWidget *parent, int selectionFlags,
00062 RubberBand rubberBand, DisplayMode cursorLabelMode)
00063 {
00064 d_rubberBand = rubberBand;
00065 d_enabled = FALSE;
00066 d_resizeMode = Stretch;
00067 d_cursorLabelMode = AlwaysOff;
00068 d_isActive = FALSE;
00069 d_labelPosition = QPoint(-1, -1);
00070 d_mouseTracking = FALSE;
00071
00072 d_stateMachine = NULL;
00073 setSelectionFlags(selectionFlags);
00074
00075 if ( parent )
00076 {
00077 if ( parent->focusPolicy() == QWidget::NoFocus )
00078 parent->setFocusPolicy(QWidget::WheelFocus);
00079
00080 d_cursorLabelFont = parent->font();
00081 d_mouseTracking = parent->hasMouseTracking();
00082 setEnabled(TRUE);
00083 }
00084 setCursorLabelMode(cursorLabelMode);
00085 }
00086
00090 void QwtPicker::setStateMachine(QwtPickerMachine *stateMachine)
00091 {
00092 if ( d_stateMachine != stateMachine )
00093 {
00094 if ( isActive() )
00095 end(FALSE);
00096
00097 delete d_stateMachine;
00098 d_stateMachine = stateMachine;
00099
00100 if ( d_stateMachine )
00101 d_stateMachine->reset();
00102 }
00103 }
00104
00121 QwtPickerMachine *QwtPicker::stateMachine(int flags) const
00122 {
00123 if ( flags & PointSelection )
00124 {
00125 if ( flags & ClickSelection )
00126 return new QwtPickerClickPointMachine;
00127 else
00128 return new QwtPickerDragPointMachine;
00129 }
00130 if ( flags & RectSelection )
00131 {
00132 if ( flags & ClickSelection )
00133 return new QwtPickerClickRectMachine;
00134 else
00135 return new QwtPickerDragRectMachine;
00136 }
00137 if ( flags & PolygonSelection )
00138 {
00139 return new QwtPickerPolygonMachine();
00140 }
00141 return NULL;
00142 }
00143
00145 QWidget *QwtPicker::parentWidget()
00146 {
00147 QObject *obj = parent();
00148 if ( obj && obj->isWidgetType() )
00149 return (QWidget *)obj;
00150
00151 return NULL;
00152 }
00153
00155 const QWidget *QwtPicker::parentWidget() const
00156 {
00157 QObject *obj = parent();
00158 if ( obj && obj->isWidgetType() )
00159 return (QWidget *)obj;
00160
00161 return NULL;
00162 }
00163
00173 void QwtPicker::setSelectionFlags(int flags)
00174 {
00175 d_selectionFlags = flags;
00176 setStateMachine(stateMachine(flags));
00177 }
00178
00184 int QwtPicker::selectionFlags() const
00185 {
00186 return d_selectionFlags;
00187 }
00188
00197 void QwtPicker::setRubberBand(RubberBand rubberBand)
00198 {
00199 d_rubberBand = rubberBand;
00200 }
00201
00206 QwtPicker::RubberBand QwtPicker::rubberBand() const
00207 {
00208 return d_rubberBand;
00209 }
00210
00227 void QwtPicker::setCursorLabelMode(DisplayMode mode)
00228 {
00229 if ( d_cursorLabelMode != mode )
00230 {
00231 d_cursorLabelMode = mode;
00232 setMouseTracking(d_cursorLabelMode == AlwaysOn);
00233 }
00234 }
00235
00240 QwtPicker::DisplayMode QwtPicker::cursorLabelMode() const
00241 {
00242 return d_cursorLabelMode;
00243 }
00244
00259 void QwtPicker::setResizeMode(ResizeMode mode)
00260 {
00261 d_resizeMode = mode;
00262 }
00263
00269 QwtPicker::ResizeMode QwtPicker::resizeMode() const
00270 {
00271 return d_resizeMode;
00272 }
00273
00283 void QwtPicker::setEnabled(bool enabled)
00284 {
00285 if ( d_enabled != enabled )
00286 {
00287 QWidget *w = parentWidget();
00288 if ( !w )
00289 return;
00290
00291 d_enabled = enabled;
00292 drawCursorLabel();
00293
00294 if ( d_enabled )
00295 w->installEventFilter(this);
00296 else
00297 w->removeEventFilter(this);
00298 }
00299 }
00300
00306 bool QwtPicker::isEnabled() const
00307 {
00308 return d_enabled;
00309 }
00310
00317 void QwtPicker::setCursorLabelFont(const QFont &font)
00318 {
00319 if ( font != d_cursorLabelFont )
00320 {
00321 if ( isEnabled() )
00322 drawCursorLabel();
00323
00324 d_cursorLabelFont = font;
00325
00326 if ( isEnabled() )
00327 drawCursorLabel();
00328 }
00329 }
00330
00336 QFont QwtPicker::cursorLabelFont() const
00337 {
00338 return d_cursorLabelFont;
00339 }
00340
00347 void QwtPicker::setCursorLabelPen(const QPen &pen)
00348 {
00349 if ( pen != d_cursorLabelPen )
00350 {
00351 if ( isEnabled() )
00352 drawCursorLabel();
00353
00354 d_cursorLabelPen = pen;
00355
00356 if ( isEnabled() )
00357 drawCursorLabel();
00358 }
00359 }
00360
00365 QPen QwtPicker::cursorLabelPen() const
00366 {
00367 return d_cursorLabelPen;
00368 }
00369
00376 void QwtPicker::setRubberBandPen(const QPen &pen)
00377 {
00378 if ( pen != d_rubberBandPen )
00379 {
00380 drawRubberBand();
00381 d_rubberBandPen = pen;
00382 drawRubberBand();
00383 }
00384 }
00385
00390 QPen QwtPicker::rubberBandPen() const
00391 {
00392 return d_rubberBandPen;
00393 }
00394
00408 QString QwtPicker::cursorLabel(const QPoint &pos) const
00409 {
00410 QString label;
00411
00412 switch(rubberBand())
00413 {
00414 case HLineRubberBand:
00415 label.sprintf("%d", pos.y());
00416 break;
00417 case VLineRubberBand:
00418 label.sprintf("%d", pos.x());
00419 break;
00420 default:
00421 label.sprintf("%d, %d", pos.x(), pos.y());
00422 }
00423 return label;
00424 }
00425
00437 void QwtPicker::drawRubberBand(const QRect &clipRect) const
00438 {
00439 QWidget *widget = (QWidget *)parentWidget();
00440 if ( !widget || !isActive() || rubberBand() == NoRubberBand ||
00441 rubberBandPen().style() == Qt::NoPen )
00442 {
00443 return;
00444 }
00445
00446 const QColor bg = widget->backgroundColor();
00447
00448 QPainter painter(widget);
00449 painter.setClipRect(clipRect.isValid() ? clipRect : pickRect());
00450 painter.setClipping(TRUE);
00451 painter.setRasterOp(XorROP);
00452
00453 QPen pen = d_rubberBandPen;
00454 pen.setColor(QColor(bg.rgb() ^ pen.color().rgb()));
00455 painter.setPen(pen);
00456
00457 drawRubberBand(&painter, pickRect(), d_selection);
00458 }
00459
00472 void QwtPicker::drawRubberBand(QPainter *painter,
00473 const QRect &pickRect, const QPointArray &pa) const
00474 {
00475 if ( rubberBand() == NoRubberBand )
00476 return;
00477
00478 if ( selectionFlags() & PointSelection )
00479 {
00480 if ( pa.count() < 1 )
00481 return;
00482
00483 const QPoint pos = pa[0];
00484
00485 switch(rubberBand())
00486 {
00487 case VLineRubberBand:
00488 QwtPainter::drawLine(painter, pos.x(),
00489 pickRect.top(), pos.x(), pickRect.bottom());
00490 break;
00491
00492 case HLineRubberBand:
00493 QwtPainter::drawLine(painter, pickRect.left(),
00494 pos.y(), pickRect.right(), pos.y());
00495 break;
00496
00497 case CrossRubberBand:
00498 QwtPainter::drawLine(painter, pos.x(),
00499 pickRect.top(), pos.x(), pickRect.bottom());
00500 QwtPainter::drawLine(painter, pickRect.left(),
00501 pos.y(), pickRect.right(), pos.y());
00502 break;
00503 default:
00504 break;
00505 }
00506 }
00507
00508 else if ( selectionFlags() & RectSelection )
00509 {
00510 if ( pa.count() < 2 )
00511 return;
00512
00513 QPoint p1 = pa[0];
00514 QPoint p2 = pa[int(pa.count() - 1)];
00515
00516 if ( selectionFlags() & CenterToCorner )
00517 {
00518 p1.setX(p1.x() - (p2.x() - p1.x()));
00519 p1.setY(p1.y() - (p2.y() - p1.y()));
00520 }
00521 else if ( selectionFlags() & CenterToRadius )
00522 {
00523 const int radius = QMAX(QABS(p2.x() - p1.x()),
00524 QABS(p2.y() - p1.y()));
00525 p2.setX(p1.x() + radius);
00526 p2.setY(p1.y() + radius);
00527 p1.setX(p1.x() - radius);
00528 p1.setY(p1.y() - radius);
00529 }
00530
00531 const QRect rect = QRect(p1, p2).normalize();
00532 switch(rubberBand())
00533 {
00534 case EllipseRubberBand:
00535 QwtPainter::drawEllipse(painter, rect);
00536 break;
00537
00538 case RectRubberBand:
00539 {
00540
00541
00542
00543 if ( rect.height() <= 1 )
00544 {
00545 QwtPainter::drawLine(painter,
00546 rect.topLeft(), rect.topRight());
00547 }
00548 else if ( rect.width() <= 1 )
00549 {
00550 QwtPainter::drawLine(painter,
00551 rect.topLeft(), rect.bottomLeft());
00552 }
00553 else
00554 QwtPainter::drawRect(painter, rect);
00555 break;
00556 }
00557 default:
00558 break;
00559 }
00560 }
00561 else if ( selectionFlags() & PolygonSelection )
00562 {
00563 if ( rubberBand() == PolygonRubberBand )
00564 painter->drawPolyline(pa);
00565 }
00566 }
00567
00580 void QwtPicker::drawCursorLabel(const QRect &clipRect) const
00581 {
00582 QWidget *widget = (QWidget *)QwtPicker::parentWidget();
00583 if ( !widget )
00584 return;
00585
00586 if ( cursorLabelMode() == AlwaysOff ||
00587 (cursorLabelMode() == ActiveOnly && !isActive() ) )
00588 {
00589 return;
00590 }
00591
00592 if ( d_labelPosition.x() < 0 || d_labelPosition.y() < 0 )
00593 return;
00594
00595 const QColor bg = widget->backgroundColor();
00596
00597 QPainter painter(widget);
00598 painter.setClipRect(clipRect.isValid() ? clipRect : pickRect());
00599 painter.setClipping(TRUE);
00600 painter.setRasterOp(XorROP);
00601
00602 QPen pen = d_cursorLabelPen;
00603 pen.setColor(QColor((bg.rgb() ^ pen.color().rgb())));
00604
00605 painter.setPen(pen);
00606 painter.setFont(d_cursorLabelFont);
00607
00608 drawCursorLabel(&painter, pickRect(), d_labelPosition, d_selection);
00609 }
00610
00627 void QwtPicker::drawCursorLabel(QPainter *painter, const QRect &pickRect,
00628 const QPoint &pos, const QPointArray &pa) const
00629 {
00630 int alignment = 0;
00631 if ( isActive() && pa.count() > 1 && rubberBand() != NoRubberBand )
00632 {
00633 const QPoint last = pa[int(pa.count()) - 2];
00634
00635 alignment |= (pos.x() >= last.x()) ? Qt::AlignRight : Qt::AlignLeft;
00636 alignment |= (pos.y() > last.y()) ? Qt::AlignBottom : Qt::AlignTop;
00637 }
00638 else
00639 alignment = Qt::AlignTop | Qt::AlignRight;
00640
00641 QString label = cursorLabel(pos);
00642 if ( !label.isEmpty() )
00643 {
00644 QwtText *text = QwtText::makeText(label, 0, painter->font(),
00645 painter->pen().color());
00646
00647 QRect textRect = text->boundingRect(painter);
00648
00649 const int margin = 5;
00650
00651 int x = pos.x();
00652 if ( alignment & Qt::AlignLeft )
00653 x -= textRect.width() + margin;
00654 else if ( alignment & Qt::AlignRight )
00655 x += margin;
00656
00657 int y = pos.y();
00658 if ( alignment & Qt::AlignBottom )
00659 y += margin;
00660 else if ( alignment & Qt::AlignTop )
00661 y -= textRect.height() + margin;
00662
00663 textRect.moveTopLeft(QPoint(x, y));
00664
00665 int right = QMIN(textRect.right(), pickRect.right() - margin);
00666 int bottom = QMIN(textRect.bottom(), pickRect.bottom() - margin);
00667 textRect.moveBottomRight(QPoint(right, bottom));
00668
00669 int left = QMAX(textRect.left(), pickRect.left() + margin);
00670 int top = QMAX(textRect.top(), pickRect.top() + margin);
00671 textRect.moveTopLeft(QPoint(left, top));
00672
00673 text->draw(painter, textRect);
00674
00675 delete text;
00676 }
00677 }
00678
00687 void QwtPicker::repaint(const QRect &rect)
00688 {
00689 QApplication::postEvent(this, new QPaintEvent(rect));
00690 }
00691
00702 bool QwtPicker::event(QEvent *e)
00703 {
00704 if ( e->type() == QEvent::Paint )
00705 {
00706 const QRect clipRect = ((const QPaintEvent *)e)->rect();
00707
00708 drawRubberBand(clipRect);
00709 drawCursorLabel(clipRect);
00710 return TRUE;
00711 }
00712
00713 return QObject::event(e);
00714 }
00715
00728 bool QwtPicker::eventFilter(QObject *o, QEvent *e)
00729 {
00730
00731
00732
00733
00734
00735
00736
00737 QApplication::sendPostedEvents(this, QEvent::Paint);
00738
00739 if ( o && o == parentWidget() )
00740 {
00741 switch(e->type())
00742 {
00743 case QEvent::Paint:
00744 {
00745
00746
00747
00748
00749 const QPaintEvent *re = (QPaintEvent *)e;
00750 repaint(re->rect());
00751 break;
00752 }
00753 case QEvent::Resize:
00754 {
00755 if ( d_resizeMode == Stretch )
00756 {
00757
00758 drawRubberBand();
00759 drawCursorLabel();
00760
00761 const QResizeEvent *re = (QResizeEvent *)e;
00762 stretchSelection(re->oldSize(), re->size());
00763
00764
00765 drawRubberBand();
00766 drawCursorLabel();
00767 }
00768 break;
00769 }
00770 case QEvent::MouseButtonPress:
00771 widgetMousePressEvent((QMouseEvent *)e);
00772 break;
00773 case QEvent::MouseButtonRelease:
00774 widgetMouseReleaseEvent((QMouseEvent *)e);
00775 break;
00776 case QEvent::MouseButtonDblClick:
00777 widgetMouseDoubleClickEvent((QMouseEvent *)e);
00778 break;
00779 case QEvent::MouseMove:
00780 widgetMouseMoveEvent((QMouseEvent *)e);
00781 break;
00782 case QEvent::KeyPress:
00783 widgetKeyPressEvent((QKeyEvent *)e);
00784 break;
00785 case QEvent::KeyRelease:
00786 widgetKeyReleaseEvent((QKeyEvent *)e);
00787 break;
00788 case QEvent::Wheel:
00789 widgetWheelEvent((QWheelEvent *)e);
00790 break;
00791 default:
00792 break;
00793 }
00794 }
00795 return FALSE;
00796 }
00797
00808 void QwtPicker::widgetMousePressEvent(QMouseEvent *e)
00809 {
00810 transition(e);
00811 }
00812
00822 void QwtPicker::widgetMouseMoveEvent(QMouseEvent *e)
00823 {
00824 drawCursorLabel();
00825
00826 if ( pickRect().contains(e->pos()) )
00827 {
00828 d_labelPosition = e->pos();
00829 drawCursorLabel();
00830 }
00831 else
00832 d_labelPosition = QPoint(-1, -1);
00833
00834 transition(e);
00835 }
00836
00847 void QwtPicker::widgetMouseReleaseEvent(QMouseEvent *e)
00848 {
00849 transition(e);
00850 }
00851
00861 void QwtPicker::widgetMouseDoubleClickEvent(QMouseEvent *me)
00862 {
00863 transition(me);
00864 }
00865
00866
00876 void QwtPicker::widgetWheelEvent(QWheelEvent *e)
00877 {
00878 drawCursorLabel();
00879
00880 if ( pickRect().contains(e->pos()) )
00881 {
00882 d_labelPosition = e->pos();
00883 drawCursorLabel();
00884 }
00885 else
00886 d_labelPosition = QPoint(-1, -1);
00887
00888 transition(e);
00889 }
00890
00904 void QwtPicker::widgetKeyPressEvent(QKeyEvent *ke)
00905 {
00906 int dx = 0;
00907 int dy = 0;
00908
00909 int offset = 1;
00910 if ( ke->isAutoRepeat() )
00911 offset = 5;
00912
00913 if ( keyMatch(KeyLeft, ke) )
00914 dx = -offset;
00915 else if ( keyMatch(KeyRight, ke) )
00916 dx = offset;
00917 else if ( keyMatch(KeyUp, ke) )
00918 dy = -offset;
00919 else if ( keyMatch(KeyDown, ke) )
00920 dy = offset;
00921 else if ( keyMatch(KeyAbort, ke) )
00922 {
00923 if ( d_stateMachine )
00924 d_stateMachine->reset();
00925
00926 if (isActive())
00927 end(FALSE);
00928 }
00929 else
00930 transition(ke);
00931
00932 if ( dx != 0 || dy != 0 )
00933 {
00934 const QRect rect = pickRect();
00935 const QPoint pos = parentWidget()->mapFromGlobal(QCursor::pos());
00936
00937 int x = pos.x() + dx;
00938 x = QMAX(rect.left(), x);
00939 x = QMIN(rect.right(), x);
00940
00941 int y = pos.y() + dy;
00942 y = QMAX(rect.top(), y);
00943 y = QMIN(rect.bottom(), y);
00944
00945 QCursor::setPos(parentWidget()->mapToGlobal(QPoint(x, y)));
00946 }
00947 }
00948
00958 void QwtPicker::widgetKeyReleaseEvent(QKeyEvent *ke)
00959 {
00960 transition(ke);
00961 }
00962
00970 void QwtPicker::transition(const QEvent *e)
00971 {
00972 if ( !d_stateMachine )
00973 return;
00974
00975 QValueList<QwtPickerMachine::Command> commandList =
00976 d_stateMachine->transition(*this, e);
00977
00978 const QPoint pos = parentWidget()->mapFromGlobal(QCursor::pos());
00979
00980 for ( uint i = 0; i < commandList.count(); i++ )
00981 {
00982 switch(commandList[i])
00983 {
00984 case QwtPickerMachine::Begin:
00985 {
00986 begin();
00987 break;
00988 }
00989 case QwtPickerMachine::Append:
00990 {
00991 append(pos);
00992 break;
00993 }
00994 case QwtPickerMachine::Move:
00995 {
00996 move(pos);
00997 break;
00998 }
00999 case QwtPickerMachine::End:
01000 {
01001 end();
01002 break;
01003 }
01004 }
01005 }
01006 }
01007
01013 void QwtPicker::begin()
01014 {
01015 drawCursorLabel();
01016
01017 d_selection.resize(0);
01018 d_isActive = TRUE;
01019
01020 if ( cursorLabelMode() != AlwaysOff )
01021 {
01022 if ( d_labelPosition.x() < 0 || d_labelPosition.y() < 0 )
01023 {
01024 QWidget *w = parentWidget();
01025 if ( w )
01026 d_labelPosition = w->mapFromGlobal(QCursor::pos());
01027 }
01028 }
01029
01030 drawCursorLabel();
01031 setMouseTracking(TRUE);
01032 }
01033
01044 bool QwtPicker::end(bool ok)
01045 {
01046 if ( d_isActive )
01047 {
01048 setMouseTracking(FALSE);
01049
01050 drawCursorLabel();
01051 drawRubberBand();
01052
01053 d_isActive = FALSE;
01054
01055 drawCursorLabel();
01056
01057 if ( cursorLabelMode() == ActiveOnly )
01058 d_labelPosition = QPoint(-1, -1);
01059
01060 if ( ok )
01061 ok = accept(d_selection);
01062
01063 if ( ok )
01064 emit selected(d_selection);
01065 else
01066 d_selection.resize(0);
01067 }
01068 else
01069 ok = FALSE;
01070
01071 return ok;
01072 }
01073
01082 void QwtPicker::append(const QPoint &pos)
01083 {
01084 if ( d_isActive )
01085 {
01086 drawRubberBand();
01087 drawCursorLabel();
01088
01089 const int idx = d_selection.count();
01090 d_selection.resize(idx + 1);
01091 d_selection[idx] = pos;
01092
01093 drawRubberBand();
01094 drawCursorLabel();
01095
01096 emit appended(pos);
01097 }
01098 }
01099
01108 void QwtPicker::move(const QPoint &pos)
01109 {
01110 if ( d_isActive )
01111 {
01112 const int idx = d_selection.count() - 1;
01113 if ( idx >= 0 )
01114 {
01115 drawRubberBand();
01116 d_selection[idx] = pos;
01117 drawRubberBand();
01118
01119 emit moved(pos);
01120 }
01121 }
01122 }
01123
01124 bool QwtPicker::accept(QPointArray &) const
01125 {
01126 return TRUE;
01127 }
01128
01133 bool QwtPicker::isActive() const
01134 {
01135 return d_isActive;
01136 }
01137
01139 const QPointArray &QwtPicker::selection() const
01140 {
01141 return d_selection;
01142 }
01143
01153 void QwtPicker::stretchSelection(const QSize &oldSize, const QSize &newSize)
01154 {
01155 const double xRatio =
01156 double(newSize.width()) / double(oldSize.width());
01157 const double yRatio =
01158 double(newSize.height()) / double(oldSize.height());
01159
01160 for ( int i = 0; i < int(d_selection.count()); i++ )
01161 {
01162 QPoint &p = d_selection[i];
01163 p.setX(qRound(p.x() * xRatio));
01164 p.setY(qRound(p.y() * yRatio));
01165
01166 emit changed(d_selection);
01167 }
01168 }
01169
01183 void QwtPicker::setMouseTracking(bool enable)
01184 {
01185 QWidget *widget = parentWidget();
01186 if ( !widget )
01187 return;
01188
01189 if ( enable )
01190 {
01191 d_mouseTracking = widget->hasMouseTracking();
01192 widget->setMouseTracking(TRUE);
01193 }
01194 else
01195 {
01196 widget->setMouseTracking(d_mouseTracking);
01197 }
01198 }
01199
01205 QRect QwtPicker::pickRect() const
01206 {
01207 QRect rect;
01208
01209 const QWidget *widget = parentWidget();
01210 if ( !widget )
01211 return rect;
01212
01213 if ( widget->inherits("QFrame") )
01214 rect = ((QFrame *)widget)->contentsRect();
01215 else
01216 rect = widget->rect();
01217
01218 return rect;
01219 }
01220
01221
01222
01223
01224
01225