• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KDEUI

  • kdeui
  • plotting
kplotwidget.cpp
Go to the documentation of this file.
1/* -*- C++ -*-
2 This file is part of the KDE libraries
3 Copyright (C) 2003 Jason Harris <kstars@30doradus.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21#include "kplotwidget.h"
22#include "kplotwidget.moc"
23
24#include <math.h>
25#include <kdebug.h>
26
27#include <QtGui/QActionEvent>
28#include <QHash>
29#include <QPainter>
30#include <QPixmap>
31#include <QToolTip>
32#include <QtAlgorithms>
33
34#include "kplotaxis.h"
35#include "kplotpoint.h"
36#include "kplotobject.h"
37
38#define XPADDING 20
39#define YPADDING 20
40#define BIGTICKSIZE 10
41#define SMALLTICKSIZE 4
42#define TICKOFFSET 0
43
44class KPlotWidget::Private
45{
46public:
47 Private( KPlotWidget *qq )
48 : q( qq ),
49 cBackground( Qt::black ), cForeground( Qt::white ), cGrid( Qt::gray ),
50 showGrid( false ), showObjectToolTip( true ), useAntialias( false )
51 {
52 // create the axes and setting their default properties
53 KPlotAxis *leftAxis = new KPlotAxis();
54 leftAxis->setTickLabelsShown( true );
55 axes.insert( LeftAxis, leftAxis );
56 KPlotAxis *bottomAxis = new KPlotAxis();
57 bottomAxis->setTickLabelsShown( true );
58 axes.insert( BottomAxis, bottomAxis );
59 KPlotAxis *rightAxis = new KPlotAxis();
60 axes.insert( RightAxis, rightAxis );
61 KPlotAxis *topAxis = new KPlotAxis();
62 axes.insert( TopAxis, topAxis );
63 }
64
65 ~Private()
66 {
67 qDeleteAll( objectList );
68 qDeleteAll( axes );
69 }
70
71 KPlotWidget *q;
72
73 void calcDataRectLimits( double x1, double x2, double y1, double y2 );
82 float rectCost( const QRectF &r ) const;
83
84 //Colors
85 QColor cBackground, cForeground, cGrid;
86 //draw options
87 bool showGrid : 1;
88 bool showObjectToolTip : 1;
89 bool useAntialias : 1;
90 //padding
91 int leftPadding, rightPadding, topPadding, bottomPadding;
92 // hashmap with the axes we have
93 QHash<Axis, KPlotAxis*> axes;
94 // List of KPlotObjects
95 QList<KPlotObject*> objectList;
96 // Limits of the plot area in data units
97 QRectF dataRect, secondDataRect;
98 // Limits of the plot area in pixel units
99 QRect pixRect;
100 //Array holding the mask of "used" regions of the plot
101 QImage plotMask;
102};
103
104KPlotWidget::KPlotWidget( QWidget * parent )
105 : QFrame( parent ), d( new Private( this ) )
106{
107 setAttribute( Qt::WA_OpaquePaintEvent );
108 setAttribute( Qt::WA_NoSystemBackground );
109
110 d->secondDataRect = QRectF(); //default: no secondary data rect
111 // sets the default limits
112 d->calcDataRectLimits( 0.0, 1.0, 0.0, 1.0 );
113
114 setDefaultPaddings();
115
116 setMinimumSize( 150, 150 );
117 resize( minimumSizeHint() );
118}
119
120KPlotWidget::~KPlotWidget()
121{
122 delete d;
123}
124
125QSize KPlotWidget::minimumSizeHint() const
126{
127 return QSize( 150, 150 );
128}
129
130QSize KPlotWidget::sizeHint() const
131{
132 return size();
133}
134
135void KPlotWidget::setLimits( double x1, double x2, double y1, double y2 )
136{
137 d->calcDataRectLimits( x1, x2, y1, y2 );
138 update();
139}
140
141void KPlotWidget::Private::calcDataRectLimits( double x1, double x2, double y1, double y2 )
142{
143 double XA1, XA2, YA1, YA2;
144 if (x2<x1) { XA1=x2; XA2=x1; }
145 else { XA1=x1; XA2=x2; }
146 if ( y2<y1) { YA1=y2; YA2=y1; }
147 else { YA1=y1; YA2=y2; }
148
149 if ( XA2 == XA1 ) {
150 kWarning() << "x1 and x2 cannot be equal. Setting x2 = x1 + 1.0";
151 XA2 = XA1 + 1.0;
152 }
153 if ( YA2 == YA1 ) {
154 kWarning() << "y1 and y2 cannot be equal. Setting y2 = y1 + 1.0";
155 YA2 = YA1 + 1.0;
156 }
157 dataRect = QRectF( XA1, YA1, XA2 - XA1, YA2 - YA1 );
158
159 q->axis( LeftAxis )->setTickMarks( dataRect.y(), dataRect.height() );
160 q->axis( BottomAxis )->setTickMarks( dataRect.x(), dataRect.width() );
161
162 if ( secondDataRect.isNull() )
163 {
164 q->axis( RightAxis )->setTickMarks( dataRect.y(), dataRect.height() );
165 q->axis( TopAxis )->setTickMarks( dataRect.x(), dataRect.width() );
166 }
167}
168
169void KPlotWidget::setSecondaryLimits( double x1, double x2, double y1, double y2 ) {
170 double XA1, XA2, YA1, YA2;
171 if (x2<x1) { XA1=x2; XA2=x1; }
172 else { XA1=x1; XA2=x2; }
173 if ( y2<y1) { YA1=y2; YA2=y1; }
174 else { YA1=y1; YA2=y2; }
175
176 if ( XA2 == XA1 ) {
177 kWarning() << "x1 and x2 cannot be equal. Setting x2 = x1 + 1.0";
178 XA2 = XA1 + 1.0;
179 }
180 if ( YA2 == YA1 ) {
181 kWarning() << "y1 and y2 cannot be equal. Setting y2 = y1 + 1.0";
182 YA2 = YA1 + 1.0;
183 }
184 d->secondDataRect = QRectF( XA1, YA1, XA2-XA1, YA2-YA1 );
185
186 axis(RightAxis)->setTickMarks( d->secondDataRect.y(), d->secondDataRect.height() );
187 axis(TopAxis)->setTickMarks( d->secondDataRect.x(), d->secondDataRect.width() );
188
189 update();
190}
191
192void KPlotWidget::clearSecondaryLimits() {
193 d->secondDataRect = QRectF();
194 axis(RightAxis)->setTickMarks( d->dataRect.y(), d->dataRect.height() );
195 axis(TopAxis)->setTickMarks( d->dataRect.x(), d->dataRect.width() );
196
197 update();
198}
199
200QRectF KPlotWidget::dataRect() const
201{
202 return d->dataRect;
203}
204
205QRectF KPlotWidget::secondaryDataRect() const
206{
207 return d->secondDataRect;
208}
209
210void KPlotWidget::addPlotObject( KPlotObject *object )
211{
212 // skip null pointers
213 if ( !object )
214 return;
215 d->objectList.append( object );
216 update();
217}
218
219void KPlotWidget::addPlotObjects( const QList< KPlotObject* >& objects )
220{
221 bool addedsome = false;
222 foreach ( KPlotObject *o, objects )
223 {
224 if ( !o )
225 continue;
226
227 d->objectList.append( o );
228 addedsome = true;
229 }
230 if ( addedsome )
231 update();
232}
233
234QList< KPlotObject* > KPlotWidget::plotObjects() const
235{
236 return d->objectList;
237}
238
239void KPlotWidget::removeAllPlotObjects()
240{
241 if ( d->objectList.isEmpty() )
242 return;
243
244 qDeleteAll( d->objectList );
245 d->objectList.clear();
246 update();
247}
248
249void KPlotWidget::resetPlotMask() {
250 d->plotMask = QImage( pixRect().size(), QImage::Format_ARGB32 );
251 QColor fillColor = Qt::black;
252 fillColor.setAlpha( 128 );
253 d->plotMask.fill( fillColor.rgb() );
254}
255
256void KPlotWidget::resetPlot() {
257 qDeleteAll( d->objectList );
258 d->objectList.clear();
259 clearSecondaryLimits();
260 d->calcDataRectLimits( 0.0, 1.0, 0.0, 1.0 );
261 KPlotAxis *a = axis( RightAxis );
262 a->setLabel( QString() );
263 a->setTickLabelsShown( false );
264 a = axis( TopAxis );
265 a->setLabel( QString() );
266 a->setTickLabelsShown( false );
267 axis(KPlotWidget::LeftAxis)->setLabel( QString() );
268 axis(KPlotWidget::BottomAxis)->setLabel( QString() );
269 resetPlotMask();
270}
271
272void KPlotWidget::replacePlotObject( int i, KPlotObject *o )
273{
274 // skip null pointers and invalid indexes
275 if ( !o || i < 0 || i >= d->objectList.count() )
276 return;
277 d->objectList.replace( i, o );
278 update();
279}
280
281QColor KPlotWidget::backgroundColor() const
282{
283 return d->cBackground;
284}
285
286QColor KPlotWidget::foregroundColor() const
287{
288 return d->cForeground;
289}
290
291QColor KPlotWidget::gridColor() const
292{
293 return d->cGrid;
294}
295
296void KPlotWidget::setBackgroundColor( const QColor &bg ) {
297 d->cBackground = bg;
298 update();
299}
300
301void KPlotWidget::setForegroundColor( const QColor &fg )
302{
303 d->cForeground = fg;
304 update();
305}
306
307void KPlotWidget::setGridColor( const QColor &gc )
308{
309 d->cGrid = gc;
310 update();
311}
312
313bool KPlotWidget::isGridShown() const
314{
315 return d->showGrid;
316}
317
318bool KPlotWidget::isObjectToolTipShown() const
319{
320 return d->showObjectToolTip;
321}
322
323bool KPlotWidget::antialiasing() const
324{
325 return d->useAntialias;
326}
327
328void KPlotWidget::setAntialiasing( bool b )
329{
330 d->useAntialias = b;
331 update();
332}
333
334void KPlotWidget::setShowGrid( bool show ) {
335 d->showGrid = show;
336 update();
337}
338
339void KPlotWidget::setObjectToolTipShown( bool show )
340{
341 d->showObjectToolTip = show;
342}
343
344
345KPlotAxis* KPlotWidget::axis( Axis type )
346{
347 QHash<Axis, KPlotAxis*>::Iterator it = d->axes.find( type );
348 return it != d->axes.end() ? it.value() : 0;
349}
350
351const KPlotAxis* KPlotWidget::axis( Axis type ) const
352{
353 QHash<Axis, KPlotAxis*>::ConstIterator it = d->axes.constFind( type );
354 return it != d->axes.constEnd() ? it.value() : 0;
355}
356
357QRect KPlotWidget::pixRect() const
358{
359 return d->pixRect;
360}
361
362QList<KPlotPoint*> KPlotWidget::pointsUnderPoint( const QPoint& p ) const {
363 QList<KPlotPoint*> pts;
364 foreach ( KPlotObject *po, d->objectList ) {
365 foreach ( KPlotPoint *pp, po->points() ) {
366 if ( ( p - mapToWidget( pp->position() ).toPoint() ).manhattanLength() <= 4 )
367 pts << pp;
368 }
369 }
370
371 return pts;
372}
373
374
375bool KPlotWidget::event( QEvent* e ) {
376 if ( e->type() == QEvent::ToolTip ) {
377 if ( d->showObjectToolTip )
378 {
379 QHelpEvent *he = static_cast<QHelpEvent*>( e );
380 QList<KPlotPoint*> pts = pointsUnderPoint( he->pos() - QPoint( leftPadding(), topPadding() ) - contentsRect().topLeft() );
381 if ( pts.count() > 0 ) {
382 QToolTip::showText( he->globalPos(), pts.front()->label(), this );
383 }
384 }
385 e->accept();
386 return true;
387 }
388 else
389 return QFrame::event( e );
390}
391
392void KPlotWidget::resizeEvent( QResizeEvent* e ) {
393 QFrame::resizeEvent( e );
394 setPixRect();
395 resetPlotMask();
396}
397
398void KPlotWidget::setPixRect() {
399 int newWidth = contentsRect().width() - leftPadding() - rightPadding();
400 int newHeight = contentsRect().height() - topPadding() - bottomPadding();
401 // PixRect starts at (0,0) because we will translate by leftPadding(), topPadding()
402 d->pixRect = QRect( 0, 0, newWidth, newHeight );
403}
404
405QPointF KPlotWidget::mapToWidget( const QPointF& p ) const
406{
407 float px = d->pixRect.left() + d->pixRect.width() * ( p.x() - d->dataRect.x() ) / d->dataRect.width();
408 float py = d->pixRect.top() + d->pixRect.height() * ( d->dataRect.y() + d->dataRect.height() - p.y() ) / d->dataRect.height();
409 return QPointF( px, py );
410}
411
412void KPlotWidget::maskRect( const QRectF& rf, float fvalue ) {
413 QRect r = rf.toRect().intersected( d->pixRect );
414 int value = int( fvalue );
415 QColor newColor;
416 for ( int ix=r.left(); ix<r.right(); ++ix ) {
417 for ( int iy=r.top(); iy<r.bottom(); ++iy ) {
418 newColor = QColor( d->plotMask.pixel(ix,iy) );
419 newColor.setAlpha( 200 );
420 newColor.setRed( qMin( newColor.red() + value, 255 ) );
421 d->plotMask.setPixel( ix, iy, newColor.rgba() );
422 }
423 }
424
425}
426
427void KPlotWidget::maskAlongLine( const QPointF &p1, const QPointF &p2, float fvalue ) {
428 if ( ! d->pixRect.contains( p1.toPoint() ) && ! d->pixRect.contains( p2.toPoint() ) ) {
429 return;
430 }
431
432 int value = int( fvalue );
433
434 //Determine slope and zeropoint of line
435 double m = (p2.y() - p1.y())/(p2.x() - p1.x());
436 double y0 = p1.y() - m*p1.x();
437 QColor newColor;
438
439 //Mask each pixel along the line joining p1 and p2
440 if ( m > 1.0 || m < -1.0 ) { //step in y-direction
441 int y1 = int( p1.y() );
442 int y2 = int( p2.y() );
443 if ( y1 > y2 ) {
444 y1 = int( p2.y() );
445 y2 = int( p1.y() );
446 }
447
448 for ( int y=y1; y<=y2; ++y ) {
449 int x = int( (y - y0)/m );
450 if ( d->pixRect.contains( x, y ) ) {
451 newColor = QColor( d->plotMask.pixel(x,y) );
452 newColor.setAlpha( 100 );
453 newColor.setRed( qMin( newColor.red() + value, 255 ) );
454 d->plotMask.setPixel( x, y, newColor.rgba() );
455 }
456 }
457
458 } else { //step in x-direction
459 int x1 = int( p1.x() );
460 int x2 = int( p2.x() );
461 if ( x1 > x2 ) {
462 x1 = int( p2.x() );
463 x2 = int( p1.x() );
464 }
465
466 for ( int x=x1; x<=x2; ++x ) {
467 int y = int( y0 + m*x );
468 if ( d->pixRect.contains( x, y ) ) {
469 newColor = QColor( d->plotMask.pixel(x,y) );
470 newColor.setAlpha( 100 );
471 newColor.setRed( qMin( newColor.red() + value, 255 ) );
472 d->plotMask.setPixel( x, y, newColor.rgba() );
473 }
474 }
475 }
476}
477
478//Determine optimal placement for a text label for point pp. We want
479//the label to be near point pp, but we don't want it to overlap with
480//other labels or plot elements. We will use a "downhill simplex"
481//algorithm to find a label position that minimizes the pixel values
482//in the plotMask image over the label's rect(). The sum of pixel
483//values in the label's rect is the "cost" of placing the label there.
484//
485//Because a downhill simplex follows the local gradient to find low
486//values, it can get stuck in local minima. To mitigate this, we will
487//iteratively attempt each of the initial path offset directions (up,
488//down, right, left) in the order of increasing cost at each location.
489void KPlotWidget::placeLabel( QPainter *painter, KPlotPoint *pp ) {
490 int textFlags = Qt::TextSingleLine | Qt::AlignCenter;
491
492 QPointF pos = mapToWidget( pp->position() );
493 if ( ! d->pixRect.contains( pos.toPoint() ) ) return;
494
495 QFontMetricsF fm( painter->font(), painter->device() );
496 QRectF bestRect = fm.boundingRect( QRectF( pos.x(), pos.y(), 1, 1 ), textFlags, pp->label() );
497 float xStep = 0.5*bestRect.width();
498 float yStep = 0.5*bestRect.height();
499 float maxCost = 0.05 * bestRect.width() * bestRect.height();
500 float bestCost = d->rectCost( bestRect );
501
502 //We will travel along a path defined by the maximum decrease in
503 //the cost at each step. If this path takes us to a local minimum
504 //whose cost exceeds maxCost, then we will restart at the
505 //beginning and select the next-best path. The indices of
506 //already-tried paths are stored in the TriedPathIndex list.
507 //
508 //If we try all four first-step paths and still don't get below
509 //maxCost, then we'll adopt the local minimum position with the
510 //best cost (designated as bestBadCost).
511 int iter = 0;
512 QList<int> TriedPathIndex;
513 float bestBadCost = 10000;
514 QRectF bestBadRect;
515
516 //needed to halt iteration from inside the switch
517 bool flagStop = false;
518
519 while ( bestCost > maxCost ) {
520 //Displace the label up, down, left, right; determine which
521 //step provides the lowest cost
522 QRectF upRect = bestRect;
523 upRect.moveTop( upRect.top() + yStep );
524 float upCost = d->rectCost( upRect );
525 QRectF downRect = bestRect;
526 downRect.moveTop( downRect.top() - yStep );
527 float downCost = d->rectCost( downRect );
528 QRectF leftRect = bestRect;
529 leftRect.moveLeft( leftRect.left() - xStep );
530 float leftCost = d->rectCost( leftRect );
531 QRectF rightRect = bestRect;
532 rightRect.moveLeft( rightRect.left() + xStep );
533 float rightCost = d->rectCost( rightRect );
534
535 //which direction leads to the lowest cost?
536 QList<float> costList;
537 costList << upCost << downCost << leftCost << rightCost;
538 int imin = -1;
539 for ( int i=0; i<costList.size(); ++i ) {
540 if ( iter == 0 && TriedPathIndex.contains( i ) ) {
541 continue; //Skip this first-step path, we already tried it!
542 }
543
544 //If this first-step path doesn't improve the cost,
545 //skip this direction from now on
546 if ( iter == 0 && costList[i] >= bestCost ) {
547 TriedPathIndex.append( i );
548 continue;
549 }
550
551 if ( costList[i] < bestCost && (imin < 0 || costList[i] < costList[imin]) ) {
552
553 imin = i;
554 }
555 }
556
557 //Make a note that we've tried the current first-step path
558 if ( iter == 0 && imin >= 0 ) {
559 TriedPathIndex.append( imin );
560 }
561
562 //Adopt the step that produced the best cost
563 switch ( imin ) {
564 case 0: //up
565 bestRect.moveTop( upRect.top() );
566 bestCost = upCost;
567 break;
568 case 1: //down
569 bestRect.moveTop( downRect.top() );
570 bestCost = downCost;
571 break;
572 case 2: //left
573 bestRect.moveLeft( leftRect.left() );
574 bestCost = leftCost;
575 break;
576 case 3: //right
577 bestRect.moveLeft( rightRect.left() );
578 bestCost = rightCost;
579 break;
580 case -1: //no lower cost found!
581 //We hit a local minimum. Keep the best of these as bestBadRect
582 if ( bestCost < bestBadCost ) {
583 bestBadCost = bestCost;
584 bestBadRect = bestRect;
585 }
586
587 //If all of the first-step paths have now been searched, we'll
588 //have to adopt the bestBadRect
589 if ( TriedPathIndex.size() == 4 ) {
590 bestRect = bestBadRect;
591 flagStop = true; //halt iteration
592 break;
593 }
594
595 //If we haven't yet tried all of the first-step paths, start over
596 if ( TriedPathIndex.size() < 4 ) {
597 iter = -1; //anticipating the ++iter below
598 bestRect = fm.boundingRect( QRectF( pos.x(), pos.y(), 1, 1 ), textFlags, pp->label() );
599 bestCost = d->rectCost( bestRect );
600 }
601 break;
602 }
603
604 //Halt iteration, because we've tried all directions and
605 //haven't gotten below maxCost (we'll adopt the best
606 //local minimum found)
607 if ( flagStop ) {
608 break;
609 }
610
611 ++iter;
612 }
613
614 painter->drawText( bestRect, textFlags, pp->label() );
615
616 //Is a line needed to connect the label to the point?
617 float deltax = pos.x() - bestRect.center().x();
618 float deltay = pos.y() - bestRect.center().y();
619 float rbest = sqrt( deltax*deltax + deltay*deltay );
620 if ( rbest > 20.0 ) {
621 //Draw a rectangle around the label
622 painter->setBrush( QBrush() );
623 //QPen pen = painter->pen();
624 //pen.setStyle( Qt::DotLine );
625 //painter->setPen( pen );
626 painter->drawRoundRect( bestRect );
627
628 //Now connect the label to the point with a line.
629 //The line is drawn from the center of the near edge of the rectangle
630 float xline = bestRect.center().x();
631 if ( bestRect.left() > pos.x() )
632 xline = bestRect.left();
633 if ( bestRect.right() < pos.x() )
634 xline = bestRect.right();
635
636 float yline = bestRect.center().y();
637 if ( bestRect.top() > pos.y() )
638 yline = bestRect.top();
639 if ( bestRect.bottom() < pos.y() )
640 yline = bestRect.bottom();
641
642 painter->drawLine( QPointF( xline, yline ), pos );
643 }
644
645 //Mask the label's rectangle so other labels won't overlap it.
646 maskRect( bestRect );
647}
648
649float KPlotWidget::Private::rectCost( const QRectF &r ) const
650{
651 if ( ! plotMask.rect().contains( r.toRect() ) ) {
652 return 10000.;
653 }
654
655 //Compute sum of mask values in the rect r
656 QImage subMask = plotMask.copy( r.toRect() );
657 int cost = 0;
658 for ( int ix=0; ix<subMask.width(); ++ix ) {
659 for ( int iy=0; iy<subMask.height(); ++iy ) {
660 cost += QColor( subMask.pixel( ix, iy ) ).red();
661 }
662 }
663
664 return float(cost);
665}
666
667void KPlotWidget::paintEvent( QPaintEvent *e ) {
668 // let QFrame draw its default stuff (like the frame)
669 QFrame::paintEvent( e );
670 QPainter p;
671
672 p.begin( this );
673 p.setRenderHint( QPainter::Antialiasing, d->useAntialias );
674 p.fillRect( rect(), backgroundColor() );
675 p.translate( leftPadding() + 0.5, topPadding() + 0.5 );
676
677 setPixRect();
678 p.setClipRect( d->pixRect );
679 p.setClipping( true );
680
681 resetPlotMask();
682
683 foreach( KPlotObject *po, d->objectList )
684 po->draw( &p, this );
685
686//DEBUG: Draw the plot mask
687// p.drawImage( 0, 0, d->plotMask );
688
689 p.setClipping( false );
690 drawAxes( &p );
691
692 p.end();
693}
694
695void KPlotWidget::drawAxes( QPainter *p ) {
696 if ( d->showGrid ) {
697 p->setPen( gridColor() );
698
699 //Grid lines are placed at locations of primary axes' major tickmarks
700 //vertical grid lines
701 foreach ( double xx, axis(BottomAxis)->majorTickMarks() ) {
702 double px = d->pixRect.width() * (xx - d->dataRect.x()) / d->dataRect.width();
703 p->drawLine( QPointF( px, 0.0 ), QPointF( px, double(d->pixRect.height()) ) );
704 }
705 //horizontal grid lines
706 foreach( double yy, axis(LeftAxis)->majorTickMarks() ) {
707 double py = d->pixRect.height() * ( 1.0 - (yy - d->dataRect.y()) / d->dataRect.height() );
708 p->drawLine( QPointF( 0.0, py ), QPointF( double(d->pixRect.width()), py ) );
709 }
710 }
711
712 p->setPen( foregroundColor() );
713 p->setBrush( Qt::NoBrush );
714
715 //set small font for tick labels
716 QFont f = p->font();
717 int s = f.pointSize();
718 f.setPointSize( s - 2 );
719 p->setFont( f );
720
721 /*** BottomAxis ***/
722 KPlotAxis *a = axis(BottomAxis);
723 if (a->isVisible()) {
724 //Draw axis line
725 p->drawLine( 0, d->pixRect.height(), d->pixRect.width(), d->pixRect.height() );
726
727 // Draw major tickmarks
728 foreach( double xx, a->majorTickMarks() ) {
729 double px = d->pixRect.width() * (xx - d->dataRect.x()) / d->dataRect.width();
730 if ( px > 0 && px < d->pixRect.width() ) {
731 p->drawLine( QPointF( px, double(d->pixRect.height() - TICKOFFSET)),
732 QPointF( px, double(d->pixRect.height() - BIGTICKSIZE - TICKOFFSET)) );
733
734 //Draw ticklabel
735 if ( a->areTickLabelsShown() ) {
736 QRect r( int(px) - BIGTICKSIZE, d->pixRect.height()+BIGTICKSIZE, 2*BIGTICKSIZE, BIGTICKSIZE );
737 p->drawText( r, Qt::AlignCenter | Qt::TextDontClip, a->tickLabel( xx ) );
738 }
739 }
740 }
741
742 // Draw minor tickmarks
743 foreach ( double xx, a->minorTickMarks() ) {
744 double px = d->pixRect.width() * (xx - d->dataRect.x()) / d->dataRect.width();
745 if ( px > 0 && px < d->pixRect.width() ) {
746 p->drawLine( QPointF( px, double(d->pixRect.height() - TICKOFFSET)),
747 QPointF( px, double(d->pixRect.height() - SMALLTICKSIZE -TICKOFFSET)) );
748 }
749 }
750
751 // Draw BottomAxis Label
752 if ( ! a->label().isEmpty() ) {
753 QRect r( 0, d->pixRect.height() + 2*YPADDING, d->pixRect.width(), YPADDING );
754 p->drawText( r, Qt::AlignCenter, a->label() );
755 }
756 } //End of BottomAxis
757
758 /*** LeftAxis ***/
759 a = axis(LeftAxis);
760 if (a->isVisible()) {
761 //Draw axis line
762 p->drawLine( 0, 0, 0, d->pixRect.height() );
763
764 // Draw major tickmarks
765 foreach( double yy, a->majorTickMarks() ) {
766 double py = d->pixRect.height() * ( 1.0 - (yy - d->dataRect.y()) / d->dataRect.height() );
767 if ( py > 0 && py < d->pixRect.height() ) {
768 p->drawLine( QPointF( TICKOFFSET, py ), QPointF( double(TICKOFFSET + BIGTICKSIZE), py ) );
769
770 //Draw ticklabel
771 if ( a->areTickLabelsShown() ) {
772 QRect r( -2*BIGTICKSIZE-SMALLTICKSIZE, int(py)-SMALLTICKSIZE, 2*BIGTICKSIZE, 2*SMALLTICKSIZE );
773 p->drawText( r, Qt::AlignRight | Qt::AlignVCenter | Qt::TextDontClip, a->tickLabel( yy ) );
774 }
775 }
776 }
777
778 // Draw minor tickmarks
779 foreach ( double yy, a->minorTickMarks() ) {
780 double py = d->pixRect.height() * ( 1.0 - (yy - d->dataRect.y()) / d->dataRect.height() );
781 if ( py > 0 && py < d->pixRect.height() ) {
782 p->drawLine( QPointF( TICKOFFSET, py ), QPointF( double(TICKOFFSET + SMALLTICKSIZE), py ) );
783 }
784 }
785
786 //Draw LeftAxis Label. We need to draw the text sideways.
787 if ( ! a->label().isEmpty() ) {
788 //store current painter translation/rotation state
789 p->save();
790
791 //translate coord sys to left corner of axis label rectangle, then rotate 90 degrees.
792 p->translate( -3*XPADDING, d->pixRect.height() );
793 p->rotate( -90.0 );
794
795 QRect r( 0, 0, d->pixRect.height(), XPADDING );
796 p->drawText( r, Qt::AlignCenter, a->label() ); //draw the label, now that we are sideways
797
798 p->restore(); //restore translation/rotation state
799 }
800 } //End of LeftAxis
801
802 //Prepare for top and right axes; we may need the secondary data rect
803 double x0 = d->dataRect.x();
804 double y0 = d->dataRect.y();
805 double dw = d->dataRect.width();
806 double dh = d->dataRect.height();
807 if ( secondaryDataRect().isValid() ) {
808 x0 = secondaryDataRect().x();
809 y0 = secondaryDataRect().y();
810 dw = secondaryDataRect().width();
811 dh = secondaryDataRect().height();
812 }
813
814 /*** TopAxis ***/
815 a = axis(TopAxis);
816 if (a->isVisible()) {
817 //Draw axis line
818 p->drawLine( 0, 0, d->pixRect.width(), 0 );
819
820 // Draw major tickmarks
821 foreach( double xx, a->majorTickMarks() ) {
822 double px = d->pixRect.width() * (xx - x0) / dw;
823 if ( px > 0 && px < d->pixRect.width() ) {
824 p->drawLine( QPointF( px, TICKOFFSET ), QPointF( px, double(BIGTICKSIZE + TICKOFFSET)) );
825
826 //Draw ticklabel
827 if ( a->areTickLabelsShown() ) {
828 QRect r( int(px) - BIGTICKSIZE, (int)-1.5*BIGTICKSIZE, 2*BIGTICKSIZE, BIGTICKSIZE );
829 p->drawText( r, Qt::AlignCenter | Qt::TextDontClip, a->tickLabel( xx ) );
830 }
831 }
832 }
833
834 // Draw minor tickmarks
835 foreach ( double xx, a->minorTickMarks() ) {
836 double px = d->pixRect.width() * (xx - x0) / dw;
837 if ( px > 0 && px < d->pixRect.width() ) {
838 p->drawLine( QPointF( px, TICKOFFSET ), QPointF( px, double(SMALLTICKSIZE + TICKOFFSET)) );
839 }
840 }
841
842 // Draw TopAxis Label
843 if ( ! a->label().isEmpty() ) {
844 QRect r( 0, 0 - 3*YPADDING, d->pixRect.width(), YPADDING );
845 p->drawText( r, Qt::AlignCenter, a->label() );
846 }
847 } //End of TopAxis
848
849 /*** RightAxis ***/
850 a = axis(RightAxis);
851 if (a->isVisible()) {
852 //Draw axis line
853 p->drawLine( d->pixRect.width(), 0, d->pixRect.width(), d->pixRect.height() );
854
855 // Draw major tickmarks
856 foreach( double yy, a->majorTickMarks() ) {
857 double py = d->pixRect.height() * ( 1.0 - (yy - y0) / dh );
858 if ( py > 0 && py < d->pixRect.height() ) {
859 p->drawLine( QPointF( double(d->pixRect.width() - TICKOFFSET), py ),
860 QPointF( double(d->pixRect.width() - TICKOFFSET - BIGTICKSIZE), py ) );
861
862 //Draw ticklabel
863 if ( a->areTickLabelsShown() ) {
864 QRect r( d->pixRect.width() + SMALLTICKSIZE, int(py)-SMALLTICKSIZE, 2*BIGTICKSIZE, 2*SMALLTICKSIZE );
865 p->drawText( r, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip, a->tickLabel( yy ) );
866 }
867 }
868 }
869
870 // Draw minor tickmarks
871 foreach ( double yy, a->minorTickMarks() ) {
872 double py = d->pixRect.height() * ( 1.0 - (yy - y0) / dh );
873 if ( py > 0 && py < d->pixRect.height() ) {
874 p->drawLine( QPointF( double(d->pixRect.width() - 0.0), py ),
875 QPointF( double(d->pixRect.width() - 0.0 - SMALLTICKSIZE), py ) );
876 }
877 }
878
879 //Draw RightAxis Label. We need to draw the text sideways.
880 if ( ! a->label().isEmpty() ) {
881 //store current painter translation/rotation state
882 p->save();
883
884 //translate coord sys to left corner of axis label rectangle, then rotate 90 degrees.
885 p->translate( d->pixRect.width() + 2*XPADDING, d->pixRect.height() );
886 p->rotate( -90.0 );
887
888 QRect r( 0, 0, d->pixRect.height(), XPADDING );
889 p->drawText( r, Qt::AlignCenter, a->label() ); //draw the label, now that we are sideways
890
891 p->restore(); //restore translation/rotation state
892 }
893 } //End of RightAxis
894}
895
896int KPlotWidget::leftPadding() const
897{
898 if ( d->leftPadding >= 0 )
899 return d->leftPadding;
900 const KPlotAxis *a = axis( LeftAxis );
901 if ( a && a->isVisible() && a->areTickLabelsShown() )
902 {
903 return !a->label().isEmpty() ? 3 * XPADDING : 2 * XPADDING;
904 }
905 return XPADDING;
906}
907
908int KPlotWidget::rightPadding() const
909{
910 if ( d->rightPadding >= 0 )
911 return d->rightPadding;
912 const KPlotAxis *a = axis( RightAxis );
913 if ( a && a->isVisible() && a->areTickLabelsShown() )
914 {
915 return !a->label().isEmpty() ? 3 * XPADDING : 2 * XPADDING;
916 }
917 return XPADDING;
918}
919
920int KPlotWidget::topPadding() const
921{
922 if ( d->topPadding >= 0 )
923 return d->topPadding;
924 const KPlotAxis *a = axis( TopAxis );
925 if ( a && a->isVisible() && a->areTickLabelsShown() )
926 {
927 return !a->label().isEmpty() ? 3 * YPADDING : 2 * YPADDING;
928 }
929 return YPADDING;
930}
931
932int KPlotWidget::bottomPadding() const
933{
934 if ( d->bottomPadding >= 0 )
935 return d->bottomPadding;
936 const KPlotAxis *a = axis( BottomAxis );
937 if ( a && a->isVisible() && a->areTickLabelsShown() )
938 {
939 return !a->label().isEmpty() ? 3 * YPADDING : 2 * YPADDING;
940 }
941 return YPADDING;
942}
943
944void KPlotWidget::setLeftPadding( int padding )
945{
946 d->leftPadding = padding;
947}
948
949void KPlotWidget::setRightPadding( int padding )
950{
951 d->rightPadding = padding;
952}
953
954void KPlotWidget::setTopPadding( int padding )
955{
956 d->topPadding = padding;
957}
958
959void KPlotWidget::setBottomPadding( int padding )
960{
961 d->bottomPadding = padding;
962}
963
964void KPlotWidget::setDefaultPaddings()
965{
966 d->leftPadding = -1;
967 d->rightPadding = -1;
968 d->topPadding = -1;
969 d->bottomPadding = -1;
970}
971
KPlotAxis
Axis for KPlotWidget.
Definition: kplotaxis.h:37
KPlotAxis::majorTickMarks
QList< double > majorTickMarks() const
Definition: kplotaxis.cpp:191
KPlotAxis::setTickMarks
void setTickMarks(double x0, double length)
Determine the positions of major and minor tickmarks for this axis.
Definition: kplotaxis.cpp:113
KPlotAxis::isVisible
bool isVisible() const
Definition: kplotaxis.cpp:61
KPlotAxis::setLabel
void setLabel(const QString &label)
Sets the axis label.
Definition: kplotaxis.cpp:81
KPlotAxis::label
QString label() const
Definition: kplotaxis.cpp:86
KPlotAxis::setTickLabelsShown
void setTickLabelsShown(bool b)
Determine whether tick labels will be drawn for this axis.
Definition: kplotaxis.cpp:76
KPlotAxis::areTickLabelsShown
bool areTickLabelsShown() const
Definition: kplotaxis.cpp:71
KPlotAxis::minorTickMarks
QList< double > minorTickMarks() const
Definition: kplotaxis.cpp:196
KPlotAxis::tickLabel
QString tickLabel(double value) const
Definition: kplotaxis.cpp:178
KPlotObject
Encapsulates a data set to be plotted in a KPlotWidget.
Definition: kplotobject.h:53
KPlotObject::draw
void draw(QPainter *p, KPlotWidget *pw)
Draw this KPlotObject on the given QPainter.
Definition: kplotobject.cpp:233
KPlotObject::points
QList< KPlotPoint * > points() const
Definition: kplotobject.cpp:196
KPlotPoint
Encapsulates a point in the plot.
Definition: kplotpoint.h:40
KPlotPoint::position
QPointF position() const
Definition: kplotpoint.cpp:63
KPlotPoint::label
QString label() const
Definition: kplotpoint.cpp:93
KPlotWidget
Generic data plotting widget.
Definition: kplotwidget.h:80
KPlotWidget::secondaryDataRect
QRectF secondaryDataRect() const
Definition: kplotwidget.cpp:205
KPlotWidget::isObjectToolTipShown
bool isObjectToolTipShown() const
Definition: kplotwidget.cpp:318
KPlotWidget::plotObjects
QList< KPlotObject * > plotObjects() const
Definition: kplotwidget.cpp:234
KPlotWidget::resetPlot
void resetPlot()
Clear the object list, reset the data limits, and remove axis labels.
Definition: kplotwidget.cpp:256
KPlotWidget::setPixRect
void setPixRect()
Synchronize the PixRect with the current widget size and padding settings.
Definition: kplotwidget.cpp:398
KPlotWidget::setSecondaryLimits
void setSecondaryLimits(double x1, double x2, double y1, double y2)
Reset the secondary data limits, which control the values displayed along the top and right axes.
Definition: kplotwidget.cpp:169
KPlotWidget::rightPadding
int rightPadding
Definition: kplotwidget.h:83
KPlotWidget::setRightPadding
void setRightPadding(int padding)
Set the number of pixels to the right of the plot area.
Definition: kplotwidget.cpp:949
KPlotWidget::setBackgroundColor
void setBackgroundColor(const QColor &bg)
Set the background color.
Definition: kplotwidget.cpp:296
KPlotWidget::dataRect
QRectF dataRect() const
Definition: kplotwidget.cpp:200
KPlotWidget::topPadding
int topPadding
Definition: kplotwidget.h:84
KPlotWidget::mapToWidget
QPointF mapToWidget(const QPointF &p) const
Map a coordinate.
Definition: kplotwidget.cpp:405
KPlotWidget::axis
KPlotAxis * axis(Axis type)
Definition: kplotwidget.cpp:345
KPlotWidget::foregroundColor
QColor foregroundColor
Definition: kplotwidget.h:87
KPlotWidget::setObjectToolTipShown
void setObjectToolTipShown(bool show)
Toggle the display of a tooltip for point objects.
Definition: kplotwidget.cpp:339
KPlotWidget::setShowGrid
void setShowGrid(bool show)
Toggle whether grid lines are drawn at major tickmarks.
Definition: kplotwidget.cpp:334
KPlotWidget::pointsUnderPoint
QList< KPlotPoint * > pointsUnderPoint(const QPoint &p) const
Definition: kplotwidget.cpp:362
KPlotWidget::placeLabel
void placeLabel(QPainter *painter, KPlotPoint *pp)
Place an object label optimally in the plot.
Definition: kplotwidget.cpp:489
KPlotWidget::drawAxes
virtual void drawAxes(QPainter *p)
Draws the plot axes and axis labels.
Definition: kplotwidget.cpp:695
KPlotWidget::bottomPadding
int bottomPadding
Definition: kplotwidget.h:85
KPlotWidget::maskAlongLine
void maskAlongLine(const QPointF &p1, const QPointF &p2, float value=1.0)
Indicate that object labels should try to avoid the line joining the two given points (in pixel coord...
Definition: kplotwidget.cpp:427
KPlotWidget::setForegroundColor
void setForegroundColor(const QColor &fg)
Set the foreground color.
Definition: kplotwidget.cpp:301
KPlotWidget::KPlotWidget
KPlotWidget(QWidget *parent=0)
Constructor.
Definition: kplotwidget.cpp:104
KPlotWidget::replacePlotObject
void replacePlotObject(int i, KPlotObject *o)
Replace an item in the KPlotObject list.
Definition: kplotwidget.cpp:272
KPlotWidget::backgroundColor
QColor backgroundColor
Definition: kplotwidget.h:86
KPlotWidget::setLimits
void setLimits(double x1, double x2, double y1, double y2)
Set new data limits for the plot.
Definition: kplotwidget.cpp:135
KPlotWidget::addPlotObject
void addPlotObject(KPlotObject *object)
Add an item to the list of KPlotObjects to be plotted.
Definition: kplotwidget.cpp:210
KPlotWidget::~KPlotWidget
virtual ~KPlotWidget()
Destructor.
Definition: kplotwidget.cpp:120
KPlotWidget::gridColor
QColor gridColor
Definition: kplotwidget.h:88
KPlotWidget::resizeEvent
virtual void resizeEvent(QResizeEvent *)
The resize event handler, called when the widget is resized.
Definition: kplotwidget.cpp:392
KPlotWidget::setLeftPadding
void setLeftPadding(int padding)
Set the number of pixels to the left of the plot area.
Definition: kplotwidget.cpp:944
KPlotWidget::leftPadding
int leftPadding
Definition: kplotwidget.h:82
KPlotWidget::setGridColor
void setGridColor(const QColor &gc)
Set the grid color.
Definition: kplotwidget.cpp:307
KPlotWidget::setAntialiasing
void setAntialiasing(bool b)
Toggle antialiased drawing.
Definition: kplotwidget.cpp:328
KPlotWidget::resetPlotMask
void resetPlotMask()
Reset the mask used for non-overlapping labels so that all regions of the plot area are considered em...
Definition: kplotwidget.cpp:249
KPlotWidget::maskRect
void maskRect(const QRectF &r, float value=1.0)
Indicate that object labels should try to avoid the given rectangle in the plot.
Definition: kplotwidget.cpp:412
KPlotWidget::sizeHint
virtual QSize sizeHint() const
Definition: kplotwidget.cpp:130
KPlotWidget::pixRect
QRect pixRect() const
Definition: kplotwidget.cpp:357
KPlotWidget::minimumSizeHint
virtual QSize minimumSizeHint() const
Definition: kplotwidget.cpp:125
KPlotWidget::paintEvent
virtual void paintEvent(QPaintEvent *)
The paint event handler, executed when update() or repaint() is called.
Definition: kplotwidget.cpp:667
KPlotWidget::Axis
Axis
The four types of plot axes.
Definition: kplotwidget.h:107
KPlotWidget::BottomAxis
@ BottomAxis
the bottom axis
Definition: kplotwidget.h:109
KPlotWidget::TopAxis
@ TopAxis
the top axis
Definition: kplotwidget.h:111
KPlotWidget::LeftAxis
@ LeftAxis
the left axis
Definition: kplotwidget.h:108
KPlotWidget::RightAxis
@ RightAxis
the right axis
Definition: kplotwidget.h:110
KPlotWidget::setDefaultPaddings
void setDefaultPaddings()
Revert all four padding values to -1, so that they will be automatically determined.
Definition: kplotwidget.cpp:964
KPlotWidget::setBottomPadding
void setBottomPadding(int padding)
Set the number of pixels below the plot area.
Definition: kplotwidget.cpp:959
KPlotWidget::addPlotObjects
void addPlotObjects(const QList< KPlotObject * > &objects)
Add more than one KPlotObject at one time.
Definition: kplotwidget.cpp:219
KPlotWidget::event
virtual bool event(QEvent *)
Generic event handler.
Definition: kplotwidget.cpp:375
KPlotWidget::isGridShown
bool isGridShown() const
Definition: kplotwidget.cpp:313
KPlotWidget::clearSecondaryLimits
void clearSecondaryLimits()
Unset the secondary limits, so the top and right axes show the same tickmarks as the bottom and left ...
Definition: kplotwidget.cpp:192
KPlotWidget::antialiasing
bool antialiasing() const
Definition: kplotwidget.cpp:323
KPlotWidget::setTopPadding
void setTopPadding(int padding)
Set the number of pixels above the plot area.
Definition: kplotwidget.cpp:954
KPlotWidget::removeAllPlotObjects
void removeAllPlotObjects()
Remove and delete all items from the list of KPlotObjects.
Definition: kplotwidget.cpp:239
QFrame
QHash
QList
QWidget
kWarning
#define kWarning
kdebug.h
kplotaxis.h
kplotobject.h
kplotpoint.h
XPADDING
#define XPADDING
Definition: kplotwidget.cpp:38
TICKOFFSET
#define TICKOFFSET
Definition: kplotwidget.cpp:42
YPADDING
#define YPADDING
Definition: kplotwidget.cpp:39
BIGTICKSIZE
#define BIGTICKSIZE
Definition: kplotwidget.cpp:40
SMALLTICKSIZE
#define SMALLTICKSIZE
Definition: kplotwidget.cpp:41
kplotwidget.h
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal