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