KChart

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

KDE's Doxygen guidelines are available online.