1 /*
2  * Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB.  All rights reserved.
3  *
4  * This file is part of the KD Chart library.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef KCHARTLAYOUTITEMS_H
21 #define KCHARTLAYOUTITEMS_H
22 
23 #include <QBrush>
24 #include <QFont>
25 #include <QFontMetricsF>
26 #include <QLayout>
27 #include <QLayoutItem>
28 #include <QPen>
29 
30 #include "KChartTextAttributes.h"
31 #include "KChartMarkerAttributes.h"
32 
33 QT_BEGIN_NAMESPACE
34 class QPainter;
35 class KTextDocument;
36 QT_END_NAMESPACE
37 
38 // TODO remove
39 QRectF rotatedRect( const QRectF& pt, qreal rotation );
40 
41 namespace KChart {
42     class AbstractDiagram;
43     class PaintContext;
44 
45     /**
46      * Base class for all layout items of KChart
47      * \internal
48      */
49     class KCHART_EXPORT AbstractLayoutItem : public QLayoutItem
50     {
51     public:
52         AbstractLayoutItem( Qt::Alignment itemAlignment = Qt::Alignment() ) :
QLayoutItem(itemAlignment)53             QLayoutItem( itemAlignment ),
54             mParent( nullptr ),
55             mParentLayout( nullptr ) {}
56 
57         /**
58          * Default impl: just call paint.
59          *
60          * Derived classes like KChart::AbstractArea are providing
61          * additional action here.
62          */
63         virtual void paintAll( QPainter& painter );
64 
65         virtual void paint( QPainter* ) = 0;
66 
67 
68         /**
69           * Default impl: Paint the complete item using its layouted position and size.
70           */
71         virtual void paintCtx( PaintContext* context );
72 
73         /**
74             Inform the item about its widget: This enables the item,
75             to trigger that widget's update, whenever the size of the item's
76             contents has changed.
77 
78             Thus, you need to call setParentWidget on every item, that
79             has a non-fixed size.
80           */
81         virtual void setParentWidget( QWidget* widget );
82 
83         /**
84             Report changed size hint: ask the parent widget to recalculate the layout.
85           */
86         virtual void sizeHintChanged() const;
87 
setParentLayout(QLayout * lay)88         void setParentLayout( QLayout* lay )
89         {
90             mParentLayout = lay;
91         }
parentLayout()92         QLayout* parentLayout()
93         {
94             return mParentLayout;
95         }
removeFromParentLayout()96         void removeFromParentLayout()
97         {
98             if ( mParentLayout ) {
99                 if ( widget() )
100                     mParentLayout->removeWidget( widget() );
101                 else
102                     mParentLayout->removeItem( this );
103             }
104         }
105     protected:
106         QWidget* mParent;
107         QLayout* mParentLayout;
108     };
109 
110     /**
111      * Layout item showing a text
112      *\internal
113      */
114     class KCHART_EXPORT TextLayoutItem : public AbstractLayoutItem
115     {
116     public:
117         TextLayoutItem();
118         TextLayoutItem( const QString& text,
119                         const TextAttributes& attributes,
120                         const QObject* autoReferenceArea,
121                         KChartEnums::MeasureOrientation autoReferenceOrientation,
122                         Qt::Alignment alignment = Qt::Alignment() );
123 
124         void setAutoReferenceArea( const QObject* area );
125         const QObject* autoReferenceArea() const;
126 
127         void setText(const QString & text);
128         QString text() const;
129 
130         void setTextAlignment( Qt::Alignment );
131         Qt::Alignment textAlignment() const;
132 
133         /**
134           \brief Use this to specify the text attributes to be used for this item.
135 
136           \sa textAttributes
137         */
138         void setTextAttributes( const TextAttributes& a );
139 
140         /**
141           Returns the text attributes to be used for this item.
142 
143           \sa setTextAttributes
144         */
145         TextAttributes textAttributes() const;
146 
147         /** pure virtual in QLayoutItem */
148         bool isEmpty() const override;
149         /** pure virtual in QLayoutItem */
150         Qt::Orientations expandingDirections() const override;
151         /** pure virtual in QLayoutItem */
152         QSize maximumSize() const override;
153         /** pure virtual in QLayoutItem */
154         QSize minimumSize() const override;
155         /** pure virtual in QLayoutItem */
156         QSize sizeHint() const override;
157         /** pure virtual in QLayoutItem */
158         void setGeometry( const QRect& r ) override;
159         /** pure virtual in QLayoutItem */
160         QRect geometry() const override;
161 
162         virtual int marginWidth() const;
163 
164         virtual QSize sizeHintUnrotated() const;
165 
166         virtual bool intersects( const TextLayoutItem& other, const QPointF& myPos, const QPointF& otherPos ) const;
167         virtual bool intersects( const TextLayoutItem& other, const QPoint& myPos, const QPoint& otherPos ) const;
168 
169         virtual qreal realFontSize() const;
170         virtual QFont realFont() const;
171 
172         void paint( QPainter* ) override;
173 
174         QPolygon boundingPolygon() const;
175     private:
176         bool maybeUpdateRealFont() const;
177         QSize unrotatedSizeHint( const QFont& fnt = QFont() ) const;
178         QSize unrotatedTextSize( QFont fnt = QFont() ) const;
179         QSize calcSizeHint( const QFont& font ) const;
180         int marginWidth( const QSize& textSize ) const;
181 
182         qreal fitFontSizeToGeometry() const;
183 
184         QRect mRect;
185         QString mText;
186         Qt::Alignment mTextAlignment;
187         TextAttributes mAttributes;
188         const QObject* mAutoReferenceArea;
189         KChartEnums::MeasureOrientation mAutoReferenceOrientation;
190         mutable QSize cachedSizeHint;
191         mutable QPolygon mCachedBoundingPolygon;
192         mutable qreal cachedFontSize;
193         mutable QFont cachedFont;
194     };
195 
196     class KCHART_EXPORT TextBubbleLayoutItem : public AbstractLayoutItem
197     {
198     public:
199         TextBubbleLayoutItem();
200         TextBubbleLayoutItem( const QString& text,
201                               const TextAttributes& attributes,
202                               const QObject* autoReferenceArea,
203                               KChartEnums::MeasureOrientation autoReferenceOrientation,
204                               Qt::Alignment alignment = Qt::Alignment() );
205 
206         ~TextBubbleLayoutItem();
207 
208         void setAutoReferenceArea( const QObject* area );
209         const QObject* autoReferenceArea() const;
210 
211         void setText(const QString & text);
212         QString text() const;
213 
214         void setTextAttributes( const TextAttributes& a );
215         TextAttributes textAttributes() const;
216 
217         /** pure virtual in QLayoutItem */
218         bool isEmpty() const override;
219         /** pure virtual in QLayoutItem */
220         Qt::Orientations expandingDirections() const override;
221         /** pure virtual in QLayoutItem */
222         QSize maximumSize() const override;
223         /** pure virtual in QLayoutItem */
224         QSize minimumSize() const override;
225         /** pure virtual in QLayoutItem */
226         QSize sizeHint() const override;
227         /** pure virtual in QLayoutItem */
228         void setGeometry( const QRect& r ) override;
229         /** pure virtual in QLayoutItem */
230         QRect geometry() const override;
231 
232         void paint( QPainter* painter ) override;
233 
234     protected:
235         int borderWidth() const;
236 
237     private:
238         TextLayoutItem* const m_text;
239     };
240 
241     /**
242      * Layout item showing a data point marker
243      * \internal
244      */
245     class KCHART_EXPORT MarkerLayoutItem : public AbstractLayoutItem
246     {
247         public:
248             MarkerLayoutItem( AbstractDiagram* diagram,
249                               const MarkerAttributes& marker,
250                               const QBrush& brush,
251                               const QPen& pen,
252                               Qt::Alignment alignment = Qt::Alignment() );
253 
254             Qt::Orientations expandingDirections() const override;
255             QRect geometry() const override;
256             bool isEmpty() const override;
257             QSize maximumSize() const override;
258             QSize minimumSize() const override;
259             void setGeometry( const QRect& r ) override;
260             QSize sizeHint() const override;
261 
262             void paint( QPainter* ) override;
263 
264             static void paintIntoRect(
265                     QPainter* painter,
266                     const QRect& rect,
267                     AbstractDiagram* diagram,
268                     const MarkerAttributes& marker,
269                     const QBrush& brush,
270                     const QPen& pen );
271 
272         private:
273             AbstractDiagram* mDiagram;
274             QRect mRect;
275             MarkerAttributes mMarker;
276             QBrush mBrush;
277             QPen mPen;
278     };
279 
280     /**
281      * Layout item showing a coloured line
282      * \internal
283      */
284     class KCHART_EXPORT LineLayoutItem : public AbstractLayoutItem
285     {
286         public:
287             LineLayoutItem( AbstractDiagram* diagram,
288                             int length,
289                             const QPen& pen,
290                             Qt::Alignment mLegendLineSymbolAlignment,
291                             Qt::Alignment alignment = Qt::Alignment() );
292 
293             Qt::Orientations expandingDirections() const override;
294             QRect geometry() const override;
295             bool isEmpty() const override;
296             QSize maximumSize() const override;
297             QSize minimumSize() const override;
298             void setGeometry( const QRect& r ) override;
299             QSize sizeHint() const override;
300 
301             void setLegendLineSymbolAlignment(Qt::Alignment legendLineSymbolAlignment);
302             virtual Qt::Alignment legendLineSymbolAlignment() const;
303 
304             void paint( QPainter* ) override;
305 
306             static void paintIntoRect(
307                     QPainter* painter,
308                     const QRect& rect,
309                     const QPen& pen,
310                     Qt::Alignment lineAlignment);
311 
312         private:
313             AbstractDiagram* mDiagram;  //TODO: not used. remove it
314             int mLength;
315             QPen mPen;
316             QRect mRect;
317             Qt::Alignment mLegendLineSymbolAlignment;
318     };
319 
320     /**
321      * Layout item showing a coloured line and a data point marker
322      * \internal
323      */
324     class KCHART_EXPORT LineWithMarkerLayoutItem : public AbstractLayoutItem
325     {
326         public:
327             LineWithMarkerLayoutItem( AbstractDiagram* diagram,
328                                       int lineLength,
329                                       const QPen& linePen,
330                                       int markerOffs,
331                                       const MarkerAttributes& marker,
332                                       const QBrush& markerBrush,
333                                       const QPen& markerPen,
334                                       Qt::Alignment alignment = Qt::Alignment() );
335 
336             Qt::Orientations expandingDirections() const override;
337             QRect geometry() const override;
338             bool isEmpty() const override;
339             QSize maximumSize() const override;
340             QSize minimumSize() const override;
341             void setGeometry( const QRect& r ) override;
342             QSize sizeHint() const override;
343 
344             void paint( QPainter* ) override;
345 
346         private:
347             AbstractDiagram* mDiagram;
348             QRect mRect;
349             int mLineLength;
350             QPen mLinePen;
351             int mMarkerOffs;
352             MarkerAttributes mMarker;
353             QBrush mMarkerBrush;
354             QPen mMarkerPen;
355     };
356 
357 
358     /**
359      * Layout item showing a horizontal line
360      * \internal
361      */
362     class KCHART_EXPORT HorizontalLineLayoutItem : public AbstractLayoutItem
363     {
364     public:
365         HorizontalLineLayoutItem();
366 
367         Qt::Orientations expandingDirections() const override;
368         QRect geometry() const override;
369         bool isEmpty() const override;
370         QSize maximumSize() const override;
371         QSize minimumSize() const override;
372         void setGeometry( const QRect& r ) override;
373         QSize sizeHint() const override;
374 
375         void paint( QPainter* ) override;
376 
377     private:
378         QRect mRect;
379     };
380 
381     /**
382      * Layout item showing a vertial line
383      * \internal
384      */
385     class KCHART_EXPORT VerticalLineLayoutItem : public AbstractLayoutItem
386     {
387         public:
388             VerticalLineLayoutItem();
389 
390             Qt::Orientations expandingDirections() const override;
391             QRect geometry() const override;
392             bool isEmpty() const override;
393             QSize maximumSize() const override;
394             QSize minimumSize() const override;
395             void setGeometry( const QRect& r ) override;
396             QSize sizeHint() const override;
397 
398             void paint( QPainter* ) override;
399 
400         private:
401             QRect mRect;
402     };
403 
404     /**
405      * @brief An empty layout item
406      * \internal
407      *
408      * The AutoSpacerLayoutItem is automatically put into each corner cell of
409      * the planeLayout grid: one of its reference-layouts is a QVBoxLayout (for
410      * the top, or bottom axes resp.), the other one is a QHBoxLayout (for the
411      * left/right sided axes).
412      *
413      * The spacer reserves enough space so all of the AbstractAreas contained
414      * in the two reference-layouts can display not only their in-bounds
415      * content but also their overlapping content reaching out of their area.
416      *
417      * KChart's layouting is applying this schema:
418 \verbatim
419     +------------------+-------------------------+-----------------+
420     | +--------------+ | +---------------------+ | +-------------+ |
421     | |              | | |  QVBoxLayout for    | | |             | |
422     | |     AUTO     | | |  the top axis/axes  | | |    AUTO     | |
423     | |    SPACER    | | +---------------------+ | |   SPACER    | |
424     | |     ITEM     | | |                     | | |    ITEM     | |
425     | |              | | |                     | | |             | |
426     | +--------------+ | +---------------------+ | +-------------+ |
427     +------------------+-------------------------+-----------------+
428     | +--------+-----+ | +---------------------+ | +-------+-----+ |
429     | |        |     | | |                     | | |       |     | |
430     | |        |     | | |                     | | |       |     | |
431     | | QHBox- |     | | |                     | | | Right |     | |
432     | | Layout |     | | |                     | | |       |     | |
433     | |        |     | | |                     | | | axes  |     | |
434     | | for    |     | | |                     | | |       |     | |
435     | |        |     | | |                     | | | layout|     | |
436     | | the    |     | | |      DIAGRAM(s)     | | |       |     | |
437     | |        |     | | |                     | | |       |     | |
438     | | left   |     | | |                     | | |       |     | |
439     | |        |     | | |                     | | |       |     | |
440     | | axis   |     | | |                     | | |       |     | |
441     | | or     |     | | |                     | | |       |     | |
442     | | axes   |     | | |                     | | |       |     | |
443     | |        |     | | |                     | | |       |     | |
444     | +--------+-----+ | +---------------------+ | +-------+-----+ |
445     +------------------+-------------------------+-----------------+
446     | +--------------+ | +---------------------+ | +-------------+ |
447     | |              | | |   QVBoxLayout for   | | |             | |
448     | |    AUTO      | | |   the bottom axes   | | |    AUTO     | |
449     | |   SPACER     | | +---------------------+ | |   SPACER    | |
450     | |    ITEM      | | |                     | | |    ITEM     | |
451     | |              | | |                     | | |             | |
452     | +--------------+ | +---------------------+ | +-------------+ |
453     +------------------+-------------------------+-----------------+
454 \endverbatim
455      *
456      * A typical use case is an Abscissa axis with long labels:
457 \verbatim
458     2 -|
459        |
460     1 -|
461        |
462     0 -+------------------------------------
463        |        |        |        |        |
464     Monday  Tuesday  Wednesday Thursday Friday
465 \endverbatim
466      * The last letters of the word "Friday" would have been
467      * cut off in previous versions of KChart - that is
468      * if you did not call KChart::Chart::setGlobalLeading().
469      *
470      * Now the word will be shown completely because there
471      * is an auto-spacer-item taking care for the additional
472      * space needed in the lower/right corner.
473      */
474     class KCHART_EXPORT AutoSpacerLayoutItem : public AbstractLayoutItem
475     {
476         public:
477             AutoSpacerLayoutItem(
478                     bool layoutIsAtTopPosition, QHBoxLayout *rightLeftLayout,
479                     bool layoutIsAtLeftPosition,  QVBoxLayout *topBottomLayout );
480 
481             Qt::Orientations expandingDirections() const override;
482             QRect geometry() const override;
483             bool isEmpty() const override;
484             QSize maximumSize() const override;
485             QSize minimumSize() const override;
486             void setGeometry( const QRect& r ) override;
487             QSize sizeHint() const override;
488 
489             void paint( QPainter* ) override;
490 
491         private:
492             QRect mRect;
493             bool mLayoutIsAtTopPosition;
494             QHBoxLayout *mRightLeftLayout;
495             bool mLayoutIsAtLeftPosition;
496             QVBoxLayout *mTopBottomLayout;
497 
498             mutable QBrush mCommonBrush;
499             mutable QSize mCachedSize;
500     };
501 
502 }
503 
504 #endif /* KCHARTLAYOUTITEMS_H */
505