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"
24
#include "qwt_scale_widget.h"
25
#include "qwt_scale_engine.h"
26
#include "qwt_text_label.h"
27
#include "qwt_legend.h"
28
#include "qwt_dyngrid_layout.h"
29
#include "qwt_plot_canvas.h"
30
#include "qwt_paint_buffer.h"
32
class QwtPlot::PrivateData
35
#if QT_VERSION < 0x040000
36
QGuardedPtr<QwtTextLabel> lblTitle;
37
QGuardedPtr<QwtPlotCanvas> canvas;
38
QGuardedPtr<QwtLegend> legend;
40
QPointer<QwtTextLabel> lblTitle;
41
QPointer<QwtPlotCanvas> canvas;
42
QPointer<QwtLegend> legend;
44
QwtPlotLayout *layout;
51
\param parent Parent widget
53
QwtPlot::QwtPlot(QWidget *parent):
61
\param title Title text
62
\param parent Parent widget
64
QwtPlot::QwtPlot(const QwtText &title, QWidget *parent):
70
#if QT_VERSION < 0x040000
73
\param parent Parent widget
74
\param name Object name
76
QwtPlot::QwtPlot(QWidget *parent, const char *name):
87
detachItems(QwtPlotItem::Rtti_PlotItem, autoDelete());
89
delete d_data->layout;
95
\brief Initializes a QwtPlot instance
96
\param title Title text
98
void QwtPlot::initPlot(const QwtText &title)
100
d_data = new PrivateData;
102
#if QT_VERSION < 0x040000
103
setWFlags(Qt::WNoAutoErase);
106
d_data->layout = new QwtPlotLayout;
108
d_data->autoReplot = false;
110
d_data->lblTitle = new QwtTextLabel(title, this);
111
d_data->lblTitle->setFont(QFont(fontInfo().family(), 14, QFont::Bold));
114
int flags = Qt::AlignCenter;
115
#if QT_VERSION < 0x040000
116
flags |= Qt::WordBreak | Qt::ExpandTabs;
118
flags |= Qt::TextWordWrap;
120
text.setRenderFlags(flags);
121
d_data->lblTitle->setText(text);
123
d_data->legend = NULL;
127
d_data->canvas = new QwtPlotCanvas(this);
128
d_data->canvas->setFrameStyle(QFrame::Panel|QFrame::Sunken);
129
d_data->canvas->setLineWidth(2);
130
d_data->canvas->setMidLineWidth(0);
134
setSizePolicy(QSizePolicy::MinimumExpanding,
135
QSizePolicy::MinimumExpanding);
139
\brief Adds handling of layout requests
141
bool QwtPlot::event(QEvent *e)
143
bool ok = QFrame::event(e);
146
#if QT_VERSION < 0x040000
147
case QEvent::LayoutHint:
149
case QEvent::LayoutRequest:
153
#if QT_VERSION >= 0x040000
154
case QEvent::PolishRequest:
164
\brief Replots the plot if QwtPlot::autoReplot() is \c true.
167
void QwtPlot::autoRefresh()
169
if (d_data->autoReplot)
174
\brief Set or reset the autoReplot option
175
If the autoReplot option is set, the plot will be
176
updated implicitly by manipulating member functions.
177
Since this may be time-consuming, it is recommended
178
to leave this option switched off and call replot()
179
explicitly if necessary.
181
The autoReplot option is set to false by default, which
182
means that the user has to call replot() in order to make
184
\param tf \c true or \c false. Defaults to \c true.
187
void QwtPlot::setAutoReplot(bool tf)
189
d_data->autoReplot = tf;
193
\return true if the autoReplot option is set.
195
bool QwtPlot::autoReplot() const
197
return d_data->autoReplot;
201
\brief Change the plot's title
204
void QwtPlot::setTitle(const QString &t)
206
if ( t != d_data->lblTitle->text().text() )
208
d_data->lblTitle->setText(t);
214
\brief Change the plot's title
217
void QwtPlot::setTitle(const QwtText &t)
219
if ( t != d_data->lblTitle->text() )
221
d_data->lblTitle->setText(t);
227
\return the plot's title
230
QwtText QwtPlot::title() const
232
return d_data->lblTitle->text();
236
\return the plot's layout
238
QwtPlotLayout *QwtPlot::plotLayout()
240
return d_data->layout;
244
\return the plot's layout
246
const QwtPlotLayout *QwtPlot::plotLayout() const
248
return d_data->layout;
252
\return the plot's titel label.
254
QwtTextLabel *QwtPlot::titleLabel()
256
return d_data->lblTitle;
260
\return the plot's titel label.
262
const QwtTextLabel *QwtPlot::titleLabel() const
264
return d_data->lblTitle;
268
\return the plot's legend
269
\sa printLegendItem()
271
QwtLegend *QwtPlot::legend()
273
return d_data->legend;
277
\return the plot's legend
278
\sa printLegendItem()
280
const QwtLegend *QwtPlot::legend() const
282
return d_data->legend;
287
\return the plot's canvas
289
QwtPlotCanvas *QwtPlot::canvas()
291
return d_data->canvas;
295
\return the plot's canvas
297
const QwtPlotCanvas *QwtPlot::canvas() const
299
return d_data->canvas;
302
void QwtPlot::polish()
306
#if QT_VERSION < 0x040000
313
\sa QwtPlot::minimumSizeHint()
316
QSize QwtPlot::sizeHint() const
320
for ( int axisId = 0; axisId < axisCnt; axisId++ )
322
if ( axisEnabled(axisId) )
324
const int niceDist = 40;
325
const QwtScaleWidget *scaleWidget = axisWidget(axisId);
326
const QwtScaleDiv &scaleDiv = scaleWidget->scaleDraw()->scaleDiv();
327
const int majCnt = scaleDiv.ticks(QwtScaleDiv::MajorTick).count();
329
if ( axisId == yLeft || axisId == yRight )
331
int hDiff = (majCnt - 1) * niceDist
332
- scaleWidget->minimumSizeHint().height();
338
int wDiff = (majCnt - 1) * niceDist
339
- scaleWidget->minimumSizeHint().width();
345
return minimumSizeHint() + QSize(dw, dh);
349
\brief Return a minimum size hint
351
QSize QwtPlot::minimumSizeHint() const
353
QSize hint = d_data->layout->minimumSizeHint(this);
354
hint += QSize(2 * frameWidth(), 2 * frameWidth());
359
//! Resize and update internal layout
360
void QwtPlot::resizeEvent(QResizeEvent *e)
362
QFrame::resizeEvent(e);
367
\brief Redraw the plot
369
If the autoReplot option is not set (which is the default)
370
or if any curves are attached to raw data, the plot has to
371
be refreshed explicitly in order to make changes visible.
374
\warning Calls canvas()->repaint, take care of infinite recursions
376
void QwtPlot::replot()
378
bool doAutoReplot = autoReplot();
379
setAutoReplot(false);
384
Maybe the layout needs to be updated, because of changed
385
axes labels. We need to process them here before painting
386
to avoid that scales and canvas get out of sync.
388
#if QT_VERSION >= 0x040000
389
QApplication::sendPostedEvents(this, QEvent::LayoutRequest);
391
QApplication::sendPostedEvents(this, QEvent::LayoutHint);
394
QwtPlotCanvas &canvas = *d_data->canvas;
396
canvas.invalidatePaintCache();
399
In case of cached or packed painting the canvas
400
is repainted completely and doesn't need to be erased.
403
!canvas.testPaintAttribute(QwtPlotCanvas::PaintPacked)
404
&& !canvas.testPaintAttribute(QwtPlotCanvas::PaintCached);
406
#if QT_VERSION >= 0x040000
407
const bool noBackgroundMode = canvas.testAttribute(Qt::WA_NoBackground);
408
if ( !erase && !noBackgroundMode )
409
canvas.setAttribute(Qt::WA_NoBackground, true);
411
canvas.repaint(canvas.contentsRect());
413
if ( !erase && !noBackgroundMode )
414
canvas.setAttribute(Qt::WA_NoBackground, false);
416
canvas.repaint(canvas.contentsRect(), erase);
419
setAutoReplot(doAutoReplot);
423
\brief Adjust plot content to its current size.
424
\sa QwtPlot::resizeEvent
426
void QwtPlot::updateLayout()
428
d_data->layout->activate(this, contentsRect());
431
// resize and show the visible widgets
433
if (!d_data->lblTitle->text().isEmpty())
435
d_data->lblTitle->setGeometry(d_data->layout->titleRect());
436
if (!d_data->lblTitle->isVisible())
437
d_data->lblTitle->show();
440
d_data->lblTitle->hide();
442
for (int axisId = 0; axisId < axisCnt; axisId++ )
444
if (axisEnabled(axisId) )
446
axisWidget(axisId)->setGeometry(d_data->layout->scaleRect(axisId));
448
if ( axisId == xBottom || axisId == xTop )
450
QRegion r(d_data->layout->scaleRect(axisId));
451
if ( axisEnabled(yLeft) )
452
r = r.subtract(QRegion(d_data->layout->scaleRect(yLeft)));
453
if ( axisEnabled(yRight) )
454
r = r.subtract(QRegion(d_data->layout->scaleRect(yRight)));
455
r.translate(-d_data->layout->scaleRect(axisId).x(),
456
-d_data->layout->scaleRect(axisId).y());
458
axisWidget(axisId)->setMask(r);
460
if (!axisWidget(axisId)->isVisible())
461
axisWidget(axisId)->show();
464
axisWidget(axisId)->hide();
467
if ( d_data->legend &&
468
d_data->layout->legendPosition() != ExternalLegend )
470
if (d_data->legend->itemCount() > 0)
472
d_data->legend->setGeometry(d_data->layout->legendRect());
473
d_data->legend->show();
476
d_data->legend->hide();
479
d_data->canvas->setGeometry(d_data->layout->canvasRect());
483
Update the focus tab order
485
The order is changed so that the canvas will be in front of the
486
first legend item, or behind the last legend item - depending
487
on the position of the legend.
490
void QwtPlot::updateTabOrder()
492
#if QT_VERSION >= 0x040000
493
using namespace Qt; // QWidget::NoFocus/Qt::NoFocus
495
if ( d_data->canvas->focusPolicy() == NoFocus )
498
if ( d_data->legend.isNull()
499
|| d_data->layout->legendPosition() == ExternalLegend
500
|| d_data->legend->legendItems().count() == 0 )
505
// Depending on the position of the legend the
506
// tab order will be changed that the canvas is
507
// next to the last legend item, or before
510
const bool canvasFirst =
511
d_data->layout->legendPosition() == QwtPlot::BottomLegend ||
512
d_data->layout->legendPosition() == QwtPlot::RightLegend;
514
QWidget *previous = NULL;
517
#if QT_VERSION >= 0x040000
519
while ( ( w = w->nextInFocusChain() ) != d_data->canvas )
521
if ( focusData() == NULL )
524
while ( focusData()->next() != d_data->canvas );
525
while ( (w = focusData()->next()) != d_data->canvas )
528
bool isLegendItem = false;
529
if ( w->focusPolicy() != NoFocus
530
&& w->parent() && w->parent() == d_data->legend->contentsWidget() )
554
if ( previous && previous != d_data->canvas)
555
setTabOrder(previous, d_data->canvas);
560
\param painter Painter used for drawing
562
\warning drawCanvas calls drawCanvasItems what is also used
563
for printing. Applications that like to add individual
564
plot items better overload QwtPlot::drawCanvasItems
565
\sa QwtPlot::drawItems
568
void QwtPlot::drawCanvas(QPainter *painter)
570
QwtScaleMap maps[axisCnt];
571
for ( int axisId = 0; axisId < axisCnt; axisId++ )
572
maps[axisId] = canvasMap(axisId);
575
d_data->canvas->contentsRect(), maps, QwtPlotPrintFilter());
579
Redraw the canvas items.
580
\param painter Painter used for drawing
581
\param rect Bounding rectangle where to paint
582
\param map QwtPlot::axisCnt maps, mapping between plot and paint device coordinates
583
\param pfilter Plot print filter
586
void QwtPlot::drawItems(QPainter *painter, const QRect &rect,
587
const QwtScaleMap map[axisCnt],
588
const QwtPlotPrintFilter &pfilter) const
590
const QwtPlotItemList& itmList = itemList();
591
for ( QwtPlotItemIterator it = itmList.begin();
592
it != itmList.end(); ++it )
594
QwtPlotItem *item = *it;
595
if ( item && item->isVisible() )
597
if ( !(pfilter.options() & QwtPlotPrintFilter::PrintGrid)
598
&& item->rtti() == QwtPlotItem::Rtti_PlotGrid )
605
#if QT_VERSION >= 0x040000
606
painter->setRenderHint(QPainter::Antialiasing,
607
item->testRenderHint(QwtPlotItem::RenderAntialiased) );
611
map[item->xAxis()], map[item->yAxis()],
621
\return Map for the axis on the canvas. With this map pixel coordinates can
622
translated to plot coordinates and vice versa.
623
\sa QwtScaleMap, QwtPlot::transform, QwtPlot::invTransform
626
QwtScaleMap QwtPlot::canvasMap(int axisId) const
629
if ( !d_data->canvas )
632
map.setTransformation(axisScaleEngine(axisId)->transformation());
634
const QwtScaleDiv *sd = axisScaleDiv(axisId);
635
map.setScaleInterval(sd->lBound(), sd->hBound());
637
if ( axisEnabled(axisId) )
639
const QwtScaleWidget *s = axisWidget(axisId);
640
if ( axisId == yLeft || axisId == yRight )
642
int y = s->y() + s->startBorderDist() - d_data->canvas->y();
643
int h = s->height() - s->startBorderDist() - s->endBorderDist();
644
map.setPaintInterval(y + h - 1, y);
648
int x = s->x() + s->startBorderDist() - d_data->canvas->x();
649
int w = s->width() - s->startBorderDist() - s->endBorderDist();
650
map.setPaintInterval(x, x + w - 1);
655
const int margin = plotLayout()->canvasMargin(axisId);
657
const QRect &canvasRect = d_data->canvas->contentsRect();
658
if ( axisId == yLeft || axisId == yRight )
660
map.setPaintInterval(canvasRect.bottom() - margin,
661
canvasRect.top() + margin);
665
map.setPaintInterval(canvasRect.left() + margin,
666
canvasRect.right() - margin);
673
Change the margin of the plot. The margin is the space
674
around all components.
676
\param margin new margin
677
\sa QwtPlotLayout::setMargin(), QwtPlot::margin(), QwtPlot::plotLayout()
679
void QwtPlot::setMargin(int margin)
684
if ( margin != d_data->layout->margin() )
686
d_data->layout->setMargin(margin);
693
\sa QwtPlot::setMargin(), QwtPlotLayout::margin(), QwtPlot::plotLayout()
695
int QwtPlot::margin() const
697
return d_data->layout->margin();
701
\brief Change the background of the plotting area
703
Sets c to QColorGroup::Background of all colorgroups of
704
the palette of the canvas. Using canvas()->setPalette()
705
is a more powerful way to set these colors.
706
\param c new background color
708
void QwtPlot::setCanvasBackground(const QColor &c)
710
QPalette p = d_data->canvas->palette();
712
for ( int i = 0; i < QPalette::NColorGroups; i++ )
714
#if QT_VERSION < 0x040000
715
p.setColor((QPalette::ColorGroup)i, QColorGroup::Background, c);
717
p.setColor((QPalette::ColorGroup)i, QPalette::Background, c);
721
canvas()->setPalette(p);
725
Nothing else than: canvas()->palette().color(
726
QPalette::Normal, QColorGroup::Background);
728
\return the background color of the plotting area.
730
const QColor & QwtPlot::canvasBackground() const
732
#if QT_VERSION < 0x040000
733
return canvas()->palette().color(
734
QPalette::Normal, QColorGroup::Background);
736
return canvas()->palette().color(
737
QPalette::Normal, QPalette::Background);
742
\brief Change the border width of the plotting area
743
Nothing else than canvas()->setLineWidth(w),
744
left for compatibility only.
745
\param w new border width
747
void QwtPlot::setCanvasLineWidth(int w)
749
canvas()->setLineWidth(w);
754
Nothing else than: canvas()->lineWidth(),
755
left for compatibility only.
756
\return the border width of the plotting area
758
int QwtPlot::canvasLineWidth() const
760
return canvas()->lineWidth();
764
\return \c true if the specified axis exists, otherwise \c false
765
\param axisId axis index
767
bool QwtPlot::axisValid(int axisId)
769
return ((axisId >= QwtPlot::yLeft) && (axisId < QwtPlot::axisCnt));
773
Called internally when the legend has been clicked on.
774
Emits a legendClicked() signal.
777
void QwtPlot::legendItemClicked()
779
if ( d_data->legend && sender()->isWidgetType() )
781
QwtPlotItem *plotItem = d_data->legend->find((QWidget *)sender());
783
emit legendClicked(plotItem);
787
void QwtPlot::legendItemChecked(bool on)
789
if ( d_data->legend && sender()->isWidgetType() )
791
QwtPlotItem *plotItem = d_data->legend->find((QWidget *)sender());
793
emit legendChecked(plotItem, on);
797
//! Remove all curves and markers
798
void QwtPlot::clear()
800
detachItems(QwtPlotItem::Rtti_PlotCurve);
801
detachItems(QwtPlotItem::Rtti_PlotMarker);
805
\brief Insert a legend
807
If the position legend is \c QwtPlot::LeftLegend or \c QwtPlot::RightLegend
808
the legend will be organized in one column from top to down.
809
Otherwise the legend items will be placed be placed in a table
810
with a best fit number of columns from left to right.
812
If pos != QwtPlot::ExternalLegend the plot widget will become
813
parent of the legend. It will be deleted when the plot is deleted,
814
or another legend is set with insertLegend().
817
\param pos The legend's position. For top/left position the number
818
of colums will be limited to 1, otherwise it will be set to
821
\param ratio Ratio between legend and the bounding rect
822
of title, canvas and axes. The legend will be shrinked
823
if it would need more space than the given ratio.
824
The ratio is limited to ]0.0 .. 1.0]. In case of <= 0.0
825
it will be reset to the default ratio.
826
The default vertical/horizontal ratio is 0.33/0.5.
828
\sa QwtPlotLayout::legendPosition(), QwtPlotLayout::setLegendPosition()
830
void QwtPlot::insertLegend(QwtLegend *legend,
831
QwtPlot::LegendPosition pos, double ratio)
833
d_data->layout->setLegendPosition(pos, ratio);
835
if ( legend != d_data->legend )
837
if ( d_data->legend && d_data->legend->parent() == this )
838
delete d_data->legend;
840
d_data->legend = legend;
842
if ( d_data->legend )
844
if ( pos != ExternalLegend )
846
if ( d_data->legend->parent() != this )
848
#if QT_VERSION < 0x040000
849
d_data->legend->reparent(this, QPoint(0, 0));
851
d_data->legend->setParent(this);
856
const QwtPlotItemList& itmList = itemList();
857
for ( QwtPlotItemIterator it = itmList.begin();
858
it != itmList.end(); ++it )
860
(*it)->updateLegend(d_data->legend);
863
QLayout *l = d_data->legend->contentsWidget()->layout();
864
if ( l && l->inherits("QwtDynGridLayout") )
866
QwtDynGridLayout *tl = (QwtDynGridLayout *)l;
867
switch(d_data->layout->legendPosition())
871
tl->setMaxCols(1); // 1 column: align vertical
875
tl->setMaxCols(0); // unlimited