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

KDEUI

  • sources
  • kde-4.12
  • kdelibs
  • 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 
44 class KPlotWidget::Private
45 {
46 public:
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 
104 KPlotWidget::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 
120 KPlotWidget::~KPlotWidget()
121 {
122  delete d;
123 }
124 
125 QSize KPlotWidget::minimumSizeHint() const
126 {
127  return QSize( 150, 150 );
128 }
129 
130 QSize KPlotWidget::sizeHint() const
131 {
132  return size();
133 }
134 
135 void KPlotWidget::setLimits( double x1, double x2, double y1, double y2 )
136 {
137  d->calcDataRectLimits( x1, x2, y1, y2 );
138  update();
139 }
140 
141 void 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 
169 void 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 
192 void 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 
200 QRectF KPlotWidget::dataRect() const
201 {
202  return d->dataRect;
203 }
204 
205 QRectF KPlotWidget::secondaryDataRect() const
206 {
207  return d->secondDataRect;
208 }
209 
210 void KPlotWidget::addPlotObject( KPlotObject *object )
211 {
212  // skip null pointers
213  if ( !object )
214  return;
215  d->objectList.append( object );
216  update();
217 }
218 
219 void 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 
234 QList< KPlotObject* > KPlotWidget::plotObjects() const
235 {
236  return d->objectList;
237 }
238 
239 void KPlotWidget::removeAllPlotObjects()
240 {
241  if ( d->objectList.isEmpty() )
242  return;
243 
244  qDeleteAll( d->objectList );
245  d->objectList.clear();
246  update();
247 }
248 
249 void 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 
256 void 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 
272 void 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 
281 QColor KPlotWidget::backgroundColor() const
282 {
283  return d->cBackground;
284 }
285 
286 QColor KPlotWidget::foregroundColor() const
287 {
288  return d->cForeground;
289 }
290 
291 QColor KPlotWidget::gridColor() const
292 {
293  return d->cGrid;
294 }
295 
296 void KPlotWidget::setBackgroundColor( const QColor &bg ) {
297  d->cBackground = bg;
298  update();
299 }
300 
301 void KPlotWidget::setForegroundColor( const QColor &fg )
302 {
303  d->cForeground = fg;
304  update();
305 }
306 
307 void KPlotWidget::setGridColor( const QColor &gc )
308 {
309  d->cGrid = gc;
310  update();
311 }
312 
313 bool KPlotWidget::isGridShown() const
314 {
315  return d->showGrid;
316 }
317 
318 bool KPlotWidget::isObjectToolTipShown() const
319 {
320  return d->showObjectToolTip;
321 }
322 
323 bool KPlotWidget::antialiasing() const
324 {
325  return d->useAntialias;
326 }
327 
328 void KPlotWidget::setAntialiasing( bool b )
329 {
330  d->useAntialias = b;
331  update();
332 }
333 
334 void KPlotWidget::setShowGrid( bool show ) {
335  d->showGrid = show;
336  update();
337 }
338 
339 void KPlotWidget::setObjectToolTipShown( bool show )
340 {
341  d->showObjectToolTip = show;
342 }
343 
344 
345 KPlotAxis* 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 
351 const 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 
357 QRect KPlotWidget::pixRect() const
358 {
359  return d->pixRect;
360 }
361 
362 QList<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 
375 bool 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 
392 void KPlotWidget::resizeEvent( QResizeEvent* e ) {
393  QFrame::resizeEvent( e );
394  setPixRect();
395  resetPlotMask();
396 }
397 
398 void 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 
405 QPointF 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 
412 void 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 
427 void 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.
489 void 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 
649 float 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 
667 void 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 
695 void 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 
896 int 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 
908 int 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 
920 int 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 
932 int 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 
944 void KPlotWidget::setLeftPadding( int padding )
945 {
946  d->leftPadding = padding;
947 }
948 
949 void KPlotWidget::setRightPadding( int padding )
950 {
951  d->rightPadding = padding;
952 }
953 
954 void KPlotWidget::setTopPadding( int padding )
955 {
956  d->topPadding = padding;
957 }
958 
959 void KPlotWidget::setBottomPadding( int padding )
960 {
961  d->bottomPadding = padding;
962 }
963 
964 void KPlotWidget::setDefaultPaddings()
965 {
966  d->leftPadding = -1;
967  d->rightPadding = -1;
968  d->topPadding = -1;
969  d->bottomPadding = -1;
970 }
971 
QColor
KPlotPoint
Encapsulates a point in the plot.
Definition: kplotpoint.h:40
KPlotWidget::setBottomPadding
void setBottomPadding(int padding)
Set the number of pixels below the plot area.
Definition: kplotwidget.cpp:959
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
KPlotAxis::label
QString label() const
Definition: kplotaxis.cpp:86
kdebug.h
KPlotWidget::~KPlotWidget
virtual ~KPlotWidget()
Destructor.
Definition: kplotwidget.cpp:120
KPlotWidget::setPixRect
void setPixRect()
Synchronize the PixRect with the current widget size and padding settings.
Definition: kplotwidget.cpp:398
XPADDING
#define XPADDING
Definition: kplotwidget.cpp:38
KPlotObject::draw
void draw(QPainter *p, KPlotWidget *pw)
Draw this KPlotObject on the given QPainter.
Definition: kplotobject.cpp:233
KPlotAxis::isVisible
bool isVisible() const
Definition: kplotaxis.cpp:61
KPlotWidget::KPlotWidget
KPlotWidget(QWidget *parent=0)
Constructor.
Definition: kplotwidget.cpp:104
KPlotWidget::paintEvent
virtual void paintEvent(QPaintEvent *)
The paint event handler, executed when update() or repaint() is called.
Definition: kplotwidget.cpp:667
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::topPadding
int topPadding() const
KPlotWidget::minimumSizeHint
virtual QSize minimumSizeHint() const
Definition: kplotwidget.cpp:125
QWidget
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::drawAxes
virtual void drawAxes(QPainter *p)
Draws the plot axes and axis labels.
Definition: kplotwidget.cpp:695
QString
KPlotPoint::label
QString label() const
Definition: kplotpoint.cpp:93
QHash< Axis, KPlotAxis * >
BIGTICKSIZE
#define BIGTICKSIZE
Definition: kplotwidget.cpp:40
KPlotWidget::secondaryDataRect
QRectF secondaryDataRect() const
Definition: kplotwidget.cpp:205
KPlotObject::points
QList< KPlotPoint * > points() const
Definition: kplotobject.cpp:196
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::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
KPlotAxis::minorTickMarks
QList< double > minorTickMarks() const
Definition: kplotaxis.cpp:196
kplotpoint.h
KPlotWidget::backgroundColor
QColor backgroundColor() const
KPlotWidget::removeAllPlotObjects
void removeAllPlotObjects()
Remove and delete all items from the list of KPlotObjects.
Definition: kplotwidget.cpp:239
KPlotWidget::Axis
Axis
The four types of plot axes.
Definition: kplotwidget.h:106
KPlotWidget::leftPadding
int leftPadding() const
KPlotAxis::tickLabel
QString tickLabel(double value) const
Definition: kplotaxis.cpp:178
KPlotWidget::bottomPadding
int bottomPadding() const
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
kplotaxis.h
KPlotWidget::addPlotObjects
void addPlotObjects(const QList< KPlotObject * > &objects)
Add more than one KPlotObject at one time.
Definition: kplotwidget.cpp:219
KPlotObject
Encapsulates a data set to be plotted in a KPlotWidget.
Definition: kplotobject.h:53
KPlotWidget::axis
KPlotAxis * axis(Axis type)
Definition: kplotwidget.cpp:345
YPADDING
#define YPADDING
Definition: kplotwidget.cpp:39
KPlotWidget::setAntialiasing
void setAntialiasing(bool b)
Toggle antialiased drawing.
Definition: kplotwidget.cpp:328
KPlotWidget::setForegroundColor
void setForegroundColor(const QColor &fg)
Set the foreground color.
Definition: kplotwidget.cpp:301
KPlotWidget::setObjectToolTipShown
void setObjectToolTipShown(bool show)
Toggle the display of a tooltip for point objects.
Definition: kplotwidget.cpp:339
KPlotWidget::placeLabel
void placeLabel(QPainter *painter, KPlotPoint *pp)
Place an object label optimally in the plot.
Definition: kplotwidget.cpp:489
KPlotWidget
Generic data plotting widget.
Definition: kplotwidget.h:80
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
KPlotWidget::isGridShown
bool isGridShown() const
Definition: kplotwidget.cpp:313
KPlotWidget::TopAxis
the top axis
Definition: kplotwidget.h:111
KPlotWidget::rightPadding
int rightPadding() const
KPlotWidget::setDefaultPaddings
void setDefaultPaddings()
Revert all four padding values to -1, so that they will be automatically determined.
Definition: kplotwidget.cpp:964
KPlotWidget::mapToWidget
QPointF mapToWidget(const QPointF &p) const
Map a coordinate.
Definition: kplotwidget.cpp:405
KPlotAxis
Axis for KPlotWidget.
Definition: kplotaxis.h:37
TICKOFFSET
#define TICKOFFSET
Definition: kplotwidget.cpp:42
KPlotWidget::LeftAxis
the left axis
Definition: kplotwidget.h:108
KPlotWidget::event
virtual bool event(QEvent *)
Generic event handler.
Definition: kplotwidget.cpp:375
KPlotWidget::pixRect
QRect pixRect() const
Definition: kplotwidget.cpp:357
KPlotWidget::gridColor
QColor gridColor() const
QFont
KPlotWidget::setLeftPadding
void setLeftPadding(int padding)
Set the number of pixels to the left of the plot area.
Definition: kplotwidget.cpp:944
KPlotAxis::setLabel
void setLabel(const QString &label)
Sets the axis label.
Definition: kplotaxis.cpp:81
KPlotWidget::sizeHint
virtual QSize sizeHint() const
Definition: kplotwidget.cpp:130
KPlotAxis::setTickMarks
void setTickMarks(double x0, double length)
Determine the positions of major and minor tickmarks for this axis.
Definition: kplotaxis.cpp:113
QPoint
KPlotWidget::resetPlot
void resetPlot()
Clear the object list, reset the data limits, and remove axis labels.
Definition: kplotwidget.cpp:256
QRect
KPlotWidget::setBackgroundColor
void setBackgroundColor(const QColor &bg)
Set the background color.
Definition: kplotwidget.cpp:296
KPlotWidget::replacePlotObject
void replacePlotObject(int i, KPlotObject *o)
Replace an item in the KPlotObject list.
Definition: kplotwidget.cpp:272
kplotwidget.h
KPlotWidget::antialiasing
bool antialiasing() const
Definition: kplotwidget.cpp:323
kWarning
static QDebug kWarning(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
SMALLTICKSIZE
#define SMALLTICKSIZE
Definition: kplotwidget.cpp:41
QSize
KPlotWidget::RightAxis
the right axis
Definition: kplotwidget.h:110
KPlotWidget::BottomAxis
the bottom axis
Definition: kplotwidget.h:109
KPlotWidget::setTopPadding
void setTopPadding(int padding)
Set the number of pixels above the plot area.
Definition: kplotwidget.cpp:954
KPlotWidget::isObjectToolTipShown
bool isObjectToolTipShown() const
Definition: kplotwidget.cpp:318
KPlotAxis::majorTickMarks
QList< double > majorTickMarks() const
Definition: kplotaxis.cpp:191
KPlotWidget::resizeEvent
virtual void resizeEvent(QResizeEvent *)
The resize event handler, called when the widget is resized.
Definition: kplotwidget.cpp:392
KPlotWidget::dataRect
QRectF dataRect() const
Definition: kplotwidget.cpp:200
QFrame
KPlotWidget::setLimits
void setLimits(double x1, double x2, double y1, double y2)
Set new data limits for the plot.
Definition: kplotwidget.cpp:135
KPlotWidget::foregroundColor
QColor foregroundColor() const
KPlotWidget::setRightPadding
void setRightPadding(int padding)
Set the number of pixels to the right of the plot area.
Definition: kplotwidget.cpp:949
KPlotPoint::position
QPointF position() const
Definition: kplotpoint.cpp:63
KPlotWidget::setGridColor
void setGridColor(const QColor &gc)
Set the grid color.
Definition: kplotwidget.cpp:307
KPlotWidget::plotObjects
QList< KPlotObject * > plotObjects() const
Definition: kplotwidget.cpp:234
QList< KPlotObject * >
KPlotWidget::addPlotObject
void addPlotObject(KPlotObject *object)
Add an item to the list of KPlotObjects to be plotted.
Definition: kplotwidget.cpp:210
kplotobject.h
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:49:15 by doxygen 1.8.7 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 API Reference

Skip menu "kdelibs 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
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



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