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 
63 KChart::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 
73 KChart::TextBubbleLayoutItem::TextBubbleLayoutItem()
74  : AbstractLayoutItem( Qt::AlignLeft ),
75  m_text( new TextLayoutItem() )
76 {
77 }
78 
79 KChart::TextBubbleLayoutItem::~TextBubbleLayoutItem()
80 {
81  delete m_text;
82 }
83 
84 void KChart::TextBubbleLayoutItem::setAutoReferenceArea( const QObject* area )
85 {
86  m_text->setAutoReferenceArea( area );
87 }
88 
89 const QObject* KChart::TextBubbleLayoutItem::autoReferenceArea() const
90 {
91  return m_text->autoReferenceArea();
92 }
93 
94 void KChart::TextBubbleLayoutItem::setText( const QString& text )
95 {
96  m_text->setText( text );
97 }
98 
99 QString KChart::TextBubbleLayoutItem::text() const
100 {
101  return m_text->text();
102 }
103 
104 void KChart::TextBubbleLayoutItem::setTextAttributes( const TextAttributes& a )
105 {
106  m_text->setTextAttributes( a );
107 }
108 
109 KChart::TextAttributes KChart::TextBubbleLayoutItem::textAttributes() const
110 {
111  return m_text->textAttributes();
112 }
113 
114 bool KChart::TextBubbleLayoutItem::isEmpty() const
115 {
116  return m_text->isEmpty();
117 }
118 
119 Qt::Orientations KChart::TextBubbleLayoutItem::expandingDirections() const
120 {
121  return m_text->expandingDirections();
122 }
123 
124 QSize KChart::TextBubbleLayoutItem::maximumSize() const
125 {
126  const int border = borderWidth();
127  return m_text->maximumSize() + QSize( 2 * border, 2 * border );
128 }
129 
130 QSize KChart::TextBubbleLayoutItem::minimumSize() const
131 {
132  const int border = borderWidth();
133  return m_text->minimumSize() + QSize( 2 * border, 2 * border );
134 }
135 
136 QSize KChart::TextBubbleLayoutItem::sizeHint() const
137 {
138  const int border = borderWidth();
139  return m_text->sizeHint() + QSize( 2 * border, 2 * border );
140 }
141 
142 void KChart::TextBubbleLayoutItem::setGeometry( const QRect& r )
143 {
144  const int border = borderWidth();
145  m_text->setGeometry( r.adjusted( border, border, -border, -border ) );
146 }
147 
148 QRect KChart::TextBubbleLayoutItem::geometry() const
149 {
150  const int border = borderWidth();
151  return m_text->geometry().adjusted( -border, -border, border, border );
152 }
153 
154 void 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 
166 int KChart::TextBubbleLayoutItem::borderWidth() const
167 {
168  return 1;
169 }
170 
171 KChart::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 
188 KChart::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 
202 void KChart::TextLayoutItem::setAutoReferenceArea( const QObject* area )
203 {
204  mAutoReferenceArea = area;
205  cachedSizeHint = QSize();
206  sizeHint();
207 }
208 
209 const QObject* KChart::TextLayoutItem::autoReferenceArea() const
210 {
211  return mAutoReferenceArea;
212 }
213 
214 void KChart::TextLayoutItem::setText(const QString & text)
215 {
216  mText = text;
217  cachedSizeHint = QSize();
218  sizeHint();
219  if ( mParent )
220  mParent->update();
221 }
222 
223 QString KChart::TextLayoutItem::text() const
224 {
225  return mText;
226 }
227 
228 void KChart::TextLayoutItem::setTextAlignment( Qt::Alignment alignment)
229 {
230  if ( mTextAlignment == alignment )
231  return;
232  mTextAlignment = alignment;
233  if ( mParent )
234  mParent->update();
235 }
236 
237 Qt::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
289 QRectF 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 
299 qreal 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 
329 qreal KChart::TextLayoutItem::realFontSize() const
330 {
331  return mAttributes.calculatedFontSize( mAutoReferenceArea, mAutoReferenceOrientation );
332 }
333 
334 bool 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 
346 QFont KChart::TextLayoutItem::realFont() const
347 {
348  maybeUpdateRealFont();
349  return cachedFont;
350 }
351 
352 QPolygon KChart::TextLayoutItem::boundingPolygon() const
353 {
354  // should probably call sizeHint() here, but that one is expensive (see TODO there)
355  return mCachedBoundingPolygon;
356 }
357 
358 bool KChart::TextLayoutItem::intersects( const TextLayoutItem& other, const QPointF& myPos, const QPointF& otherPos ) const
359 {
360  return intersects( other, myPos.toPoint(), otherPos.toPoint() );
361 }
362 
363 bool 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 
385 QSize 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 
395 QSize 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 
407 int KChart::TextLayoutItem::marginWidth() const
408 {
409  return marginWidth( unrotatedTextSize() );
410 }
411 
412 int 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 
419 QSize 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 
427 QSize 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 
450 void 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 
487 KChart::HorizontalLineLayoutItem::HorizontalLineLayoutItem()
488  : AbstractLayoutItem( Qt::AlignCenter )
489 {
490 }
491 
492 Qt::Orientations KChart::HorizontalLineLayoutItem::expandingDirections() const
493 {
494  return Qt::Horizontal;
495 }
496 
497 QRect KChart::HorizontalLineLayoutItem::geometry() const
498 {
499  return mRect;
500 }
501 
502 bool KChart::HorizontalLineLayoutItem::isEmpty() const
503 {
504  return false; // never empty, otherwise the layout item would not exist
505 }
506 
507 QSize KChart::HorizontalLineLayoutItem::maximumSize() const
508 {
509  return QSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
510 }
511 
512 QSize KChart::HorizontalLineLayoutItem::minimumSize() const
513 {
514  return QSize( 0, 0 );
515 }
516 
517 void KChart::HorizontalLineLayoutItem::setGeometry( const QRect& r )
518 {
519  mRect = r;
520 }
521 
522 QSize KChart::HorizontalLineLayoutItem::sizeHint() const
523 {
524  return QSize( -1, 3 ); // see qframe.cpp
525 }
526 
527 
528 void 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 
538 KChart::VerticalLineLayoutItem::VerticalLineLayoutItem()
539  : AbstractLayoutItem( Qt::AlignCenter )
540 {
541 }
542 
543 Qt::Orientations KChart::VerticalLineLayoutItem::expandingDirections() const
544 {
545  return Qt::Vertical;
546 }
547 
548 QRect KChart::VerticalLineLayoutItem::geometry() const
549 {
550  return mRect;
551 }
552 
553 bool KChart::VerticalLineLayoutItem::isEmpty() const
554 {
555  return false; // never empty, otherwise the layout item would not exist
556 }
557 
558 QSize KChart::VerticalLineLayoutItem::maximumSize() const
559 {
560  return QSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
561 }
562 
563 QSize KChart::VerticalLineLayoutItem::minimumSize() const
564 {
565  return QSize( 0, 0 );
566 }
567 
568 void KChart::VerticalLineLayoutItem::setGeometry( const QRect& r )
569 {
570  mRect = r;
571 }
572 
573 QSize KChart::VerticalLineLayoutItem::sizeHint() const
574 {
575  return QSize( 3, -1 ); // see qframe.cpp
576 }
577 
578 
579 void 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 
590 KChart::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 
602 Qt::Orientations KChart::MarkerLayoutItem::expandingDirections() const
603 {
604  return Qt::Orientations(); // Grow neither vertically nor horizontally
605 }
606 
607 QRect KChart::MarkerLayoutItem::geometry() const
608 {
609  return mRect;
610 }
611 
612 bool KChart::MarkerLayoutItem::isEmpty() const
613 {
614  return false; // never empty, otherwise the layout item would not exist
615 }
616 
617 QSize KChart::MarkerLayoutItem::maximumSize() const
618 {
619  return sizeHint(); // PENDING(kalle) Review, quite inflexible
620 }
621 
622 QSize KChart::MarkerLayoutItem::minimumSize() const
623 {
624  return sizeHint(); // PENDING(kalle) Review, quite inflexible
625 }
626 
627 void KChart::MarkerLayoutItem::setGeometry( const QRect& r )
628 {
629  mRect = r;
630 }
631 
632 QSize KChart::MarkerLayoutItem::sizeHint() const
633 {
634  //qDebug() << "KChart::MarkerLayoutItem::sizeHint() returns:"<<mMarker.markerSize().toSize();
635  return mMarker.markerSize().toSize();
636 }
637 
638 void KChart::MarkerLayoutItem::paint( QPainter* painter )
639 {
640  paintIntoRect( painter, mRect, mDiagram, mMarker, mBrush, mPen );
641 }
642 
643 void 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 
681 KChart::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 
697 Qt::Orientations KChart::LineLayoutItem::expandingDirections() const
698 {
699  return Qt::Orientations(); // Grow neither vertically nor horizontally
700 }
701 
702 QRect KChart::LineLayoutItem::geometry() const
703 {
704  return mRect;
705 }
706 
707 bool KChart::LineLayoutItem::isEmpty() const
708 {
709  return false; // never empty, otherwise the layout item would not exist
710 }
711 
712 QSize KChart::LineLayoutItem::maximumSize() const
713 {
714  return sizeHint(); // PENDING(kalle) Review, quite inflexible
715 }
716 
717 QSize KChart::LineLayoutItem::minimumSize() const
718 {
719  return sizeHint(); // PENDING(kalle) Review, quite inflexible
720 }
721 
722 void KChart::LineLayoutItem::setGeometry( const QRect& r )
723 {
724  mRect = r;
725 }
726 
727 QSize KChart::LineLayoutItem::sizeHint() const
728 {
729  return QSize( mLength, mPen.width() + 2 );
730 }
731 
732 
733 void KChart::LineLayoutItem::setLegendLineSymbolAlignment(Qt::Alignment legendLineSymbolAlignment)
734 {
735  if (mLegendLineSymbolAlignment == legendLineSymbolAlignment)
736  return;
737 
738  mLegendLineSymbolAlignment = legendLineSymbolAlignment;
739 }
740 
741 Qt::Alignment KChart::LineLayoutItem::legendLineSymbolAlignment() const
742 {
743  return mLegendLineSymbolAlignment;
744 }
745 
746 void KChart::LineLayoutItem::paint( QPainter* painter )
747 {
748  paintIntoRect( painter, mRect, mPen, mLegendLineSymbolAlignment );
749 }
750 
751 void 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 
776 KChart::LineWithMarkerLayoutItem::LineWithMarkerLayoutItem(
777  KChart::AbstractDiagram* diagram,
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 
796 Qt::Orientations KChart::LineWithMarkerLayoutItem::expandingDirections() const
797 {
798  return Qt::Orientations(); // Grow neither vertically nor horizontally
799 }
800 
801 QRect KChart::LineWithMarkerLayoutItem::geometry() const
802 {
803  return mRect;
804 }
805 
806 bool KChart::LineWithMarkerLayoutItem::isEmpty() const
807 {
808  return false; // never empty, otherwise the layout item would not exist
809 }
810 
811 QSize KChart::LineWithMarkerLayoutItem::maximumSize() const
812 {
813  return sizeHint(); // PENDING(kalle) Review, quite inflexible
814 }
815 
816 QSize KChart::LineWithMarkerLayoutItem::minimumSize() const
817 {
818  return sizeHint(); // PENDING(kalle) Review, quite inflexible
819 }
820 
821 void KChart::LineWithMarkerLayoutItem::setGeometry( const QRect& r )
822 {
823  mRect = r;
824 }
825 
826 QSize KChart::LineWithMarkerLayoutItem::sizeHint() const
827 {
828  const QSize lineSize( mLineLength, mLinePen.width() + 2 );
829  return lineSize.expandedTo( mMarker.markerSize().toSize() );
830 }
831 
832 void 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 
845 KChart::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 
856 Qt::Orientations KChart::AutoSpacerLayoutItem::expandingDirections() const
857 {
858  return Qt::Orientations(); // Grow neither vertically nor horizontally
859 }
860 
861 QRect KChart::AutoSpacerLayoutItem::geometry() const
862 {
863  return mRect;
864 }
865 
866 bool KChart::AutoSpacerLayoutItem::isEmpty() const
867 {
868  return true; // never empty, otherwise the layout item would not exist
869 }
870 
871 QSize KChart::AutoSpacerLayoutItem::maximumSize() const
872 {
873  return sizeHint();
874 }
875 
876 QSize KChart::AutoSpacerLayoutItem::minimumSize() const
877 {
878  return sizeHint();
879 }
880 
881 void KChart::AutoSpacerLayoutItem::setGeometry( const QRect& r )
882 {
883  mRect = r;
884 }
885 
886 
887 static 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 
906 QSize 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 
948 void 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 }
Base class for all layout items of KChart.
Class only listed here to document inheritance of some KChart classes.
QPoint map(const QPoint &point) const const
typedef Alignment
An area in the chart with a background, a frame, etc.
virtual void setParentWidget(QWidget *widget)
Inform the item about its widget: This enables the item, to trigger that widget's update,...
Project global class providing some enums needed both by KChartParams and by KChartCustomBox.
Definition: KChartEnums.h:26
qreal height() const const
QSize sizeHint() const override
pure virtual in QLayoutItem
void setPen(const QColor &color)
QPoint topLeft() const const
bool isValid() const const
QSize size() const const
void rotate(qreal angle)
QTransform & rotate(qreal angle, Qt::Axis axis)
int right() const const
void drawRect(const QRectF &rectangle)
QAbstractTextDocumentLayout * documentLayout() const const
Class only listed here to document inheritance of some KChart classes.
QSize maximumSize() const override
pure virtual in QLayoutItem
int width() const const
TextAttributes textAttributes() const
Returns the text attributes to be used for this item.
void setBrushOrigin(int x, int y)
int y() const const
Stores information about painting diagrams.
RelativeSize
int width() const const
const QPen & pen() const const
void setPageSize(const QSizeF &size)
void drawText(const QPointF &position, const QString &text)
int left() const const
virtual QWidget * widget()
Layout item showing a text.
QPoint brushOrigin() const const
int bottom() const const
void setGeometry(const QRect &r) override
pure virtual in QLayoutItem
bool isEmpty() const override
pure virtual in QLayoutItem
int top() const const
void drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode)
int width() const const
void setTextAttributes(const TextAttributes &a)
Use this to specify the text attributes to be used for this item.
MeasureOrientation
Measure orientation mode: the way how the absolute value of a KChart::Measure is determined during KC...
Definition: KChartEnums.h:282
int height() const const
QTransform & translate(qreal dx, qreal dy)
typedef Orientations
bool isValid() const const
virtual void sizeHintChanged() const
Report changed size hint: ask the parent widget to recalculate the layout.
bool isNull() const const
Set of attributes usable for background pixmaps.
QPoint center() const const
QSize minimumSize() const override
pure virtual in QLayoutItem
QRect boundingRect() const const
const QBrush & brush() const const
void setBrush(const QBrush &brush)
virtual void paintCtx(PaintContext *context)
Default impl: Paint the complete item using its layouted position and size.
virtual void paintAll(QPainter &painter)
Default impl: just call paint.
QPointF center() const const
int height() const const
void postEvent(QObject *receiver, QEvent *event, int priority)
void setHtml(const QString &html)
const QTransform & deviceTransform() const const
void drawLine(const QLineF &line)
QPoint toPoint() const const
QRect geometry() const override
pure virtual in QLayoutItem
QRect adjusted(int dx1, int dy1, int dx2, int dy2) const const
void translate(const QPointF &offset)
static QPaintDevice * paintDevice()
Return the paint device to use for calculating font metrics.
void translate(qreal dx, qreal dy)
QSizeF size() const const
AbstractDiagram defines the interface for diagram classes.
void setPointSizeF(qreal pointSize)
QRectF normalized() const const
QPolygon mapToPolygon(const QRect &rectangle) const const
qreal pointSizeF() const const
virtual void draw(QPainter *painter, const QAbstractTextDocumentLayout::PaintContext &context)=0
QRect mapRect(const QRect &rectangle) const const
void setFont(const QFont &font)
A set of text attributes.
Qt::Orientations expandingDirections() const override
pure virtual in QLayoutItem
QStyle * style()
qreal width() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Thu Sep 21 2023 03:54:17 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.