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());
347
Resize and update internal layout
348
\param e Resize event
350
void QwtPlot::resizeEvent(QResizeEvent *e)
352
QFrame::resizeEvent(e);
357
\brief Redraw the plot
359
If the autoReplot option is not set (which is the default)
360
or if any curves are attached to raw data, the plot has to
361
be refreshed explicitly in order to make changes visible.
364
\warning Calls canvas()->repaint, take care of infinite recursions
366
void QwtPlot::replot()
368
bool doAutoReplot = autoReplot();
369
setAutoReplot(false);
374
Maybe the layout needs to be updated, because of changed
375
axes labels. We need to process them here before painting
376
to avoid that scales and canvas get out of sync.
378
#if QT_VERSION >= 0x040000
379
QApplication::sendPostedEvents(this, QEvent::LayoutRequest);
381
QApplication::sendPostedEvents(this, QEvent::LayoutHint);
384
d_data->canvas->replot();
386
setAutoReplot(doAutoReplot);
390
\brief Adjust plot content to its current size.
393
void QwtPlot::updateLayout()
395
d_data->layout->activate(this, contentsRect());
398
// resize and show the visible widgets
400
if (!d_data->lblTitle->text().isEmpty())
402
d_data->lblTitle->setGeometry(d_data->layout->titleRect());
403
if (!d_data->lblTitle->isVisible())
404
d_data->lblTitle->show();
407
d_data->lblTitle->hide();
409
for (int axisId = 0; axisId < axisCnt; axisId++ )
411
if (axisEnabled(axisId) )
413
axisWidget(axisId)->setGeometry(d_data->layout->scaleRect(axisId));
415
if ( axisId == xBottom || axisId == xTop )
417
QRegion r(d_data->layout->scaleRect(axisId));
418
if ( axisEnabled(yLeft) )
419
r = r.subtract(QRegion(d_data->layout->scaleRect(yLeft)));
420
if ( axisEnabled(yRight) )
421
r = r.subtract(QRegion(d_data->layout->scaleRect(yRight)));
422
r.translate(-d_data->layout->scaleRect(axisId).x(),
423
-d_data->layout->scaleRect(axisId).y());
425
axisWidget(axisId)->setMask(r);
427
if (!axisWidget(axisId)->isVisible())
428
axisWidget(axisId)->show();
431
axisWidget(axisId)->hide();
434
if ( d_data->legend &&
435
d_data->layout->legendPosition() != ExternalLegend )
437
if (d_data->legend->itemCount() > 0)
439
d_data->legend->setGeometry(d_data->layout->legendRect());
440
d_data->legend->show();
443
d_data->legend->hide();
446
d_data->canvas->setGeometry(d_data->layout->canvasRect());
450
Update the focus tab order
452
The order is changed so that the canvas will be in front of the
453
first legend item, or behind the last legend item - depending
454
on the position of the legend.
457
void QwtPlot::updateTabOrder()
459
#if QT_VERSION >= 0x040000
460
using namespace Qt; // QWidget::NoFocus/Qt::NoFocus
462
if ( d_data->canvas->focusPolicy() == NoFocus )
465
if ( d_data->legend.isNull()
466
|| d_data->layout->legendPosition() == ExternalLegend
467
|| d_data->legend->legendItems().count() == 0 )
472
// Depending on the position of the legend the
473
// tab order will be changed that the canvas is
474
// next to the last legend item, or before
477
const bool canvasFirst =
478
d_data->layout->legendPosition() == QwtPlot::BottomLegend ||
479
d_data->layout->legendPosition() == QwtPlot::RightLegend;
481
QWidget *previous = NULL;
484
#if QT_VERSION >= 0x040000
486
while ( ( w = w->nextInFocusChain() ) != d_data->canvas )
488
if ( focusData() == NULL )
491
while ( focusData()->next() != d_data->canvas );
492
while ( (w = focusData()->next()) != d_data->canvas )
495
bool isLegendItem = false;
496
if ( w->focusPolicy() != NoFocus
497
&& w->parent() && w->parent() == d_data->legend->contentsWidget() )
521
if ( previous && previous != d_data->canvas)
522
setTabOrder(previous, d_data->canvas);
527
\param painter Painter used for drawing
529
\warning drawCanvas calls drawItems what is also used
530
for printing. Applications that like to add individual
531
plot items better overload drawItems()
534
void QwtPlot::drawCanvas(QPainter *painter)
536
QwtScaleMap maps[axisCnt];
537
for ( int axisId = 0; axisId < axisCnt; axisId++ )
538
maps[axisId] = canvasMap(axisId);
541
d_data->canvas->contentsRect(), maps, QwtPlotPrintFilter());
545
Redraw the canvas items.
546
\param painter Painter used for drawing
547
\param rect Bounding rectangle where to paint
548
\param map QwtPlot::axisCnt maps, mapping between plot and paint device coordinates
549
\param pfilter Plot print filter
552
void QwtPlot::drawItems(QPainter *painter, const QRect &rect,
553
const QwtScaleMap map[axisCnt],
554
const QwtPlotPrintFilter &pfilter) const
556
const QwtPlotItemList& itmList = itemList();
557
for ( QwtPlotItemIterator it = itmList.begin();
558
it != itmList.end(); ++it )
560
QwtPlotItem *item = *it;
561
if ( item && item->isVisible() )
563
if ( !(pfilter.options() & QwtPlotPrintFilter::PrintGrid)
564
&& item->rtti() == QwtPlotItem::Rtti_PlotGrid )
571
#if QT_VERSION >= 0x040000
572
painter->setRenderHint(QPainter::Antialiasing,
573
item->testRenderHint(QwtPlotItem::RenderAntialiased) );
577
map[item->xAxis()], map[item->yAxis()],
587
\return Map for the axis on the canvas. With this map pixel coordinates can
588
translated to plot coordinates and vice versa.
589
\sa QwtScaleMap, transform(), invTransform()
592
QwtScaleMap QwtPlot::canvasMap(int axisId) const
595
if ( !d_data->canvas )
598
map.setTransformation(axisScaleEngine(axisId)->transformation());
600
const QwtScaleDiv *sd = axisScaleDiv(axisId);
601
map.setScaleInterval(sd->lowerBound(), sd->upperBound());
603
if ( axisEnabled(axisId) )
605
const QwtScaleWidget *s = axisWidget(axisId);
606
if ( axisId == yLeft || axisId == yRight )
608
int y = s->y() + s->startBorderDist() - d_data->canvas->y();
609
int h = s->height() - s->startBorderDist() - s->endBorderDist();
610
map.setPaintInterval(y + h, y);
614
int x = s->x() + s->startBorderDist() - d_data->canvas->x();
615
int w = s->width() - s->startBorderDist() - s->endBorderDist();
616
map.setPaintInterval(x, x + w);
621
const int margin = plotLayout()->canvasMargin(axisId);
623
const QRect &canvasRect = d_data->canvas->contentsRect();
624
if ( axisId == yLeft || axisId == yRight )
626
map.setPaintInterval(canvasRect.bottom() - margin,
627
canvasRect.top() + margin);
631
map.setPaintInterval(canvasRect.left() + margin,
632
canvasRect.right() - margin);
639
Change the margin of the plot. The margin is the space
640
around all components.
642
\param margin new margin
643
\sa QwtPlotLayout::setMargin(), margin(), plotLayout()
645
void QwtPlot::setMargin(int margin)
650
if ( margin != d_data->layout->margin() )
652
d_data->layout->setMargin(margin);
659
\sa setMargin(), QwtPlotLayout::margin(), plotLayout()
661
int QwtPlot::margin() const
663
return d_data->layout->margin();
667
\brief Change the background of the plotting area
669
Sets c to QColorGroup::Background of all colorgroups of
670
the palette of the canvas. Using canvas()->setPalette()
671
is a more powerful way to set these colors.
672
\param c new background color
674
void QwtPlot::setCanvasBackground(const QColor &c)
676
QPalette p = d_data->canvas->palette();
678
for ( int i = 0; i < QPalette::NColorGroups; i++ )
680
#if QT_VERSION < 0x040000
681
p.setColor((QPalette::ColorGroup)i, QColorGroup::Background, c);
683
p.setColor((QPalette::ColorGroup)i, QPalette::Background, c);
687
canvas()->setPalette(p);
691
Nothing else than: canvas()->palette().color(
692
QPalette::Normal, QColorGroup::Background);
694
\return the background color of the plotting area.
696
const QColor & QwtPlot::canvasBackground() const
698
#if QT_VERSION < 0x040000
699
return canvas()->palette().color(
700
QPalette::Normal, QColorGroup::Background);
702
return canvas()->palette().color(
703
QPalette::Normal, QPalette::Background);
708
\brief Change the border width of the plotting area
709
Nothing else than canvas()->setLineWidth(w),
710
left for compatibility only.
711
\param w new border width
713
void QwtPlot::setCanvasLineWidth(int w)
715
canvas()->setLineWidth(w);
720
Nothing else than: canvas()->lineWidth(),
721
left for compatibility only.
722
\return the border width of the plotting area
724
int QwtPlot::canvasLineWidth() const
726
return canvas()->lineWidth();
730
\return \c true if the specified axis exists, otherwise \c false
731
\param axisId axis index
733
bool QwtPlot::axisValid(int axisId)
735
return ((axisId >= QwtPlot::yLeft) && (axisId < QwtPlot::axisCnt));
739
Called internally when the legend has been clicked on.
740
Emits a legendClicked() signal.
742
void QwtPlot::legendItemClicked()
744
if ( d_data->legend && sender()->isWidgetType() )
746
QwtPlotItem *plotItem =
747
(QwtPlotItem*)d_data->legend->find((QWidget *)sender());
749
emit legendClicked(plotItem);
754
Called internally when the legend has been checked
755
Emits a legendClicked() signal.
757
void QwtPlot::legendItemChecked(bool on)
759
if ( d_data->legend && sender()->isWidgetType() )
761
QwtPlotItem *plotItem =
762
(QwtPlotItem*)d_data->legend->find((QWidget *)sender());
764
emit legendChecked(plotItem, on);
769
Remove all curves and markers
770
\deprecated Use QwtPlotDeict::detachItems instead
772
void QwtPlot::clear()
774
detachItems(QwtPlotItem::Rtti_PlotCurve);
775
detachItems(QwtPlotItem::Rtti_PlotMarker);
779
\brief Insert a legend
781
If the position legend is \c QwtPlot::LeftLegend or \c QwtPlot::RightLegend
782
the legend will be organized in one column from top to down.
783
Otherwise the legend items will be placed in a table
784
with a best fit number of columns from left to right.
786
If pos != QwtPlot::ExternalLegend the plot widget will become
787
parent of the legend. It will be deleted when the plot is deleted,
788
or another legend is set with insertLegend().
791
\param pos The legend's position. For top/left position the number
792
of colums will be limited to 1, otherwise it will be set to
795
\param ratio Ratio between legend and the bounding rect
796
of title, canvas and axes. The legend will be shrinked
797
if it would need more space than the given ratio.
798
The ratio is limited to ]0.0 .. 1.0]. In case of <= 0.0
799
it will be reset to the default ratio.
800
The default vertical/horizontal ratio is 0.33/0.5.
802
\sa legend(), QwtPlotLayout::legendPosition(),
803
QwtPlotLayout::setLegendPosition()
805
void QwtPlot::insertLegend(QwtLegend *legend,
806
QwtPlot::LegendPosition pos, double ratio)
808
d_data->layout->setLegendPosition(pos, ratio);
810
if ( legend != d_data->legend )
812
if ( d_data->legend && d_data->legend->parent() == this )
813
delete d_data->legend;
815
d_data->legend = legend;
817
if ( d_data->legend )
819
if ( pos != ExternalLegend )
821
if ( d_data->legend->parent() != this )
823
#if QT_VERSION < 0x040000
824
d_data->legend->reparent(this, QPoint(0, 0));
826
d_data->legend->setParent(this);
831
const QwtPlotItemList& itmList = itemList();
832
for ( QwtPlotItemIterator it = itmList.begin();
833
it != itmList.end(); ++it )
835
(*it)->updateLegend(d_data->legend);
838
QLayout *l = d_data->legend->contentsWidget()->layout();
839
if ( l && l->inherits("QwtDynGridLayout") )
841
QwtDynGridLayout *tl = (QwtDynGridLayout *)l;
842
switch(d_data->layout->legendPosition())
846
tl->setMaxCols(1); // 1 column: align vertical
850
tl->setMaxCols(0); // unlimited