1 #include <qevent.h>
2 #include <qwt_plot_canvas.h>
3 #include <qwt_plot_layout.h>
4 #include <qwt_scale_engine.h>
5 #include <qwt_scale_widget.h>
6 #include "scrollbar.h"
7 #include "scrollzoomer.h"
8
9 class ScrollData
10 {
11 public:
ScrollData()12 ScrollData():
13 scrollBar(NULL),
14 position(ScrollZoomer::OppositeToScale),
15 #if QT_VERSION < 0x040000
16 mode(QScrollView::Auto)
17 #else
18 mode(Qt::ScrollBarAsNeeded)
19 #endif
20 {
21 }
22
~ScrollData()23 ~ScrollData()
24 {
25 delete scrollBar;
26 }
27
28 ScrollBar *scrollBar;
29 ScrollZoomer::ScrollBarPosition position;
30 #if QT_VERSION < 0x040000
31 QScrollView::ScrollBarMode mode;
32 #else
33 Qt::ScrollBarPolicy mode;
34 #endif
35 };
36
ScrollZoomer(QwtPlotCanvas * canvas)37 ScrollZoomer::ScrollZoomer(QwtPlotCanvas *canvas):
38 QwtPlotZoomer(canvas),
39 d_cornerWidget(NULL),
40 d_hScrollData(NULL),
41 d_vScrollData(NULL),
42 d_inZoom(false),
43 d_alignCanvasToScales(false)
44 {
45 if ( !canvas )
46 return;
47
48 d_hScrollData = new ScrollData;
49 d_vScrollData = new ScrollData;
50 }
51
~ScrollZoomer()52 ScrollZoomer::~ScrollZoomer()
53 {
54 delete d_cornerWidget;
55 delete d_vScrollData;
56 delete d_hScrollData;
57 }
58
rescale()59 void ScrollZoomer::rescale()
60 {
61 QwtScaleWidget *xScale = plot()->axisWidget(xAxis());
62 QwtScaleWidget *yScale = plot()->axisWidget(yAxis());
63
64 if ( zoomRectIndex() <= 0 )
65 {
66 if ( d_inZoom )
67 {
68 xScale->setMinBorderDist(0, 0);
69 yScale->setMinBorderDist(0, 0);
70
71 QwtPlotLayout *layout = plot()->plotLayout();
72 layout->setAlignCanvasToScales(d_alignCanvasToScales);
73
74 d_inZoom = false;
75 }
76 }
77 else
78 {
79 if ( !d_inZoom )
80 {
81 /*
82 We set a minimum border distance.
83 Otherwise the canvas size changes when scrolling,
84 between situations where the major ticks are at
85 the canvas borders (requiring extra space for the label)
86 and situations where all labels can be painted below/top
87 or left/right of the canvas.
88 */
89 int start, end;
90
91 xScale->getBorderDistHint(start, end);
92 xScale->setMinBorderDist(start, end);
93
94 yScale->getBorderDistHint(start, end);
95 yScale->setMinBorderDist(start, end);
96
97 QwtPlotLayout *layout = plot()->plotLayout();
98 d_alignCanvasToScales = layout->alignCanvasToScales();
99 layout->setAlignCanvasToScales(false);
100
101 d_inZoom = true;
102 }
103 }
104
105 QwtPlotZoomer::rescale();
106 updateScrollBars();
107 }
108
scrollBar(Qt::Orientation o)109 ScrollBar *ScrollZoomer::scrollBar(Qt::Orientation o)
110 {
111 ScrollBar *&sb = (o == Qt::Vertical)
112 ? d_vScrollData->scrollBar : d_hScrollData->scrollBar;
113
114 if ( sb == NULL )
115 {
116 sb = new ScrollBar(o, canvas());
117 sb->hide();
118 connect(sb,
119 SIGNAL(valueChanged(Qt::Orientation, double, double)),
120 SLOT(scrollBarMoved(Qt::Orientation, double, double)));
121 }
122 return sb;
123 }
124
horizontalScrollBar() const125 ScrollBar *ScrollZoomer::horizontalScrollBar() const
126 {
127 return d_hScrollData->scrollBar;
128 }
129
verticalScrollBar() const130 ScrollBar *ScrollZoomer::verticalScrollBar() const
131 {
132 return d_vScrollData->scrollBar;
133 }
134
135 #if QT_VERSION < 0x040000
setHScrollBarMode(QScrollView::ScrollBarMode mode)136 void ScrollZoomer::setHScrollBarMode(QScrollView::ScrollBarMode mode)
137 #else
138 void ScrollZoomer::setHScrollBarMode(Qt::ScrollBarPolicy mode)
139 #endif
140 {
141 if ( hScrollBarMode() != mode )
142 {
143 d_hScrollData->mode = mode;
144 updateScrollBars();
145 }
146 }
147
148 #if QT_VERSION < 0x040000
setVScrollBarMode(QScrollView::ScrollBarMode mode)149 void ScrollZoomer::setVScrollBarMode(QScrollView::ScrollBarMode mode)
150 #else
151 void ScrollZoomer::setVScrollBarMode(Qt::ScrollBarPolicy mode)
152 #endif
153 {
154 if ( vScrollBarMode() != mode )
155 {
156 d_vScrollData->mode = mode;
157 updateScrollBars();
158 }
159 }
160
161 #if QT_VERSION < 0x040000
hScrollBarMode() const162 QScrollView::ScrollBarMode ScrollZoomer::hScrollBarMode() const
163 #else
164 Qt::ScrollBarPolicy ScrollZoomer::hScrollBarMode() const
165 #endif
166 {
167 return d_hScrollData->mode;
168 }
169
170 #if QT_VERSION < 0x040000
vScrollBarMode() const171 QScrollView::ScrollBarMode ScrollZoomer::vScrollBarMode() const
172 #else
173 Qt::ScrollBarPolicy ScrollZoomer::vScrollBarMode() const
174 #endif
175 {
176 return d_vScrollData->mode;
177 }
178
setHScrollBarPosition(ScrollBarPosition pos)179 void ScrollZoomer::setHScrollBarPosition(ScrollBarPosition pos)
180 {
181 if ( d_hScrollData->position != pos )
182 {
183 d_hScrollData->position = pos;
184 updateScrollBars();
185 }
186 }
187
setVScrollBarPosition(ScrollBarPosition pos)188 void ScrollZoomer::setVScrollBarPosition(ScrollBarPosition pos)
189 {
190 if ( d_vScrollData->position != pos )
191 {
192 d_vScrollData->position = pos;
193 updateScrollBars();
194 }
195 }
196
hScrollBarPosition() const197 ScrollZoomer::ScrollBarPosition ScrollZoomer::hScrollBarPosition() const
198 {
199 return d_hScrollData->position;
200 }
201
vScrollBarPosition() const202 ScrollZoomer::ScrollBarPosition ScrollZoomer::vScrollBarPosition() const
203 {
204 return d_vScrollData->position;
205 }
206
setCornerWidget(QWidget * w)207 void ScrollZoomer::setCornerWidget(QWidget *w)
208 {
209 if ( w != d_cornerWidget )
210 {
211 if ( canvas() )
212 {
213 delete d_cornerWidget;
214 d_cornerWidget = w;
215 if ( d_cornerWidget->parent() != canvas() )
216 {
217 #if QT_VERSION < 0x040000
218 d_cornerWidget->reparent(canvas(), QPoint(0, 0));
219 #else
220 d_cornerWidget->setParent(canvas());
221 #endif
222 }
223
224 updateScrollBars();
225 }
226 }
227 }
228
cornerWidget() const229 QWidget *ScrollZoomer::cornerWidget() const
230 {
231 return d_cornerWidget;
232 }
233
eventFilter(QObject * o,QEvent * e)234 bool ScrollZoomer::eventFilter(QObject *o, QEvent *e)
235 {
236 if ( o == canvas() )
237 {
238 switch(e->type())
239 {
240 case QEvent::Resize:
241 {
242 const int fw = ((QwtPlotCanvas *)canvas())->frameWidth();
243
244 QRect rect;
245 rect.setSize(((QResizeEvent *)e)->size());
246 rect.setRect(rect.x() + fw, rect.y() + fw,
247 rect.width() - 2 * fw, rect.height() - 2 * fw);
248
249 layoutScrollBars(rect);
250 break;
251 }
252 case QEvent::ChildRemoved:
253 {
254 const QObject *child = ((QChildEvent *)e)->child();
255 if ( child == d_cornerWidget )
256 d_cornerWidget = NULL;
257 else if ( child == d_hScrollData->scrollBar )
258 d_hScrollData->scrollBar = NULL;
259 else if ( child == d_vScrollData->scrollBar )
260 d_vScrollData->scrollBar = NULL;
261 break;
262 }
263 default:
264 break;
265 }
266 }
267 return QwtPlotZoomer::eventFilter(o, e);
268 }
269
needScrollBar(Qt::Orientation o) const270 bool ScrollZoomer::needScrollBar(Qt::Orientation o) const
271 {
272 #if QT_VERSION < 0x040000
273 QScrollView::ScrollBarMode mode;
274 #else
275 Qt::ScrollBarPolicy mode;
276 #endif
277 double zoomMin, zoomMax, baseMin, baseMax;
278
279 if ( o == Qt::Horizontal )
280 {
281 mode = d_hScrollData->mode;
282 baseMin = zoomBase().left();
283 baseMax = zoomBase().right();
284 zoomMin = zoomRect().left();
285 zoomMax = zoomRect().right();
286 }
287 else
288 {
289 mode = d_vScrollData->mode;
290 baseMin = zoomBase().top();
291 baseMax = zoomBase().bottom();
292 zoomMin = zoomRect().top();
293 zoomMax = zoomRect().bottom();
294 }
295
296 bool needed = false;
297 switch(mode)
298 {
299 #if QT_VERSION < 0x040000
300 case QScrollView::AlwaysOn:
301 #else
302 case Qt::ScrollBarAlwaysOn:
303 #endif
304 needed = true;
305 break;
306 #if QT_VERSION < 0x040000
307 case QScrollView::AlwaysOff:
308 #else
309 case Qt::ScrollBarAlwaysOff:
310 #endif
311 needed = false;
312 break;
313 default:
314 {
315 if ( baseMin < zoomMin || baseMax > zoomMax )
316 needed = true;
317 break;
318 }
319 }
320 return needed;
321 }
322
updateScrollBars()323 void ScrollZoomer::updateScrollBars()
324 {
325 if ( !canvas() )
326 return;
327
328 const int xAxis = QwtPlotZoomer::xAxis();
329 const int yAxis = QwtPlotZoomer::yAxis();
330
331 int xScrollBarAxis = xAxis;
332 if ( hScrollBarPosition() == OppositeToScale )
333 xScrollBarAxis = oppositeAxis(xScrollBarAxis);
334
335 int yScrollBarAxis = yAxis;
336 if ( vScrollBarPosition() == OppositeToScale )
337 yScrollBarAxis = oppositeAxis(yScrollBarAxis);
338
339
340 QwtPlotLayout *layout = plot()->plotLayout();
341
342 bool showHScrollBar = needScrollBar(Qt::Horizontal);
343 if ( showHScrollBar )
344 {
345 ScrollBar *sb = scrollBar(Qt::Horizontal);
346
347 sb->setPalette(plot()->palette());
348
349 const QwtScaleDiv *sd = plot()->axisScaleDiv(xAxis);
350 sb->setInverted(sd->lowerBound() > sd->upperBound() );
351
352 sb->setBase(zoomBase().left(), zoomBase().right());
353 sb->moveSlider(zoomRect().left(), zoomRect().right());
354
355 if ( !sb->isVisibleTo(canvas()) )
356 {
357 sb->show();
358 layout->setCanvasMargin(layout->canvasMargin(xScrollBarAxis)
359 + sb->extent(), xScrollBarAxis);
360 }
361 }
362 else
363 {
364 if ( horizontalScrollBar() )
365 {
366 horizontalScrollBar()->hide();
367 layout->setCanvasMargin(layout->canvasMargin(xScrollBarAxis)
368 - horizontalScrollBar()->extent(), xScrollBarAxis);
369 }
370 }
371
372 bool showVScrollBar = needScrollBar(Qt::Vertical);
373 if ( showVScrollBar )
374 {
375 ScrollBar *sb = scrollBar(Qt::Vertical);
376
377 sb->setPalette(plot()->palette());
378
379 const QwtScaleDiv *sd = plot()->axisScaleDiv(yAxis);
380 sb->setInverted(sd->lowerBound() < sd->upperBound() );
381
382 sb->setBase(zoomBase().top(), zoomBase().bottom());
383 sb->moveSlider(zoomRect().top(), zoomRect().bottom());
384
385 if ( !sb->isVisibleTo(canvas()) )
386 {
387 sb->show();
388 layout->setCanvasMargin(layout->canvasMargin(yScrollBarAxis)
389 + sb->extent(), yScrollBarAxis);
390 }
391 }
392 else
393 {
394 if ( verticalScrollBar() )
395 {
396 verticalScrollBar()->hide();
397 layout->setCanvasMargin(layout->canvasMargin(yScrollBarAxis)
398 - verticalScrollBar()->extent(), yScrollBarAxis);
399 }
400 }
401
402 if ( showHScrollBar && showVScrollBar )
403 {
404 if ( d_cornerWidget == NULL )
405 {
406 d_cornerWidget = new QWidget(canvas());
407 #if QT_VERSION >= 0x040100
408 d_cornerWidget->setAutoFillBackground(true);
409 #endif
410 d_cornerWidget->setPalette(plot()->palette());
411 }
412 d_cornerWidget->show();
413 }
414 else
415 {
416 if ( d_cornerWidget )
417 d_cornerWidget->hide();
418 }
419
420 layoutScrollBars(((QwtPlotCanvas *)canvas())->contentsRect());
421 plot()->updateLayout();
422 }
423
layoutScrollBars(const QRect & rect)424 void ScrollZoomer::layoutScrollBars(const QRect &rect)
425 {
426 int hPos = xAxis();
427 if ( hScrollBarPosition() == OppositeToScale )
428 hPos = oppositeAxis(hPos);
429
430 int vPos = yAxis();
431 if ( vScrollBarPosition() == OppositeToScale )
432 vPos = oppositeAxis(vPos);
433
434 ScrollBar *hScrollBar = horizontalScrollBar();
435 ScrollBar *vScrollBar = verticalScrollBar();
436
437 const int hdim = hScrollBar ? hScrollBar->extent() : 0;
438 const int vdim = vScrollBar ? vScrollBar->extent() : 0;
439
440 if ( hScrollBar && hScrollBar->isVisible() )
441 {
442 int x = rect.x();
443 int y = (hPos == QwtPlot::xTop)
444 ? rect.top() : rect.bottom() - hdim + 1;
445 int w = rect.width();
446
447 if ( vScrollBar && vScrollBar->isVisible() )
448 {
449 if ( vPos == QwtPlot::yLeft )
450 x += vdim;
451 w -= vdim;
452 }
453
454 hScrollBar->setGeometry(x, y, w, hdim);
455 }
456 if ( vScrollBar && vScrollBar->isVisible() )
457 {
458 int pos = yAxis();
459 if ( vScrollBarPosition() == OppositeToScale )
460 pos = oppositeAxis(pos);
461
462 int x = (vPos == QwtPlot::yLeft)
463 ? rect.left() : rect.right() - vdim + 1;
464 int y = rect.y();
465
466 int h = rect.height();
467
468 if ( hScrollBar && hScrollBar->isVisible() )
469 {
470 if ( hPos == QwtPlot::xTop )
471 y += hdim;
472
473 h -= hdim;
474 }
475
476 vScrollBar->setGeometry(x, y, vdim, h);
477 }
478 if ( hScrollBar && hScrollBar->isVisible() &&
479 vScrollBar && vScrollBar->isVisible() )
480 {
481 if ( d_cornerWidget )
482 {
483 QRect cornerRect(
484 vScrollBar->pos().x(), hScrollBar->pos().y(),
485 vdim, hdim);
486 d_cornerWidget->setGeometry(cornerRect);
487 }
488 }
489 }
490
scrollBarMoved(Qt::Orientation o,double min,double)491 void ScrollZoomer::scrollBarMoved(Qt::Orientation o, double min, double)
492 {
493 if ( o == Qt::Horizontal )
494 move(min, zoomRect().top());
495 else
496 move(zoomRect().left(), min);
497
498 emit zoomed(zoomRect());
499 }
500
oppositeAxis(int axis) const501 int ScrollZoomer::oppositeAxis(int axis) const
502 {
503 switch(axis)
504 {
505 case QwtPlot::xBottom:
506 return QwtPlot::xTop;
507 case QwtPlot::xTop:
508 return QwtPlot::xBottom;
509 case QwtPlot::yLeft:
510 return QwtPlot::yRight;
511 case QwtPlot::yRight:
512 return QwtPlot::yLeft;
513 default:
514 break;
515 }
516
517 return axis;
518 }
519