KChart

KChartLayoutItems.cpp
1/*
2 * SPDX-FileCopyrightText: 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
3 *
4 * This file is part of the KD Chart library.
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9#include "KChartLayoutItems.h"
10
11#include "KTextDocument.h"
12#include "KChartAbstractArea.h"
13#include "KChartAbstractDiagram.h"
14#include "KChartBackgroundAttributes.h"
15#include "KChartFrameAttributes.h"
16#include "KChartPaintContext.h"
17#include "KChartPainterSaver_p.h"
18#include "KChartPrintingParameters.h"
19#include "KChartMath_p.h"
20
21#include <QTextCursor>
22#include <QTextBlockFormat>
23#include <QTextDocumentFragment>
24#include <QAbstractTextDocumentLayout>
25#include <QPainter>
26#include <QDebug>
27#include <QCoreApplication>
28#include <QApplication>
29#include <QStringList>
30#include <QStyle>
31
32
33//#define DEBUG_ITEMS_PAINT
34
36{
37 mParent = widget;
38}
39
41{
42 paint( &painter );
43}
44
46{
47 if ( context )
48 paint( context->painter() );
49}
50
52{
53 // This is exactly like what QWidget::updateGeometry does.
54// qDebug("KChart::AbstractLayoutItem::sizeHintChanged() called");
55 if ( mParent ) {
56 if ( mParent->layout() )
57 mParent->layout()->invalidate();
58 else
60 }
61}
62
63KChart::TextBubbleLayoutItem::TextBubbleLayoutItem( const QString& text,
64 const KChart::TextAttributes& attributes,
65 const QObject* area,
67 Qt::Alignment alignment )
68 : AbstractLayoutItem( alignment ),
69 m_text( new TextLayoutItem( text, attributes, area, orientation, alignment ) )
70{
71}
72
73KChart::TextBubbleLayoutItem::TextBubbleLayoutItem()
74 : AbstractLayoutItem( Qt::AlignLeft ),
75 m_text( new TextLayoutItem() )
76{
77}
78
79KChart::TextBubbleLayoutItem::~TextBubbleLayoutItem()
80{
81 delete m_text;
82}
83
84void KChart::TextBubbleLayoutItem::setAutoReferenceArea( const QObject* area )
85{
86 m_text->setAutoReferenceArea( area );
87}
88
89const QObject* KChart::TextBubbleLayoutItem::autoReferenceArea() const
90{
91 return m_text->autoReferenceArea();
92}
93
94void KChart::TextBubbleLayoutItem::setText( const QString& text )
95{
96 m_text->setText( text );
97}
98
99QString KChart::TextBubbleLayoutItem::text() const
100{
101 return m_text->text();
102}
103
104void KChart::TextBubbleLayoutItem::setTextAttributes( const TextAttributes& a )
105{
106 m_text->setTextAttributes( a );
107}
108
109KChart::TextAttributes KChart::TextBubbleLayoutItem::textAttributes() const
110{
111 return m_text->textAttributes();
112}
113
114bool KChart::TextBubbleLayoutItem::isEmpty() const
115{
116 return m_text->isEmpty();
117}
118
119Qt::Orientations KChart::TextBubbleLayoutItem::expandingDirections() const
120{
121 return m_text->expandingDirections();
122}
123
124QSize KChart::TextBubbleLayoutItem::maximumSize() const
125{
126 const int border = borderWidth();
127 return m_text->maximumSize() + QSize( 2 * border, 2 * border );
128}
129
130QSize KChart::TextBubbleLayoutItem::minimumSize() const
131{
132 const int border = borderWidth();
133 return m_text->minimumSize() + QSize( 2 * border, 2 * border );
134}
135
136QSize KChart::TextBubbleLayoutItem::sizeHint() const
137{
138 const int border = borderWidth();
139 return m_text->sizeHint() + QSize( 2 * border, 2 * border );
140}
141
142void KChart::TextBubbleLayoutItem::setGeometry( const QRect& r )
143{
144 const int border = borderWidth();
145 m_text->setGeometry( r.adjusted( border, border, -border, -border ) );
146}
147
148QRect KChart::TextBubbleLayoutItem::geometry() const
149{
150 const int border = borderWidth();
151 return m_text->geometry().adjusted( -border, -border, border, border );
152}
153
154void KChart::TextBubbleLayoutItem::paint( QPainter* painter )
155{
156 const QPen oldPen = painter->pen();
157 const QBrush oldBrush = painter->brush();
158 painter->setPen( Qt::black );
159 painter->setBrush( QColor( 255, 255, 220 ) );
160 painter->drawRoundedRect( geometry(), 10, Qt::RelativeSize );
161 painter->setPen( oldPen );
162 painter->setBrush( oldBrush );
163 m_text->paint( painter );
164}
165
166int KChart::TextBubbleLayoutItem::borderWidth() const
167{
168 return 1;
169}
170
171KChart::TextLayoutItem::TextLayoutItem( const QString& text,
172 const KChart::TextAttributes& attributes,
173 const QObject* area,
175 Qt::Alignment alignment )
176 : AbstractLayoutItem( alignment )
177 , mText( text )
178 , mTextAlignment( alignment )
179 , mAttributes( attributes )
180 , mAutoReferenceArea( area )
181 , mAutoReferenceOrientation( orientation )
182 , cachedSizeHint() // default this to invalid to force just-in-time calculation before first use of sizeHint()
183 , cachedFontSize( 0.0 )
184 , cachedFont( mAttributes.font() )
185{
186}
187
188KChart::TextLayoutItem::TextLayoutItem()
189 : AbstractLayoutItem( Qt::AlignLeft )
190 , mText()
191 , mTextAlignment( Qt::AlignLeft )
192 , mAttributes()
193 , mAutoReferenceArea( nullptr )
194 , mAutoReferenceOrientation( KChartEnums::MeasureOrientationHorizontal )
195 , cachedSizeHint() // default this to invalid to force just-in-time calculation before first use of sizeHint()
196 , cachedFontSize( 0.0 )
197 , cachedFont( mAttributes.font() )
198{
199
200}
201
202void KChart::TextLayoutItem::setAutoReferenceArea( const QObject* area )
203{
204 mAutoReferenceArea = area;
205 cachedSizeHint = QSize();
206 sizeHint();
207}
208
209const QObject* KChart::TextLayoutItem::autoReferenceArea() const
210{
211 return mAutoReferenceArea;
212}
213
214void KChart::TextLayoutItem::setText(const QString & text)
215{
216 mText = text;
217 cachedSizeHint = QSize();
218 sizeHint();
219 if ( mParent )
220 mParent->update();
221}
222
223QString KChart::TextLayoutItem::text() const
224{
225 return mText;
226}
227
228void KChart::TextLayoutItem::setTextAlignment( Qt::Alignment alignment)
229{
230 if ( mTextAlignment == alignment )
231 return;
232 mTextAlignment = alignment;
233 if ( mParent )
234 mParent->update();
235}
236
237Qt::Alignment KChart::TextLayoutItem::textAlignment() const
238{
239 return mTextAlignment;
240}
241
243{
244 mAttributes = a;
245 cachedFont = a.font();
246 cachedSizeHint = QSize(); // invalidate size hint
247 sizeHint();
248 if ( mParent )
249 mParent->update();
250}
251
253{
254 return mAttributes;
255}
256
257
259{
260 return Qt::Orientations(); // Grow neither vertically nor horizontally
261}
262
264{
265 return mRect;
266}
267
269{
270 return false; // never empty, otherwise the layout item would not exist
271}
272
274{
275 return sizeHint(); // PENDING(kalle) Review, quite inflexible
276}
277
279{
280 return sizeHint(); // PENDING(kalle) Review, quite inflexible
281}
282
284{
285 mRect = r;
286}
287
288// returns the bounding box of rect rotated around its center
289QRectF rotatedRect( const QRectF& rect, qreal rotation )
290{
291 QTransform t;
292 QPointF center = rect.center();
293 t.translate( center.x(), center.y() );
294 t.rotate( rotation );
295 t.translate( -center.x(), -center.y() );
296 return t.mapRect( rect );
297}
298
299qreal KChart::TextLayoutItem::fitFontSizeToGeometry() const
300{
301 QFont f = realFont();
302 const qreal origResult = f.pointSizeF();
303 qreal result = origResult;
304 const qreal minSize = mAttributes.minimalFontSize().value();
305 const QSize mySize = geometry().size();
306 if ( mySize.isNull() ) {
307 return result;
308 }
309
310 QFontMetrics fm( f );
311 while ( true ) {
312 const QSizeF textSize = rotatedRect( fm.boundingRect( mText ), mAttributes.rotation() ).normalized().size();
313
314 if ( textSize.height() <= mySize.height() && textSize.width() <= mySize.width() ) {
315 return result;
316 }
317
318 result -= 0.5;
319 if ( minSize > 0 && result < minSize ) {
320 return result + 0.5;
321 } else if ( result <= 0.0 ) {
322 return origResult;
323 }
324 f.setPointSizeF( result );
325 fm = QFontMetrics( f );
326 }
327}
328
329qreal KChart::TextLayoutItem::realFontSize() const
330{
331 return mAttributes.calculatedFontSize( mAutoReferenceArea, mAutoReferenceOrientation );
332}
333
334bool KChart::TextLayoutItem::maybeUpdateRealFont() const
335{
336 const qreal fntSiz = realFontSize();
337 const bool doUpdate = !cachedSizeHint.isValid() || cachedFontSize != fntSiz;
338
339 if ( doUpdate && fntSiz > 0.0 ) {
340 cachedFontSize = fntSiz;
341 cachedFont.setPointSizeF( fntSiz );
342 }
343 return doUpdate; // "didUpdate" by now
344}
345
346QFont KChart::TextLayoutItem::realFont() const
347{
348 maybeUpdateRealFont();
349 return cachedFont;
350}
351
352QPolygon KChart::TextLayoutItem::boundingPolygon() const
353{
354 // should probably call sizeHint() here, but that one is expensive (see TODO there)
355 return mCachedBoundingPolygon;
356}
357
358bool KChart::TextLayoutItem::intersects( const TextLayoutItem& other, const QPointF& myPos, const QPointF& otherPos ) const
359{
360 return intersects( other, myPos.toPoint(), otherPos.toPoint() );
361}
362
363bool KChart::TextLayoutItem::intersects( const TextLayoutItem& other, const QPoint& myPos, const QPoint& otherPos ) const
364{
365 QRegion myRegion( boundingPolygon().translated( myPos - otherPos ) );
366 QRegion otherRegion( other.boundingPolygon() );
367
368 return myRegion.intersects( otherRegion );
369}
370
372{
373 // ### we only really need to recalculate the size hint when mAttributes.rotation has *changed*
374 if ( maybeUpdateRealFont() || mAttributes.rotation() || !cachedSizeHint.isValid() ) {
375 const QSize newSizeHint( calcSizeHint( cachedFont ) );
376 Q_ASSERT( newSizeHint.isValid() );
377 if ( newSizeHint != cachedSizeHint ) {
378 cachedSizeHint = newSizeHint;
379 sizeHintChanged();
380 }
381 }
382 return cachedSizeHint;
383}
384
385QSize KChart::TextLayoutItem::sizeHintUnrotated() const
386{
387 maybeUpdateRealFont(); // make sure the cached font is up to date
388 return unrotatedSizeHint( cachedFont );
389}
390
391
392// PENDING(kalle) Support auto shrink
393
394
395QSize KChart::TextLayoutItem::unrotatedTextSize( QFont fnt ) const
396{
397 if ( fnt == QFont() ) {
398 fnt = realFont(); // this is the cached font in most cases
399 }
400
402 QRect veryLarge( 0, 0, 100000, 100000 );
403 // this overload of boundingRect() interprets \n as line breaks, not as regular characters.
404 return fm.boundingRect( veryLarge, Qt::AlignLeft | Qt::AlignTop, mText ).size().toSize();
405}
406
407int KChart::TextLayoutItem::marginWidth() const
408{
409 return marginWidth( unrotatedTextSize() );
410}
411
412int KChart::TextLayoutItem::marginWidth( const QSize& textSize ) const
413{
414 return qMin ( QApplication::style()->pixelMetric( QStyle::PM_ButtonMargin, nullptr, nullptr ),
415 // decrease frame size if the text is small
416 textSize.height() * 2 / 3 );
417}
418
419QSize KChart::TextLayoutItem::unrotatedSizeHint( const QFont& fnt ) const
420{
421 QSize ret = unrotatedTextSize( fnt );
422 const int margin = marginWidth( ret );
423 ret += QSize( margin, margin );
424 return ret;
425}
426
427QSize KChart::TextLayoutItem::calcSizeHint( const QFont& font ) const
428{
429 const QSize size = unrotatedSizeHint( font );
430 QPoint topLeft( -size.width() * 0.5, -size.height() * 0.5 );
431 if ( !mAttributes.rotation() ) {
432 mCachedBoundingPolygon.resize( 4 );
433 // using the same winding order as returned by QPolygon QTransform::mapToPolygon(const QRect&),
434 // which is: 0-1: top edge, 1-2: right edge, 2-3: bottom edge, 3-0: left edge (of input rect)
435 mCachedBoundingPolygon[ 0 ] = topLeft;
436 mCachedBoundingPolygon[ 1 ] = topLeft + QPoint( size.width(), 0 ); // top right
437 mCachedBoundingPolygon[ 2 ] = topLeft + QPoint( size.width(), size.height() ); // bottom right
438 mCachedBoundingPolygon[ 3 ] = topLeft + QPoint( 0, size.height() ); // bottom left
439 return size;
440 }
441
442 const QRect rect( topLeft, size );
443 QTransform t;
444 t.rotate( mAttributes.rotation() );
445 mCachedBoundingPolygon = t.mapToPolygon( rect );
446
447 return mCachedBoundingPolygon.boundingRect().size();
448}
449
450void KChart::TextLayoutItem::paint( QPainter* painter )
451{
452 if ( !mRect.isValid() ) {
453 return;
454 }
455 const PainterSaver painterSaver( painter );
456 QFont f = realFont();
457 if ( mAttributes.autoShrink() ) {
458 f.setPointSizeF( fitFontSizeToGeometry() );
459 }
460 painter->setFont( f );
461
462 QSize innerSize = unrotatedTextSize();
463 QRectF rect = QRectF( QPointF( 0, 0 ), innerSize );
464 rect.translate( -rect.center() );
465 painter->translate( mRect.center() );
466 painter->rotate( mAttributes.rotation() );
467#ifdef DEBUG_ITEMS_PAINT
468 painter->setPen( Qt::red );
469 painter->drawRect( rect );
470#endif
471
472 painter->setPen( PrintingParameters::scalePen( mAttributes.pen() ) );
473 QTextDocument* document = mAttributes.textDocument();
474 if ( document ) {
475 document->setPageSize( rect.size() );
476 document->setHtml( mText );
478 // ### this doesn't work for rotated painting because clip does not translate the painting
479 // TODO translate the painting either using a QTransform or one of QPainter's transform stages
480 paintcontext.clip = rect;
481 document->documentLayout()->draw( painter, paintcontext );
482 } else {
483 painter->drawText( rect, mTextAlignment, mText );
484 }
485}
486
487KChart::HorizontalLineLayoutItem::HorizontalLineLayoutItem()
488 : AbstractLayoutItem( Qt::AlignCenter )
489{
490}
491
492Qt::Orientations KChart::HorizontalLineLayoutItem::expandingDirections() const
493{
494 return Qt::Horizontal;
495}
496
497QRect KChart::HorizontalLineLayoutItem::geometry() const
498{
499 return mRect;
500}
501
502bool KChart::HorizontalLineLayoutItem::isEmpty() const
503{
504 return false; // never empty, otherwise the layout item would not exist
505}
506
507QSize KChart::HorizontalLineLayoutItem::maximumSize() const
508{
509 return QSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
510}
511
512QSize KChart::HorizontalLineLayoutItem::minimumSize() const
513{
514 return QSize( 0, 0 );
515}
516
517void KChart::HorizontalLineLayoutItem::setGeometry( const QRect& r )
518{
519 mRect = r;
520}
521
522QSize KChart::HorizontalLineLayoutItem::sizeHint() const
523{
524 return QSize( -1, 3 ); // see qframe.cpp
525}
526
527
528void KChart::HorizontalLineLayoutItem::paint( QPainter* painter )
529{
530 if ( !mRect.isValid() )
531 return;
532
533 painter->drawLine( QPointF( mRect.left(), mRect.center().y() ),
534 QPointF( mRect.right(), mRect.center().y() ) );
535}
536
537
538KChart::VerticalLineLayoutItem::VerticalLineLayoutItem()
539 : AbstractLayoutItem( Qt::AlignCenter )
540{
541}
542
543Qt::Orientations KChart::VerticalLineLayoutItem::expandingDirections() const
544{
545 return Qt::Vertical;
546}
547
548QRect KChart::VerticalLineLayoutItem::geometry() const
549{
550 return mRect;
551}
552
553bool KChart::VerticalLineLayoutItem::isEmpty() const
554{
555 return false; // never empty, otherwise the layout item would not exist
556}
557
558QSize KChart::VerticalLineLayoutItem::maximumSize() const
559{
560 return QSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
561}
562
563QSize KChart::VerticalLineLayoutItem::minimumSize() const
564{
565 return QSize( 0, 0 );
566}
567
568void KChart::VerticalLineLayoutItem::setGeometry( const QRect& r )
569{
570 mRect = r;
571}
572
573QSize KChart::VerticalLineLayoutItem::sizeHint() const
574{
575 return QSize( 3, -1 ); // see qframe.cpp
576}
577
578
579void KChart::VerticalLineLayoutItem::paint( QPainter* painter )
580{
581 if ( !mRect.isValid() )
582 return;
583
584 painter->drawLine( QPointF( mRect.center().x(), mRect.top() ),
585 QPointF( mRect.center().x(), mRect.bottom() ) );
586}
587
588
589
590KChart::MarkerLayoutItem::MarkerLayoutItem( KChart::AbstractDiagram* diagram,
591 const MarkerAttributes& marker,
592 const QBrush& brush, const QPen& pen,
593 Qt::Alignment alignment )
594 : AbstractLayoutItem( alignment )
595 , mDiagram( diagram )
596 , mMarker( marker )
597 , mBrush( brush )
598 , mPen( pen )
599{
600}
601
602Qt::Orientations KChart::MarkerLayoutItem::expandingDirections() const
603{
604 return Qt::Orientations(); // Grow neither vertically nor horizontally
605}
606
607QRect KChart::MarkerLayoutItem::geometry() const
608{
609 return mRect;
610}
611
612bool KChart::MarkerLayoutItem::isEmpty() const
613{
614 return false; // never empty, otherwise the layout item would not exist
615}
616
617QSize KChart::MarkerLayoutItem::maximumSize() const
618{
619 return sizeHint(); // PENDING(kalle) Review, quite inflexible
620}
621
622QSize KChart::MarkerLayoutItem::minimumSize() const
623{
624 return sizeHint(); // PENDING(kalle) Review, quite inflexible
625}
626
627void KChart::MarkerLayoutItem::setGeometry( const QRect& r )
628{
629 mRect = r;
630}
631
632QSize KChart::MarkerLayoutItem::sizeHint() const
633{
634 //qDebug() << "KChart::MarkerLayoutItem::sizeHint() returns:"<<mMarker.markerSize().toSize();
635 return mMarker.markerSize().toSize();
636}
637
638void KChart::MarkerLayoutItem::paint( QPainter* painter )
639{
640 paintIntoRect( painter, mRect, mDiagram, mMarker, mBrush, mPen );
641}
642
643void KChart::MarkerLayoutItem::paintIntoRect(
644 QPainter* painter,
645 const QRect& rect,
646 AbstractDiagram* diagram,
647 const MarkerAttributes& marker,
648 const QBrush& brush,
649 const QPen& pen )
650{
651 if ( !rect.isValid() )
652 return;
653
654 // The layout management may assign a larger rect than what we
655 // wanted. We need to adjust the position.
656 const QSize siz = marker.markerSize().toSize();
657 QPointF pos = rect.topLeft();
658 pos += QPointF( static_cast<qreal>(( rect.width() - siz.width()) / 2.0 ),
659 static_cast<qreal>(( rect.height() - siz.height()) / 2.0 ) );
660
661#ifdef DEBUG_ITEMS_PAINT
662 QPointF oldPos = pos;
663#endif
664
665// And finally, drawMarker() assumes the position to be the center
666 // of the marker, adjust again.
667 pos += QPointF( static_cast<qreal>( siz.width() ) / 2.0,
668 static_cast<qreal>( siz.height() )/ 2.0 );
669
670 diagram->paintMarker( painter, marker, brush, pen, pos.toPoint(), siz );
671
672#ifdef DEBUG_ITEMS_PAINT
673 const QPen oldPen( painter->pen() );
674 painter->setPen( Qt::red );
675 painter->drawRect( QRect( oldPos.toPoint(), siz ) );
676 painter->setPen( oldPen );
677#endif
678}
679
680
681KChart::LineLayoutItem::LineLayoutItem( KChart::AbstractDiagram* diagram,
682 int length,
683 const QPen& pen,
684 Qt::Alignment legendLineSymbolAlignment,
685 Qt::Alignment alignment )
686 : AbstractLayoutItem( alignment )
687 , mDiagram( diagram )
688 , mLength( length )
689 , mPen( pen )
690 , mLegendLineSymbolAlignment(legendLineSymbolAlignment)
691{
692 // enforce a minimum pen width
693 if ( pen.width() < 2 )
694 mPen.setWidth( 2 );
695}
696
697Qt::Orientations KChart::LineLayoutItem::expandingDirections() const
698{
699 return Qt::Orientations(); // Grow neither vertically nor horizontally
700}
701
702QRect KChart::LineLayoutItem::geometry() const
703{
704 return mRect;
705}
706
707bool KChart::LineLayoutItem::isEmpty() const
708{
709 return false; // never empty, otherwise the layout item would not exist
710}
711
712QSize KChart::LineLayoutItem::maximumSize() const
713{
714 return sizeHint(); // PENDING(kalle) Review, quite inflexible
715}
716
717QSize KChart::LineLayoutItem::minimumSize() const
718{
719 return sizeHint(); // PENDING(kalle) Review, quite inflexible
720}
721
722void KChart::LineLayoutItem::setGeometry( const QRect& r )
723{
724 mRect = r;
725}
726
727QSize KChart::LineLayoutItem::sizeHint() const
728{
729 return QSize( mLength, mPen.width() + 2 );
730}
731
732
733void KChart::LineLayoutItem::setLegendLineSymbolAlignment(Qt::Alignment legendLineSymbolAlignment)
734{
735 if (mLegendLineSymbolAlignment == legendLineSymbolAlignment)
736 return;
737
738 mLegendLineSymbolAlignment = legendLineSymbolAlignment;
739}
740
741Qt::Alignment KChart::LineLayoutItem::legendLineSymbolAlignment() const
742{
743 return mLegendLineSymbolAlignment;
744}
745
746void KChart::LineLayoutItem::paint( QPainter* painter )
747{
748 paintIntoRect( painter, mRect, mPen, mLegendLineSymbolAlignment );
749}
750
751void KChart::LineLayoutItem::paintIntoRect(
752 QPainter* painter,
753 const QRect& rect,
754 const QPen& pen,
755 Qt::Alignment lineAlignment)
756{
757 if ( ! rect.isValid() )
758 return;
759
760 const QPen oldPen = painter->pen();
761 painter->setPen( PrintingParameters::scalePen( pen ) );
762 qreal y = 0;
763 if (lineAlignment == Qt::AlignTop)
764 y = rect.top();
765 else if (lineAlignment == Qt::AlignBottom)
766 y = rect.bottom();
767 else
768 y = rect.center().y();
769
770 painter->drawLine( QPointF( rect.left(), y ),
771 QPointF( rect.right(), y ) );
772 painter->setPen( oldPen );
773}
774
775
776KChart::LineWithMarkerLayoutItem::LineWithMarkerLayoutItem(
778 int lineLength,
779 const QPen& linePen,
780 int markerOffs,
781 const MarkerAttributes& marker,
782 const QBrush& markerBrush,
783 const QPen& markerPen,
784 Qt::Alignment alignment )
785 : AbstractLayoutItem( alignment )
786 , mDiagram( diagram )
787 , mLineLength( lineLength )
788 , mLinePen( linePen )
789 , mMarkerOffs( markerOffs )
790 , mMarker( marker )
791 , mMarkerBrush( markerBrush )
792 , mMarkerPen( markerPen )
793{
794}
795
796Qt::Orientations KChart::LineWithMarkerLayoutItem::expandingDirections() const
797{
798 return Qt::Orientations(); // Grow neither vertically nor horizontally
799}
800
801QRect KChart::LineWithMarkerLayoutItem::geometry() const
802{
803 return mRect;
804}
805
806bool KChart::LineWithMarkerLayoutItem::isEmpty() const
807{
808 return false; // never empty, otherwise the layout item would not exist
809}
810
811QSize KChart::LineWithMarkerLayoutItem::maximumSize() const
812{
813 return sizeHint(); // PENDING(kalle) Review, quite inflexible
814}
815
816QSize KChart::LineWithMarkerLayoutItem::minimumSize() const
817{
818 return sizeHint(); // PENDING(kalle) Review, quite inflexible
819}
820
821void KChart::LineWithMarkerLayoutItem::setGeometry( const QRect& r )
822{
823 mRect = r;
824}
825
826QSize KChart::LineWithMarkerLayoutItem::sizeHint() const
827{
828 const QSize lineSize( mLineLength, mLinePen.width() + 2 );
829 return lineSize.expandedTo( mMarker.markerSize().toSize() );
830}
831
832void KChart::LineWithMarkerLayoutItem::paint( QPainter* painter )
833{
834 // paint the line over the full width, into the vertical middle of the rect
835 LineLayoutItem::paintIntoRect( painter, mRect, mLinePen, Qt::AlignCenter );
836
837 // paint the marker with the given offset from the left side of the line
838 const QRect r(
839 QPoint( mRect.x()+mMarkerOffs, mRect.y() ),
840 QSize( mMarker.markerSize().toSize().width(), mRect.height() ) );
841 MarkerLayoutItem::paintIntoRect(
842 painter, r, mDiagram, mMarker, mMarkerBrush, mMarkerPen );
843}
844
845KChart::AutoSpacerLayoutItem::AutoSpacerLayoutItem(
846 bool layoutIsAtTopPosition, QHBoxLayout *rightLeftLayout,
847 bool layoutIsAtLeftPosition, QVBoxLayout *topBottomLayout )
848 : AbstractLayoutItem( Qt::AlignCenter )
849 , mLayoutIsAtTopPosition( layoutIsAtTopPosition )
850 , mRightLeftLayout( rightLeftLayout )
851 , mLayoutIsAtLeftPosition( layoutIsAtLeftPosition )
852 , mTopBottomLayout( topBottomLayout )
853{
854}
855
856Qt::Orientations KChart::AutoSpacerLayoutItem::expandingDirections() const
857{
858 return Qt::Orientations(); // Grow neither vertically nor horizontally
859}
860
861QRect KChart::AutoSpacerLayoutItem::geometry() const
862{
863 return mRect;
864}
865
866bool KChart::AutoSpacerLayoutItem::isEmpty() const
867{
868 return true; // never empty, otherwise the layout item would not exist
869}
870
871QSize KChart::AutoSpacerLayoutItem::maximumSize() const
872{
873 return sizeHint();
874}
875
876QSize KChart::AutoSpacerLayoutItem::minimumSize() const
877{
878 return sizeHint();
879}
880
881void KChart::AutoSpacerLayoutItem::setGeometry( const QRect& r )
882{
883 mRect = r;
884}
885
886
887static void updateCommonBrush( QBrush& commonBrush, bool& bStart, const KChart::AbstractArea& area )
888{
889 const KChart::BackgroundAttributes ba( area.backgroundAttributes() );
890 const bool hasSimpleBrush = (
891 ! area.frameAttributes().isVisible() &&
892 ba.isVisible() &&
893 ba.pixmapMode() == KChart::BackgroundAttributes::BackgroundPixmapModeNone &&
894 ba.brush().gradient() == nullptr );
895 if ( bStart ) {
896 bStart = false;
897 commonBrush = hasSimpleBrush ? ba.brush() : QBrush();
898 } else {
899 if ( ! hasSimpleBrush || ba.brush() != commonBrush )
900 {
901 commonBrush = QBrush();
902 }
903 }
904}
905
906QSize KChart::AutoSpacerLayoutItem::sizeHint() const
907{
908 QBrush commonBrush;
909 bool bStart=true;
910 // calculate the maximal overlap of the top/bottom axes:
911 int topBottomOverlap = 0;
912 if ( mTopBottomLayout ) {
913 for (int i = 0; i < mTopBottomLayout->count(); ++i) {
914 AbstractArea* area = dynamic_cast<AbstractArea*>(mTopBottomLayout->itemAt(i));
915 if ( area ) {
916 //qDebug() << "AutoSpacerLayoutItem testing" << area;
917 topBottomOverlap = qMax( topBottomOverlap,
918 mLayoutIsAtLeftPosition ? area->rightOverlap()
919 : area->leftOverlap() );
920 updateCommonBrush( commonBrush, bStart, *area );
921 }
922 }
923 }
924 // calculate the maximal overlap of the left/right axes:
925 int leftRightOverlap = 0;
926 if ( mRightLeftLayout ) {
927 for (int i = 0; i < mRightLeftLayout->count(); ++i) {
928 AbstractArea* area = dynamic_cast<AbstractArea*>(mRightLeftLayout->itemAt(i));
929 if ( area ) {
930 //qDebug() << "AutoSpacerLayoutItem testing" << area;
931 leftRightOverlap = qMax( leftRightOverlap,
932 mLayoutIsAtTopPosition ? area->bottomOverlap()
933 : area->topOverlap() );
934 updateCommonBrush( commonBrush, bStart, *area );
935 }
936 }
937 }
938 if ( topBottomOverlap > 0 && leftRightOverlap > 0 )
939 mCommonBrush = commonBrush;
940 else
941 mCommonBrush = QBrush();
942 mCachedSize = QSize( topBottomOverlap, leftRightOverlap );
943 //qDebug() << mCachedSize;
944 return mCachedSize;
945}
946
947
948void KChart::AutoSpacerLayoutItem::paint( QPainter* painter )
949{
950 if ( mParentLayout && mRect.isValid() && mCachedSize.isValid() &&
951 mCommonBrush.style() != Qt::NoBrush )
952 {
953 QPoint p1( mRect.topLeft() );
954 QPoint p2( mRect.bottomRight() );
955 if ( mLayoutIsAtLeftPosition )
956 p1.rx() += mCachedSize.width() - mParentLayout->spacing();
957 else
958 p2.rx() -= mCachedSize.width() - mParentLayout->spacing();
959 if ( mLayoutIsAtTopPosition ) {
960 p1.ry() += mCachedSize.height() - mParentLayout->spacing() - 1;
961 p2.ry() -= 1;
962 } else
963 p2.ry() -= mCachedSize.height() - mParentLayout->spacing() - 1;
964 //qDebug() << mLayoutIsAtTopPosition << mLayoutIsAtLeftPosition;
965 //qDebug() << mRect;
966 //qDebug() << mParentLayout->margin();
967 //qDebug() << QRect( p1, p2 );
968 const QPoint oldBrushOrigin( painter->brushOrigin() );
969 const QBrush oldBrush( painter->brush() );
970 const QPen oldPen( painter->pen() );
971 const QPointF newTopLeft( painter->deviceTransform().map( p1 ) );
972 painter->setBrushOrigin( newTopLeft );
973 painter->setBrush( mCommonBrush );
974 painter->setPen( Qt::NoPen );
975 painter->drawRect( QRect( p1, p2 ) );
976 painter->setBrushOrigin( oldBrushOrigin );
977 painter->setBrush( oldBrush );
978 painter->setPen( oldPen );
979 }
980 // debug code:
981#if 0
982 //qDebug() << "KChart::AutoSpacerLayoutItem::paint()";
983 if ( !mRect.isValid() )
984 return;
985
986 painter->drawRect( mRect );
987 painter->drawLine( QPointF( mRect.topLeft(), mRect.bottomRight() ) );
988 painter->drawLine( QPointF( mRect.topRight(), mRect.bottomLeft() ) );
989#endif
990}
Project global class providing some enums needed both by KChartParams and by KChartCustomBox.
Definition KChartEnums.h:27
MeasureOrientation
Measure orientation mode: the way how the absolute value of a KChart::Measure is determined during KC...
An area in the chart with a background, a frame, etc.
AbstractDiagram defines the interface for diagram classes.
Base class for all layout items of KChart.
virtual void setParentWidget(QWidget *widget)
Inform the item about its widget: This enables the item, to trigger that widget's update,...
virtual void paintAll(QPainter &painter)
Default impl: just call paint.
virtual void sizeHintChanged() const
Report changed size hint: ask the parent widget to recalculate the layout.
virtual void paintCtx(PaintContext *context)
Default impl: Paint the complete item using its layouted position and size.
Set of attributes usable for background pixmaps.
static QPaintDevice * paintDevice()
Return the paint device to use for calculating font metrics.
Stores information about painting diagrams.
A set of text attributes.
Layout item showing a text.
QSize sizeHint() const override
pure virtual in QLayoutItem
Qt::Orientations expandingDirections() const override
pure virtual in QLayoutItem
void setTextAttributes(const TextAttributes &a)
Use this to specify the text attributes to be used for this item.
QRect geometry() const override
pure virtual in QLayoutItem
bool isEmpty() const override
pure virtual in QLayoutItem
QSize minimumSize() const override
pure virtual in QLayoutItem
void setGeometry(const QRect &r) override
pure virtual in QLayoutItem
TextAttributes textAttributes() const
Returns the text attributes to be used for this item.
QSize maximumSize() const override
pure virtual in QLayoutItem
virtual void draw(QPainter *painter, const QAbstractTextDocumentLayout::PaintContext &context)=0
QStyle * style()
void postEvent(QObject *receiver, QEvent *event, int priority)
qreal pointSizeF() const const
void setPointSizeF(qreal pointSize)
virtual QWidget * widget()
const QBrush & brush() const const
QPoint brushOrigin() const const
const QTransform & deviceTransform() const const
void drawLine(const QLineF &line)
void drawRect(const QRectF &rectangle)
void drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode)
void drawText(const QPointF &position, const QString &text)
const QPen & pen() const const
void rotate(qreal angle)
void setBrush(const QBrush &brush)
void setBrushOrigin(int x, int y)
void setFont(const QFont &font)
void setPen(const QColor &color)
void translate(const QPointF &offset)
int width() const const
int y() const const
QPoint toPoint() const const
QRect boundingRect() const const
QRect adjusted(int dx1, int dy1, int dx2, int dy2) const const
int bottom() const const
QPoint center() const const
int height() const const
bool isValid() const const
int left() const const
int right() const const
QSize size() const const
int top() const const
QPoint topLeft() const const
int width() const const
QPointF center() const const
QRectF normalized() const const
QSizeF size() const const
void translate(qreal dx, qreal dy)
int height() const const
bool isNull() const const
bool isValid() const const
int width() const const
qreal height() const const
qreal width() const const
typedef Alignment
typedef Orientations
RelativeSize
QAbstractTextDocumentLayout * documentLayout() const const
void setPageSize(const QSizeF &size)
void setHtml(const QString &html)
QPoint map(const QPoint &point) const const
QRect mapRect(const QRect &rectangle) const const
QPolygon mapToPolygon(const QRect &rectangle) const const
QTransform & rotate(qreal angle, Qt::Axis axis)
QTransform & translate(qreal dx, qreal dy)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sun Feb 25 2024 18:40:00 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.