Qwt User's Guide 6.3.0
Loading...
Searching...
No Matches
qwt_plot_legenditem.cpp
1/******************************************************************************
2 * Qwt Widget Library
3 * Copyright (C) 1997 Josef Wilgen
4 * Copyright (C) 2002 Uwe Rathmann
5 *
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 *****************************************************************************/
9
10#include "qwt_plot_legenditem.h"
11#include "qwt_dyngrid_layout.h"
12#include "qwt_text.h"
13#include "qwt_graphic.h"
14#include "qwt_legend_data.h"
15#include "qwt_math.h"
16
17#include <qlayoutitem.h>
18#include <qpen.h>
19#include <qbrush.h>
20#include <qpainter.h>
21
22namespace
23{
24 class LayoutItem QWT_FINAL : public QLayoutItem
25 {
26 public:
27 LayoutItem( const QwtPlotLegendItem*, const QwtPlotItem* );
28 virtual ~LayoutItem();
29
30 const QwtPlotItem* plotItem() const;
31
32 void setData( const QwtLegendData& );
33 const QwtLegendData& data() const;
34
35 virtual Qt::Orientations expandingDirections() const QWT_OVERRIDE;
36 virtual QRect geometry() const QWT_OVERRIDE;
37 virtual bool hasHeightForWidth() const QWT_OVERRIDE;
38 virtual int heightForWidth( int ) const QWT_OVERRIDE;
39 virtual bool isEmpty() const QWT_OVERRIDE;
40 virtual QSize maximumSize() const QWT_OVERRIDE;
41 virtual int minimumHeightForWidth( int ) const QWT_OVERRIDE;
42 virtual QSize minimumSize() const QWT_OVERRIDE;
43 virtual void setGeometry( const QRect& ) QWT_OVERRIDE;
44 virtual QSize sizeHint() const QWT_OVERRIDE;
45
46 private:
47
48 const QwtPlotLegendItem* m_legendItem;
49 const QwtPlotItem* m_plotItem;
50 QwtLegendData m_data;
51
52 QRect m_rect;
53 };
54
55 LayoutItem::LayoutItem(
56 const QwtPlotLegendItem* legendItem, const QwtPlotItem* plotItem )
57 : m_legendItem( legendItem )
58 , m_plotItem( plotItem)
59 {
60 }
61
62 LayoutItem::~LayoutItem()
63 {
64 }
65
66 const QwtPlotItem* LayoutItem::plotItem() const
67 {
68 return m_plotItem;
69 }
70
71 void LayoutItem::setData( const QwtLegendData& data )
72 {
73 m_data = data;
74 }
75
76 const QwtLegendData& LayoutItem::data() const
77 {
78 return m_data;
79 }
80
81 Qt::Orientations LayoutItem::expandingDirections() const
82 {
83 return Qt::Horizontal;
84 }
85
86 bool LayoutItem::hasHeightForWidth() const
87 {
88 return !m_data.title().isEmpty();
89 }
90
91 int LayoutItem::minimumHeightForWidth( int w ) const
92 {
93 return m_legendItem->heightForWidth( m_data, w );
94 }
95
96 int LayoutItem::heightForWidth( int w ) const
97 {
98 return m_legendItem->heightForWidth( m_data, w );
99 }
100
101 bool LayoutItem::isEmpty() const
102 {
103 return false;
104 }
105
106 QSize LayoutItem::maximumSize() const
107 {
108 return QSize( QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX );
109 }
110
111 QSize LayoutItem::minimumSize() const
112 {
113 return m_legendItem->minimumSize( m_data );
114 }
115
116 QSize LayoutItem::sizeHint() const
117 {
118 return minimumSize();
119 }
120
121 void LayoutItem::setGeometry( const QRect& rect )
122 {
123 m_rect = rect;
124 }
125
126 QRect LayoutItem::geometry() const
127 {
128 return m_rect;
129 }
130}
131
132class QwtPlotLegendItem::PrivateData
133{
134 public:
135 PrivateData()
136 : itemMargin( 4 )
137 , itemSpacing( 4 )
138 , borderRadius( 0.0 )
139 , borderPen( Qt::NoPen )
140 , backgroundBrush( Qt::NoBrush )
141 , backgroundMode( QwtPlotLegendItem::LegendBackground )
142 , canvasAlignment( Qt::AlignRight | Qt::AlignBottom )
143 {
144 canvasOffset[ 0 ] = canvasOffset[1] = 10;
145 layout = new QwtDynGridLayout();
146 layout->setMaxColumns( 2 );
147
148 layout->setSpacing( 0 );
149 layout->setContentsMargins( 0, 0, 0, 0 );
150 }
151
152 ~PrivateData()
153 {
154 delete layout;
155 }
156
157 QFont font;
158 QPen textPen;
159 int itemMargin;
160 int itemSpacing;
161
162 double borderRadius;
163 QPen borderPen;
164 QBrush backgroundBrush;
166
167 int canvasOffset[2];
168 Qt::Alignment canvasAlignment;
169
171 QwtDynGridLayout* layout;
172};
173
176 : QwtPlotItem( QwtText( "Legend" ) )
177{
178 m_data = new PrivateData;
179
181 setZ( 100.0 );
182}
183
186{
187 clearLegend();
188 delete m_data;
189}
190
196
210void QwtPlotLegendItem::setAlignmentInCanvas( Qt::Alignment alignment )
211{
212 if ( m_data->canvasAlignment != alignment )
213 {
214 m_data->canvasAlignment = alignment;
215 itemChanged();
216 }
217}
218
224{
225 return m_data->canvasAlignment;
226}
227
238void QwtPlotLegendItem::setMaxColumns( uint maxColumns )
239{
240 if ( maxColumns != m_data->layout->maxColumns() )
241 {
242 m_data->layout->setMaxColumns( maxColumns );
243 itemChanged();
244 }
245}
246
252{
253 return m_data->layout->maxColumns();
254}
255
265{
266 margin = qMax( margin, 0 );
267 if ( margin != this->margin() )
268 {
269 m_data->layout->setContentsMargins(
271
272 itemChanged();
273 }
274}
275
281{
282 int left;
283 m_data->layout->getContentsMargins( &left, NULL, NULL, NULL );
284
285 return left;
286}
287
295{
296 spacing = qMax( spacing, 0 );
297 if ( spacing != m_data->layout->spacing() )
298 {
299 m_data->layout->setSpacing( spacing );
300 itemChanged();
301 }
302}
303
309{
310 return m_data->layout->spacing();
311}
312
320{
321 margin = qMax( margin, 0 );
322 if ( margin != m_data->itemMargin )
323 {
324 m_data->itemMargin = margin;
325
326 m_data->layout->invalidate();
327 itemChanged();
328 }
329}
330
336{
337 return m_data->itemMargin;
338}
339
347{
348 spacing = qMax( spacing, 0 );
349 if ( spacing != m_data->itemSpacing )
350 {
351 m_data->itemSpacing = spacing;
352
353 m_data->layout->invalidate();
354 itemChanged();
355 }
356
357}
358
364{
365 return m_data->itemSpacing;
366}
367
374void QwtPlotLegendItem::setFont( const QFont& font )
375{
376 if ( font != m_data->font )
377 {
378 m_data->font = font;
379
380 m_data->layout->invalidate();
381 itemChanged();
382 }
383}
384
390{
391 return m_data->font;
392}
393
406 Qt::Orientations orientations, int numPixels )
407{
408 if ( numPixels < 0 )
409 numPixels = -1;
410
411 bool isChanged = false;
412
413 int* offset = m_data->canvasOffset;
414
415 if ( orientations & Qt::Horizontal )
416 {
417 if ( numPixels != offset[0] )
418 {
419 offset[0] = numPixels;
420 isChanged = true;
421 }
422 }
423
424 if ( orientations & Qt::Vertical )
425 {
426 if ( numPixels != offset[1] )
427 {
428 offset[1] = numPixels;
429 isChanged = true;
430 }
431 }
432
433 if ( isChanged )
434 itemChanged();
435}
436
445 Qt::Orientation orientation ) const
446{
447 const int index = ( orientation == Qt::Vertical ) ? 1 : 0;
448 return m_data->canvasOffset[index];
449}
450
458{
459 radius = qwtMaxF( 0.0, radius );
460
461 if ( radius != m_data->borderRadius )
462 {
463 m_data->borderRadius = radius;
464 itemChanged();
465 }
466}
467
473{
474 return m_data->borderRadius;
475}
476
483void QwtPlotLegendItem::setBorderPen( const QPen& pen )
484{
485 if ( m_data->borderPen != pen )
486 {
487 m_data->borderPen = pen;
488 itemChanged();
489 }
490}
491
497{
498 return m_data->borderPen;
499}
500
509void QwtPlotLegendItem::setBackgroundBrush( const QBrush& brush )
510{
511 if ( m_data->backgroundBrush != brush )
512 {
513 m_data->backgroundBrush = brush;
514 itemChanged();
515 }
516}
517
523{
524 return m_data->backgroundBrush;
525}
526
538{
539 if ( mode != m_data->backgroundMode )
540 {
541 m_data->backgroundMode = mode;
542 itemChanged();
543 }
544}
545
551{
552 return m_data->backgroundMode;
553}
554
561void QwtPlotLegendItem::setTextPen( const QPen& pen )
562{
563 if ( m_data->textPen != pen )
564 {
565 m_data->textPen = pen;
566 itemChanged();
567 }
568}
569
575{
576 return m_data->textPen;
577}
578
587void QwtPlotLegendItem::draw( QPainter* painter,
588 const QwtScaleMap& xMap, const QwtScaleMap& yMap,
589 const QRectF& canvasRect ) const
590{
591 Q_UNUSED( xMap );
592 Q_UNUSED( yMap );
593
594 m_data->layout->setGeometry( geometry( canvasRect ) );
595 if ( m_data->layout->geometry().isEmpty() )
596 {
597 // don't draw a legend when having no content
598 return;
599 }
600
601 if ( m_data->backgroundMode == QwtPlotLegendItem::LegendBackground )
602 drawBackground( painter, m_data->layout->geometry() );
603
604 for ( int i = 0; i < m_data->layout->count(); i++ )
605 {
606 const LayoutItem* layoutItem =
607 static_cast< LayoutItem* >( m_data->layout->itemAt( i ) );
608
609 if ( m_data->backgroundMode == QwtPlotLegendItem::ItemBackground )
610 drawBackground( painter, layoutItem->geometry() );
611
612 painter->save();
613
614 drawLegendData( painter, layoutItem->plotItem(),
615 layoutItem->data(), layoutItem->geometry() );
616
617 painter->restore();
618 }
619}
620
631 QPainter* painter, const QRectF& rect ) const
632{
633 painter->save();
634
635 painter->setPen( m_data->borderPen );
636 painter->setBrush( m_data->backgroundBrush );
637
638 const double radius = m_data->borderRadius;
639 painter->drawRoundedRect( rect, radius, radius );
640
641 painter->restore();
642}
643
650QRect QwtPlotLegendItem::geometry( const QRectF& canvasRect ) const
651{
652 QRect rect;
653 rect.setSize( m_data->layout->sizeHint() );
654
655 if ( m_data->canvasAlignment & Qt::AlignHCenter )
656 {
657 int x = qRound( canvasRect.center().x() );
658 rect.moveCenter( QPoint( x, rect.center().y() ) );
659 }
660 else if ( m_data->canvasAlignment & Qt::AlignRight )
661 {
662 const int offset = offsetInCanvas( Qt::Horizontal );
663 rect.moveRight( qwtFloor( canvasRect.right() - offset ) );
664 }
665 else
666 {
667 const int offset = offsetInCanvas( Qt::Horizontal );
668 rect.moveLeft( qwtCeil( canvasRect.left() + offset ) );
669 }
670
671 if ( m_data->canvasAlignment & Qt::AlignVCenter )
672 {
673 int y = qRound( canvasRect.center().y() );
674 rect.moveCenter( QPoint( rect.center().x(), y ) );
675 }
676 else if ( m_data->canvasAlignment & Qt::AlignBottom )
677 {
678 const int offset = offsetInCanvas( Qt::Vertical );
679 rect.moveBottom( qwtFloor( canvasRect.bottom() - offset ) );
680 }
681 else
682 {
683 const int offset = offsetInCanvas( Qt::Vertical );
684 rect.moveTop( qwtCeil( canvasRect.top() + offset ) );
685 }
686
687 return rect;
688}
689
698 const QList< QwtLegendData >& data )
699{
700 if ( plotItem == NULL )
701 return;
702
703 QList< LayoutItem* > layoutItems;
704
706 m_data->map.constFind( plotItem );
707 if ( it != m_data->map.constEnd() )
708 layoutItems = it.value();
709
710 bool changed = false;
711
712 if ( data.size() != layoutItems.size() )
713 {
714 changed = true;
715
716 for ( int i = 0; i < layoutItems.size(); i++ )
717 {
718 m_data->layout->removeItem( layoutItems[i] );
719 delete layoutItems[i];
720 }
721 layoutItems.clear();
722
723 if ( it != m_data->map.constEnd() )
724 m_data->map.remove( plotItem );
725
726 if ( !data.isEmpty() )
727 {
728 layoutItems.reserve( data.size() );
729
730 for ( int i = 0; i < data.size(); i++ )
731 {
732 LayoutItem* layoutItem =
733 new LayoutItem( this, plotItem );
734 m_data->layout->addItem( layoutItem );
735 layoutItems += layoutItem;
736 }
737
738 m_data->map.insert( plotItem, layoutItems );
739 }
740 }
741
742 for ( int i = 0; i < data.size(); i++ )
743 {
744 if ( layoutItems[i]->data().values() != data[i].values() )
745 {
746 layoutItems[i]->setData( data[i] );
747 changed = true;
748 }
749 }
750
751 if ( changed )
752 {
753 m_data->layout->invalidate();
754 itemChanged();
755 }
756}
757
760{
761 if ( !m_data->map.isEmpty() )
762 {
763 m_data->map.clear();
764
765 for ( int i = m_data->layout->count() - 1; i >= 0; i-- )
766 delete m_data->layout->takeAt( i );
767
768 itemChanged();
769 }
770}
771
780void QwtPlotLegendItem::drawLegendData( QPainter* painter,
781 const QwtPlotItem* plotItem, const QwtLegendData& data,
782 const QRectF& rect ) const
783{
784 Q_UNUSED( plotItem );
785
786 const int m = m_data->itemMargin;
787 const QRectF r = rect.toRect().adjusted( m, m, -m, -m );
788
789 painter->setClipRect( r, Qt::IntersectClip );
790
791 int titleOff = 0;
792
793 const QwtGraphic graphic = data.icon();
794 if ( !graphic.isEmpty() )
795 {
796 QRectF iconRect( r.topLeft(), graphic.defaultSize() );
797
798 iconRect.moveCenter(
799 QPoint( iconRect.center().x(), rect.center().y() ) );
800
801 graphic.render( painter, iconRect, Qt::KeepAspectRatio );
802
803 titleOff += iconRect.width() + m_data->itemSpacing;
804 }
805
806 const QwtText text = data.title();
807 if ( !text.isEmpty() )
808 {
809 painter->setPen( textPen() );
810 painter->setFont( font() );
811
812 const QRectF textRect = r.adjusted( titleOff, 0, 0, 0 );
813 text.draw( painter, textRect );
814 }
815}
816
824{
825 QSize size( 2 * m_data->itemMargin, 2 * m_data->itemMargin );
826
827 if ( !data.isValid() )
828 return size;
829
830 const QwtGraphic graphic = data.icon();
831 const QwtText text = data.title();
832
833 int w = 0;
834 int h = 0;
835
836 if ( !graphic.isNull() )
837 {
838 w = graphic.width();
839 h = graphic.height();
840 }
841
842 if ( !text.isEmpty() )
843 {
844 const QSizeF sz = text.textSize( font() );
845
846 w += qwtCeil( sz.width() );
847 h = qMax( h, qwtCeil( sz.height() ) );
848 }
849
850 if ( graphic.width() > 0 && !text.isEmpty() )
851 w += m_data->itemSpacing;
852
853 size += QSize( w, h );
854 return size;
855}
856
863 const QwtLegendData& data, int width ) const
864{
865 width -= 2 * m_data->itemMargin;
866
867 const QwtGraphic graphic = data.icon();
868 const QwtText text = data.title();
869
870 if ( text.isEmpty() )
871 return graphic.height();
872
873 if ( graphic.width() > 0 )
874 width -= graphic.width() + m_data->itemSpacing;
875
876 int h = text.heightForWidth( width, font() );
877 h += 2 * m_data->itemMargin;
878
879 return qMax( graphic.height(), h );
880}
881
887{
888 return m_data->map.keys();
889}
890
896 const QwtPlotItem* plotItem ) const
897{
898 QList< LayoutItem* > layoutItems;
899
901 m_data->map.constFind( plotItem );
902 if ( it != m_data->map.constEnd() )
903 layoutItems = it.value();
904
905 QList< QRect > geometries;
906 geometries.reserve(layoutItems.size() );
907
908 for ( int i = 0; i < layoutItems.size(); i++ )
909 geometries += layoutItems[i]->geometry();
910
911 return geometries;
912}
The QwtDynGridLayout class lays out widgets in a grid, adjusting the number of columns and rows to th...
virtual QLayoutItem * itemAt(int index) const override
virtual bool isEmpty() const override
virtual QLayoutItem * takeAt(int index) override
virtual QSize sizeHint() const override
uint maxColumns() const
Return the upper limit for the number of columns.
void setMaxColumns(uint maxColumns)
virtual void addItem(QLayoutItem *) override
Add an item to the next free position.
virtual void setGeometry(const QRect &) override
virtual int count() const override
virtual void invalidate() override
Invalidate all internal caches.
A paint device for scalable graphics.
Definition qwt_graphic.h:76
bool isEmpty() const
bool isNull() const
QSizeF defaultSize() const
Default size.
void render(QPainter *) const
Replay all recorded painter commands.
Attributes of an entry on a legend.
bool isValid() const
QwtGraphic icon() const
QwtText title() const
Base class for items on the plot canvas.
void setZ(double z)
Set the z value.
@ Rtti_PlotLegend
For QwtPlotLegendItem.
void setItemInterest(ItemInterest, bool on=true)
virtual void itemChanged()
A class which draws a legend inside the plot canvas.
void setOffsetInCanvas(Qt::Orientations, int numPixels)
Set the distance between the legend and the canvas border.
BackgroundMode
Background mode.
@ LegendBackground
The legend has a background.
@ ItemBackground
Each item has a background.
int offsetInCanvas(Qt::Orientation) const
virtual QRect geometry(const QRectF &canvasRect) const
BackgroundMode backgroundMode() const
void setBackgroundMode(BackgroundMode)
Set the background mode.
virtual void draw(QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect) const override
virtual void updateLegend(const QwtPlotItem *, const QList< QwtLegendData > &) override
QBrush backgroundBrush() const
void setAlignmentInCanvas(Qt::Alignment)
Set the alignmnet.
void setMargin(int)
Set the margin around legend items.
QwtPlotLegendItem()
Constructor.
Qt::Alignment alignmentInCanvas() const
virtual void drawLegendData(QPainter *, const QwtPlotItem *, const QwtLegendData &, const QRectF &) const
QList< QRect > legendGeometries(const QwtPlotItem *) const
void setBackgroundBrush(const QBrush &)
Set the background brush.
QList< const QwtPlotItem * > plotItems() const
void setMaxColumns(uint)
Limit the number of columns.
void setBorderPen(const QPen &)
void setSpacing(int)
Set the spacing between the legend items.
virtual int heightForWidth(const QwtLegendData &, int width) const
void setFont(const QFont &)
virtual QSize minimumSize(const QwtLegendData &) const
virtual void drawBackground(QPainter *, const QRectF &rect) const
virtual int rtti() const override
void clearLegend()
Remove all items from the legend.
virtual ~QwtPlotLegendItem()
Destructor.
void setTextPen(const QPen &)
Set the pen for drawing text labels.
A scale map.
A class representing a text.
Definition qwt_text.h:52
QSizeF textSize() const
Definition qwt_text.cpp:570
bool isEmpty() const
Definition qwt_text.cpp:739
void setFont(const QFont &)
Definition qwt_text.cpp:329
void draw(QPainter *painter, const QRectF &rect) const
Definition qwt_text.cpp:615
double heightForWidth(double width) const
Definition qwt_text.cpp:522