1
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
3
* Copyright (C) 1997 Josef Wilgen
4
* Copyright (C) 2002 Uwe Rathmann
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the Qwt License, Version 1.0
8
*****************************************************************************/
11
#if QT_VERSION < 0x040000
12
#include <qguardedptr.h>
13
#include <qfocusdata.h>
16
#include <qpaintengine.h>
18
#include <qapplication.h>
21
#include "qwt_plot_dict.h"
22
#include "qwt_plot_layout.h"
23
#include "qwt_scale_widget.h"
24
#include "qwt_scale_engine.h"
25
#include "qwt_text_label.h"
26
#include "qwt_legend.h"
27
#include "qwt_dyngrid_layout.h"
28
#include "qwt_plot_canvas.h"
29
#include "qwt_paint_buffer.h"
31
class QwtPlot::PrivateData
34
#if QT_VERSION < 0x040000
35
QGuardedPtr<QwtTextLabel> lblTitle;
36
QGuardedPtr<QwtPlotCanvas> canvas;
37
QGuardedPtr<QwtLegend> legend;
39
QPointer<QwtTextLabel> lblTitle;
40
QPointer<QwtPlotCanvas> canvas;
41
QPointer<QwtLegend> legend;
43
QwtPlotLayout *layout;
50
\param parent Parent widget
52
QwtPlot::QwtPlot(QWidget *parent):
60
\param title Title text
61
\param parent Parent widget
63
QwtPlot::QwtPlot(const QwtText &title, QWidget *parent):
69
#if QT_VERSION < 0x040000
72
\param parent Parent widget
73
\param name Object name
75
QwtPlot::QwtPlot(QWidget *parent, const char *name):
86
detachItems(QwtPlotItem::Rtti_PlotItem, autoDelete());
88
delete d_data->layout;
94
\brief Initializes a QwtPlot instance
95
\param title Title text
97
void QwtPlot::initPlot(const QwtText &title)
99
d_data = new PrivateData;
101
#if QT_VERSION < 0x040000
102
setWFlags(Qt::WNoAutoErase);
105
d_data->layout = new QwtPlotLayout;
107
d_data->autoReplot = false;
109
d_data->lblTitle = new QwtTextLabel(title, this);
110
d_data->lblTitle->setFont(QFont(fontInfo().family(), 14, QFont::Bold));
113
int flags = Qt::AlignCenter;
114
#if QT_VERSION < 0x040000
115
flags |= Qt::WordBreak | Qt::ExpandTabs;
117
flags |= Qt::TextWordWrap;
119
text.setRenderFlags(flags);
120
d_data->lblTitle->setText(text);
122
d_data->legend = NULL;
126
d_data->canvas = new QwtPlotCanvas(this);
127
d_data->canvas->setFrameStyle(QFrame::Panel|QFrame::Sunken);
128
d_data->canvas->setLineWidth(2);
129
d_data->canvas->setMidLineWidth(0);
133
setSizePolicy(QSizePolicy::MinimumExpanding,
134
QSizePolicy::MinimumExpanding);
138
\brief Adds handling of layout requests
140
bool QwtPlot::event(QEvent *e)
142
bool ok = QFrame::event(e);
145
#if QT_VERSION < 0x040000
146
case QEvent::LayoutHint:
148
case QEvent::LayoutRequest:
152
#if QT_VERSION >= 0x040000
153
case QEvent::PolishRequest:
162
//! Replots the plot if QwtPlot::autoReplot() is \c true.
163
void QwtPlot::autoRefresh()
165
if (d_data->autoReplot)
170
\brief Set or reset the autoReplot option
172
If the autoReplot option is set, the plot will be
173
updated implicitly by manipulating member functions.
174
Since this may be time-consuming, it is recommended
175
to leave this option switched off and call replot()
176
explicitly if necessary.
178
The autoReplot option is set to false by default, which
179
means that the user has to call replot() in order to make
181
\param tf \c true or \c false. Defaults to \c true.
184
void QwtPlot::setAutoReplot(bool tf)
186
d_data->autoReplot = tf;
189
//! \return true if the autoReplot option is set.
190
bool QwtPlot::autoReplot() const
192
return d_data->autoReplot;
196
Change the plot's title
197
\param title New title
199
void QwtPlot::setTitle(const QString &title)
201
if ( title != d_data->lblTitle->text().text() )
203
d_data->lblTitle->setText(title);
209
Change the plot's title
210
\param title New title
212
void QwtPlot::setTitle(const QwtText &title)
214
if ( title != d_data->lblTitle->text() )
216
d_data->lblTitle->setText(title);
221
//! \return the plot's title
222
QwtText QwtPlot::title() const
224
return d_data->lblTitle->text();
227
//! \return the plot's title
228
QwtPlotLayout *QwtPlot::plotLayout()
230
return d_data->layout;
233
//! \return the plot's titel label.
234
const QwtPlotLayout *QwtPlot::plotLayout() const
236
return d_data->layout;
239
//! \return the plot's titel label.
240
QwtTextLabel *QwtPlot::titleLabel()
242
return d_data->lblTitle;
246
\return the plot's titel label.
248
const QwtTextLabel *QwtPlot::titleLabel() const
250
return d_data->lblTitle;
254
\return the plot's legend
257
QwtLegend *QwtPlot::legend()
259
return d_data->legend;
263
\return the plot's legend
266
const QwtLegend *QwtPlot::legend() const
268
return d_data->legend;
273
\return the plot's canvas
275
QwtPlotCanvas *QwtPlot::canvas()
277
return d_data->canvas;
281
\return the plot's canvas
283
const QwtPlotCanvas *QwtPlot::canvas() const
285
return d_data->canvas;
289
void QwtPlot::polish()
293
#if QT_VERSION < 0x040000
300
\sa minimumSizeHint()
303
QSize QwtPlot::sizeHint() const
307
for ( int axisId = 0; axisId < axisCnt; axisId++ )
309
if ( axisEnabled(axisId) )
311
const int niceDist = 40;
312
const QwtScaleWidget *scaleWidget = axisWidget(axisId);
313
const QwtScaleDiv &scaleDiv = scaleWidget->scaleDraw()->scaleDiv();
314
const int majCnt = scaleDiv.ticks(QwtScaleDiv::MajorTick).count();
316
if ( axisId == yLeft || axisId == yRight )
318
int hDiff = (majCnt - 1) * niceDist
319
- scaleWidget->minimumSizeHint().height();
325
int wDiff = (majCnt - 1) * niceDist
326
- scaleWidget->minimumSizeHint().width();
332
return minimumSizeHint() + QSize(dw, dh);
336
\brief Return a minimum size hint
338
QSize QwtPlot::minimumSizeHint() const
340
QSize hint = d_data->layout->minimumSizeHint(this);
341
hint += QSize(2 * frameWidth(), 2 * frameWidth());
346
//! Resize and update internal layout
347
void QwtPlot::resizeEvent(QResizeEvent *e)
349
QFrame::resizeEvent(e);
354
\brief Redraw the plot
356
If the autoReplot option is not set (which is the default)
357
or if any curves are attached to raw data, the plot has to
358
be refreshed explicitly in order to make changes visible.
361
\warning Calls canvas()->repaint, take care of infinite recursions
363
void QwtPlot::replot()
365
bool doAutoReplot = autoReplot();
366
setAutoReplot(false);
371
Maybe the layout needs to be updated, because of changed
372
axes labels. We need to process them here before painting
373
to avoid that scales and canvas get out of sync.
375
#if QT_VERSION >= 0x040000
376
QApplication::sendPostedEvents(this, QEvent::LayoutRequest);
378
QApplication::sendPostedEvents(this, QEvent::LayoutHint);
381
QwtPlotCanvas &canvas = *d_data->canvas;
383
canvas.invalidatePaintCache();
386
In case of cached or packed painting the canvas
387
is repainted completely and doesn't need to be erased.
390
!canvas.testPaintAttribute(QwtPlotCanvas::PaintPacked)
391
&& !canvas.testPaintAttribute(QwtPlotCanvas::PaintCached);
393
#if QT_VERSION >= 0x040000
394
const bool noBackgroundMode = canvas.testAttribute(Qt::WA_NoBackground);
395
if ( !erase && !noBackgroundMode )
396
canvas.setAttribute(Qt::WA_NoBackground, true);
398
canvas.repaint(canvas.contentsRect());
400
if ( !erase && !noBackgroundMode )
401
canvas.setAttribute(Qt::WA_NoBackground, false);
403
canvas.repaint(canvas.contentsRect(), erase);
406
setAutoReplot(doAutoReplot);
410
\brief Adjust plot content to its current size.
413
void QwtPlot::updateLayout()
415
d_data->layout->activate(this, contentsRect());
418
// resize and show the visible widgets
420
if (!d_data->lblTitle->text().isEmpty())
422
d_data->lblTitle->setGeometry(d_data->layout->titleRect());
423
if (!d_data->lblTitle->isVisible())
424
d_data->lblTitle->show();
427
d_data->lblTitle->hide();
429
for (int axisId = 0; axisId < axisCnt; axisId++ )
431
if (axisEnabled(axisId) )
433
axisWidget(axisId)->setGeometry(d_data->layout->scaleRect(axisId));
435
if ( axisId == xBottom || axisId == xTop )
437
QRegion r(d_data->layout->scaleRect(axisId));
438
if ( axisEnabled(yLeft) )
439
r = r.subtract(QRegion(d_data->layout->scaleRect(yLeft)));
440
if ( axisEnabled(yRight) )
441
r = r.subtract(QRegion(d_data->layout->scaleRect(yRight)));
442
r.translate(-d_data->layout->scaleRect(axisId).x(),
443
-d_data->layout->scaleRect(axisId).y());
445
axisWidget(axisId)->setMask(r);
447
if (!axisWidget(axisId)->isVisible())
448
axisWidget(axisId)->show();
451
axisWidget(axisId)->hide();
454
if ( d_data->legend &&
455
d_data->layout->legendPosition() != ExternalLegend )
457
if (d_data->legend->itemCount() > 0)
459
d_data->legend->setGeometry(d_data->layout->legendRect());
460
d_data->legend->show();
463
d_data->legend->hide();
466
d_data->canvas->setGeometry(d_data->layout->canvasRect());
470
Update the focus tab order
472
The order is changed so that the canvas will be in front of the
473
first legend item, or behind the last legend item - depending
474
on the position of the legend.
477
void QwtPlot::updateTabOrder()
479
#if QT_VERSION >= 0x040000
480
using namespace Qt; // QWidget::NoFocus/Qt::NoFocus
482
if ( d_data->canvas->focusPolicy() == NoFocus )
485
if ( d_data->legend.isNull()
486
|| d_data->layout->legendPosition() == ExternalLegend
487
|| d_data->legend->legendItems().count() == 0 )
492
// Depending on the position of the legend the
493
// tab order will be changed that the canvas is
494
// next to the last legend item, or before
497
const bool canvasFirst =
498
d_data->layout->legendPosition() == QwtPlot::BottomLegend ||
499
d_data->layout->legendPosition() == QwtPlot::RightLegend;
501
QWidget *previous = NULL;
504
#if QT_VERSION >= 0x040000
506
while ( ( w = w->nextInFocusChain() ) != d_data->canvas )
508
if ( focusData() == NULL )
511
while ( focusData()->next() != d_data->canvas );
512
while ( (w = focusData()->next()) != d_data->canvas )
515
bool isLegendItem = false;
516
if ( w->focusPolicy() != NoFocus
517
&& w->parent() && w->parent() == d_data->legend->contentsWidget() )
541
if ( previous && previous != d_data->canvas)
542
setTabOrder(previous, d_data->canvas);
547
\param painter Painter used for drawing
549
\warning drawCanvas calls drawItems what is also used
550
for printing. Applications that like to add individual
551
plot items better overload drawItems()
554
void QwtPlot::drawCanvas(QPainter *painter)
556
QwtScaleMap maps[axisCnt];
557
for ( int axisId = 0; axisId < axisCnt; axisId++ )
558
maps[axisId] = canvasMap(axisId);
561
d_data->canvas->contentsRect(), maps, QwtPlotPrintFilter());
565
Redraw the canvas items.
566
\param painter Painter used for drawing
567
\param rect Bounding rectangle where to paint
568
\param map QwtPlot::axisCnt maps, mapping between plot and paint device coordinates
569
\param pfilter Plot print filter
572
void QwtPlot::drawItems(QPainter *painter, const QRect &rect,
573
const QwtScaleMap map[axisCnt],
574
const QwtPlotPrintFilter &pfilter) const
576
const QwtPlotItemList& itmList = itemList();
577
for ( QwtPlotItemIterator it = itmList.begin();
578
it != itmList.end(); ++it )
580
QwtPlotItem *item = *it;
581
if ( item && item->isVisible() )
583
if ( !(pfilter.options() & QwtPlotPrintFilter::PrintGrid)
584
&& item->rtti() == QwtPlotItem::Rtti_PlotGrid )
591
#if QT_VERSION >= 0x040000
592
painter->setRenderHint(QPainter::Antialiasing,
593
item->testRenderHint(QwtPlotItem::RenderAntialiased) );
597
map[item->xAxis()], map[item->yAxis()],
607
\return Map for the axis on the canvas. With this map pixel coordinates can
608
translated to plot coordinates and vice versa.
609
\sa QwtScaleMap, transform(), invTransform()
612
QwtScaleMap QwtPlot::canvasMap(int axisId) const
615
if ( !d_data->canvas )
618
map.setTransformation(axisScaleEngine(axisId)->transformation());
620
const QwtScaleDiv *sd = axisScaleDiv(axisId);
621
map.setScaleInterval(sd->lBound(), sd->hBound());
623
if ( axisEnabled(axisId) )
625
const QwtScaleWidget *s = axisWidget(axisId);
626
if ( axisId == yLeft || axisId == yRight )
628
int y = s->y() + s->startBorderDist() - d_data->canvas->y();
629
int h = s->height() - s->startBorderDist() - s->endBorderDist();
630
map.setPaintInterval(y + h, y);
634
int x = s->x() + s->startBorderDist() - d_data->canvas->x();
635
int w = s->width() - s->startBorderDist() - s->endBorderDist();
636
map.setPaintInterval(x, x + w);
641
const int margin = plotLayout()->canvasMargin(axisId);
643
const QRect &canvasRect = d_data->canvas->contentsRect();
644
if ( axisId == yLeft || axisId == yRight )
646
map.setPaintInterval(canvasRect.bottom() - margin,
647
canvasRect.top() + margin);
651
map.setPaintInterval(canvasRect.left() + margin,
652
canvasRect.right() - margin);
659
Change the margin of the plot. The margin is the space
660
around all components.
662
\param margin new margin
663
\sa QwtPlotLayout::setMargin(), margin(), plotLayout()
665
void QwtPlot::setMargin(int margin)
670
if ( margin != d_data->layout->margin() )
672
d_data->layout->setMargin(margin);
679
\sa setMargin(), QwtPlotLayout::margin(), plotLayout()
681
int QwtPlot::margin() const
683
return d_data->layout->margin();
687
\brief Change the background of the plotting area
689
Sets c to QColorGroup::Background of all colorgroups of
690
the palette of the canvas. Using canvas()->setPalette()
691
is a more powerful way to set these colors.
692
\param c new background color
694
void QwtPlot::setCanvasBackground(const QColor &c)
696
QPalette p = d_data->canvas->palette();
698
for ( int i = 0; i < QPalette::NColorGroups; i++ )
700
#if QT_VERSION < 0x040000
701
p.setColor((QPalette::ColorGroup)i, QColorGroup::Background, c);
703
p.setColor((QPalette::ColorGroup)i, QPalette::Background, c);
707
canvas()->setPalette(p);
711
Nothing else than: canvas()->palette().color(
712
QPalette::Normal, QColorGroup::Background);
714
\return the background color of the plotting area.
716
const QColor & QwtPlot::canvasBackground() const
718
#if QT_VERSION < 0x040000
719
return canvas()->palette().color(
720
QPalette::Normal, QColorGroup::Background);
722
return canvas()->palette().color(
723
QPalette::Normal, QPalette::Background);
728
\brief Change the border width of the plotting area
729
Nothing else than canvas()->setLineWidth(w),
730
left for compatibility only.
731
\param w new border width
733
void QwtPlot::setCanvasLineWidth(int w)
735
canvas()->setLineWidth(w);
740
Nothing else than: canvas()->lineWidth(),
741
left for compatibility only.
742
\return the border width of the plotting area
744
int QwtPlot::canvasLineWidth() const
746
return canvas()->lineWidth();
750
\return \c true if the specified axis exists, otherwise \c false
751
\param axisId axis index
753
bool QwtPlot::axisValid(int axisId)
755
return ((axisId >= QwtPlot::yLeft) && (axisId < QwtPlot::axisCnt));
759
Called internally when the legend has been clicked on.
760
Emits a legendClicked() signal.
762
void QwtPlot::legendItemClicked()
764
if ( d_data->legend && sender()->isWidgetType() )
766
QwtPlotItem *plotItem =
767
(QwtPlotItem*)d_data->legend->find((QWidget *)sender());
769
emit legendClicked(plotItem);
774
Called internally when the legend has been checked
775
Emits a legendClicked() signal.
777
void QwtPlot::legendItemChecked(bool on)
779
if ( d_data->legend && sender()->isWidgetType() )
781
QwtPlotItem *plotItem =
782
(QwtPlotItem*)d_data->legend->find((QWidget *)sender());
784
emit legendChecked(plotItem, on);
788
//! Remove all curves and markers
789
void QwtPlot::clear()
791
detachItems(QwtPlotItem::Rtti_PlotCurve);
792
detachItems(QwtPlotItem::Rtti_PlotMarker);
796
\brief Insert a legend
798
If the position legend is \c QwtPlot::LeftLegend or \c QwtPlot::RightLegend
799
the legend will be organized in one column from top to down.
800
Otherwise the legend items will be placed in a table
801
with a best fit number of columns from left to right.
803
If pos != QwtPlot::ExternalLegend the plot widget will become
804
parent of the legend. It will be deleted when the plot is deleted,
805
or another legend is set with insertLegend().
808
\param pos The legend's position. For top/left position the number
809
of colums will be limited to 1, otherwise it will be set to
812
\param ratio Ratio between legend and the bounding rect
813
of title, canvas and axes. The legend will be shrinked
814
if it would need more space than the given ratio.
815
The ratio is limited to ]0.0 .. 1.0]. In case of <= 0.0
816
it will be reset to the default ratio.
817
The default vertical/horizontal ratio is 0.33/0.5.
819
\sa legend(), QwtPlotLayout::legendPosition(),
820
QwtPlotLayout::setLegendPosition()
822
void QwtPlot::insertLegend(QwtLegend *legend,
823
QwtPlot::LegendPosition pos, double ratio)
825
d_data->layout->setLegendPosition(pos, ratio);
827
if ( legend != d_data->legend )
829
if ( d_data->legend && d_data->legend->parent() == this )
830
delete d_data->legend;
832
d_data->legend = legend;
834
if ( d_data->legend )
836
if ( pos != ExternalLegend )
838
if ( d_data->legend->parent() != this )
840
#if QT_VERSION < 0x040000
841
d_data->legend->reparent(this, QPoint(0, 0));
843
d_data->legend->setParent(this);
848
const QwtPlotItemList& itmList = itemList();
849
for ( QwtPlotItemIterator it = itmList.begin();
850
it != itmList.end(); ++it )
852
(*it)->updateLegend(d_data->legend);
855
QLayout *l = d_data->legend->contentsWidget()->layout();
856
if ( l && l->inherits("QwtDynGridLayout") )
858
QwtDynGridLayout *tl = (QwtDynGridLayout *)l;
859
switch(d_data->layout->legendPosition())
863
tl->setMaxCols(1); // 1 column: align vertical
867
tl->setMaxCols(0); // unlimited