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