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#ifndef KPLOTWIDGET_H
22#define KPLOTWIDGET_H
23
24#include <kdeui_export.h>
25
26#include <QtGui/QFrame>
27#include <QtCore/QList>
28
29class KPlotAxis;
30class KPlotObject;
31class KPlotPoint;
32
33/**
34 *@class KPlotWidget
35 *
36 *@short Generic data plotting widget.
37 *
38 *Widget for drawing plots. The basic idea behind KPlotWidget is that
39 *you don't have to worry about any transformation from your data's
40 *natural units to screen pixel coordinates; this is handled internally
41 *by the widget.
42 *
43 *Data to be plotted are represented by one or more instances of
44 *KPlotObject. KPlotObject contains a list of QPointFs to be plotted
45 *(again, in the data's natural units), as well as information about how
46 *the data are to be rendered in the plot (i.e., as separate points or
47 *connected by lines? With what color and point style? etc). See
48 *KPlotObject for more information.
49 *
50 *KPlotWidget automatically adds axis labels with tickmarks and tick
51 *labels. These are encapsulated in the KPlotAxis class. All you have
52 *to do is set the limits of the plotting area in data units, and
53 *KPlotWidget wil figure out the optimal positions and labels for the
54 *tickmarks on the axes.
55 *
56 *Example of usage:
57 *
58 * @code
59KPlotWidget *kpw = new KPlotWidget( parent );
60// setting our limits for the plot
61kpw->setLimits( 1.0, 5.0, 1.0, 25.0 );
62
63// creating a plot object whose points are connected by red lines ...
64KPlotObject *kpo = new KPlotObject( Qt::red, KPlotObject::Lines );
65// ... adding some points to it ...
66for ( float x = 1.0; x <= 5.0; x += 0.1 )
67 kpo->addPoint( x, x*x );
68
69// ... and adding the object to the plot widget
70kpw->addPlotObject( kpo );
71 * @endcode
72 *
73 *@note KPlotWidget will take care of the objects added to it, so when
74 *clearing the objects list (eg with removeAllPlotObjects()) any previous
75 *reference to a KPlotObject already added to a KPlotWidget will be invalid.
76 *
77 *@author Jason Harris
78 *@version 1.1
79 */
80class KDEUI_EXPORT KPlotWidget : public QFrame {
81 Q_OBJECT
82 Q_PROPERTY(int leftPadding READ leftPadding)
83 Q_PROPERTY(int rightPadding READ rightPadding)
84 Q_PROPERTY(int topPadding READ topPadding)
85 Q_PROPERTY(int bottomPadding READ bottomPadding)
86 Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor)
87 Q_PROPERTY(QColor foregroundColor READ foregroundColor WRITE setForegroundColor)
88 Q_PROPERTY(QColor gridColor READ gridColor WRITE setGridColor)
89 Q_PROPERTY(bool grid READ isGridShown WRITE setShowGrid)
90 Q_PROPERTY(bool objectToolTip READ isObjectToolTipShown WRITE setObjectToolTipShown)
91public:
92 /**
93 *@short Constructor.
94 *@param parent the parent widget
95 */
96 explicit KPlotWidget( QWidget * parent = 0 );
97
98 /**
99 *@short Destructor.
100 */
101 virtual ~KPlotWidget();
102
103 /**
104 * The four types of plot axes.
105 */
106 enum Axis
107 {
108 LeftAxis = 0, ///< the left axis
109 BottomAxis, ///< the bottom axis
110 RightAxis, ///< the right axis
111 TopAxis ///< the top axis
112 };
113
114 /**
115 *@return suggested minimum size for the plot widget
116 */
117 virtual QSize minimumSizeHint() const;
118
119 /**
120 *@return suggested size for the plot widget
121 */
122 virtual QSize sizeHint() const;
123
124 /**
125 * Set new data limits for the plot.
126 * @param x1 the minimum X value in data units
127 * @param x2 the maximum X value in data units
128 * @param y1 the minimum Y value in data units
129 * @param y2 the maximum Y value in data units
130 */
131 void setLimits( double x1, double x2, double y1, double y2 );
132
133 /**
134 * @short Reset the secondary data limits, which control the
135 * values displayed along the top and right axes.
136 *
137 * All data points are *plotted* using the coordinates
138 * defined by setLimits(), so this function is only useful for
139 * showing alternate tickmark labels along the top and right
140 * edges. For example, if you were plotting temperature on the
141 * X-axis, you could use Centigrade units for the primary
142 * (bottom) axis, using setLimits( 0.0, 100.0, 0.0, 1.0 ). If
143 * you also wanted to show Farenheit units along the secondary
144 * (top) axis, you would additionally use
145 * setSecondaryLimits( 32.0, 212.0, 0.0, 1.0 ). The data
146 * added to the plot would have x-coordinates in Centigrade degrees.
147 *
148 * @param x1 the minimum X value in secondary data units
149 * @param x2 the maximum X value in secondary data units
150 * @param y1 the minimum Y value in secondary data units
151 * @param y2 the maximum Y value in secondary data units
152 * @sa setLimits()
153 */
154 void setSecondaryLimits( double x1, double x2, double y1, double y2 );
155
156 /**
157 * Unset the secondary limits, so the top and right axes
158 * show the same tickmarks as the bottom and left axes (no tickmark
159 * labels will be drawn for the top and right axes in this case)
160 */
161 void clearSecondaryLimits();
162
163 /**
164 * @return the rectangle representing the boundaries of the current plot,
165 * in natural data units.
166 * @sa setLimits()
167 */
168 QRectF dataRect() const;
169
170 /**
171 * @return the rectangle representing the boundaries of the secondary
172 * data limits, if they have been set. Otherwise, this function
173 * behaves the same as dataRect().
174 * @sa setSecondaryLimits()
175 */
176 QRectF secondaryDataRect() const;
177
178 /**
179 * @return the rectangle representing the boundaries of the current plot,
180 * in screen pixel units.
181 */
182 QRect pixRect() const;
183
184 /**
185 * Add an item to the list of KPlotObjects to be plotted.
186 * @note do not use this multiple time if many objects have to be added,
187 * addPlotObjects() is strongly suggested in this case
188 * @param object the KPlotObject to be added
189 */
190 void addPlotObject( KPlotObject *object );
191
192 /**
193 * Add more than one KPlotObject at one time.
194 * @param objects the list of KPlotObjects to be added
195 */
196 void addPlotObjects( const QList< KPlotObject* >& objects );
197
198 /**
199 * @return the current list of plot objects
200 */
201 QList< KPlotObject* > plotObjects() const;
202
203 /**
204 * Remove and delete all items from the list of KPlotObjects
205 */
206 void removeAllPlotObjects();
207
208 /**
209 * Reset the mask used for non-overlapping labels so that all
210 * regions of the plot area are considered empty.
211 */
212 void resetPlotMask();
213
214 /**
215 * Clear the object list, reset the data limits, and remove axis labels
216 */
217 void resetPlot();
218
219 /**
220 * Replace an item in the KPlotObject list.
221 * @param i the index of the item to be replaced
222 * @param o pointer to the replacement KPlotObject
223 */
224 void replacePlotObject( int i, KPlotObject *o );
225
226 /**
227 * @return the background color of the plot.
228 *
229 * The default color is black.
230 */
231 QColor backgroundColor() const;
232
233 /**
234 * @return the foreground color, used for axes, tickmarks and associated
235 * labels.
236 *
237 * The default color is white.
238 */
239 QColor foregroundColor() const;
240
241 /**
242 * @return the grid color.
243 *
244 * The default color is gray.
245 */
246 QColor gridColor() const;
247
248 /**
249 * Set the background color
250 * @param bg the new background color
251 */
252 void setBackgroundColor( const QColor &bg );
253
254 /**
255 * Set the foreground color
256 * @param fg the new foreground color
257 */
258 void setForegroundColor( const QColor &fg );
259
260 /**
261 * Set the grid color
262 * @param gc the new grid color
263 */
264 void setGridColor( const QColor &gc );
265
266 /**
267 * @return whether the grid lines are shown
268 * Grid lines are not shown by default.
269 */
270 bool isGridShown() const;
271
272 /**
273 * @return whether the tooltip for the point objects is shown.
274 * Tooltips are enabled by default.
275 */
276 bool isObjectToolTipShown() const;
277
278 /**
279 * @return whether the antialiasing is active
280 * Antialiasing is not active by default.
281 */
282 bool antialiasing() const;
283
284 /**
285 * Toggle antialiased drawing.
286 * @param b if true, the plot graphics will be antialiased.
287 */
288 void setAntialiasing( bool b );
289
290 /**
291 * @return the number of pixels to the left of the plot area.
292 *
293 * Padding values are set to -1 by default; if unchanged, this
294 * function will try to guess a good value, based on whether
295 * ticklabels and/or axis labels need to be drawn.
296 */
297 int leftPadding() const;
298
299 /**
300 * @return the number of pixels to the right of the plot area.
301 * Padding values are set to -1 by default; if unchanged, this
302 * function will try to guess a good value, based on whether
303 * ticklabels and/or axis labels are to be drawn.
304 */
305 int rightPadding() const;
306
307 /**
308 * @return the number of pixels above the plot area.
309 * Padding values are set to -1 by default; if unchanged, this
310 * function will try to guess a good value, based on whether
311 * ticklabels and/or axis labels are to be drawn.
312 */
313 int topPadding() const;
314
315 /**
316 * @return the number of pixels below the plot area.
317 * Padding values are set to -1 by default; if unchanged, this
318 * function will try to guess a good value, based on whether
319 * ticklabels and/or axis labels are to be drawn.
320 */
321 int bottomPadding() const;
322
323 /**
324 * @short Set the number of pixels to the left of the plot area.
325 * Set this to -1 to revert to automatic determination of padding values.
326 */
327 void setLeftPadding( int padding );
328
329 /**
330 * @short Set the number of pixels to the right of the plot area.
331 * Set this to -1 to revert to automatic determination of padding values.
332 */
333 void setRightPadding( int padding );
334
335 /**
336 * @short Set the number of pixels above the plot area.
337 * Set this to -1 to revert to automatic determination of padding values.
338 */
339 void setTopPadding( int padding );
340
341 /**
342 * @short Set the number of pixels below the plot area.
343 * Set this to -1 to revert to automatic determination of padding values.
344 */
345 void setBottomPadding( int padding );
346
347 /**
348 * @short Revert all four padding values to -1, so that they will be
349 * automatically determined.
350 */
351 void setDefaultPaddings();
352
353 /**
354 * @short Map a coordinate @param p from the data rect to the physical
355 * pixel rect.
356 * Used mainly when drawing.
357 * @param p the point to be converted, in natural data units
358 * @return the coordinate in the pixel coordinate system
359 */
360 QPointF mapToWidget( const QPointF& p ) const;
361
362 /**
363 * Indicate that object labels should try to avoid the given
364 * rectangle in the plot. The rectangle is in pixel coordinates.
365 *
366 * @note You should not normally call this function directly.
367 * It is called by KPlotObject when points, bars and labels are drawn.
368 * @param r the rectangle defining the region in the plot that
369 * text labels should avoid (in pixel coordinates)
370 * @param value Allows you to determine how strongly the rectangle
371 * should be avoided. Larger values are avoided more strongly.
372 */
373 void maskRect( const QRectF &r, float value=1.0 );
374
375 /**
376 * Indicate that object labels should try to avoid the line
377 * joining the two given points (in pixel coordinates).
378 *
379 * @note You should not normally call this function directly.
380 * It is called by KPlotObject when lines are drawn in the plot.
381 * @param p1 the starting point for the line
382 * @param p2 the ending point for the line
383 * @param value Allows you to determine how strongly the line
384 * should be avoided. Larger values are avoided more strongly.
385 */
386 void maskAlongLine( const QPointF &p1, const QPointF &p2, float value=1.0 );
387
388 /**
389 * Place an object label optimally in the plot. This function will
390 * attempt to place the label as close as it can to the point to which
391 * the label belongs, while avoiding overlap with regions of the plot
392 * that have been masked.
393 *
394 * @note You should not normally call this function directly.
395 * It is called internally in KPlotObject::draw().
396 *
397 * @param painter Pointer to the painter on which to draw the label
398 * @param pp pointer to the KPlotPoint whose label is to be drawn.
399 */
400 void placeLabel( QPainter *painter, KPlotPoint *pp );
401
402 /**
403 * @return the axis of the specified @p type, or 0 if no axis has been set.
404 * @sa Axis
405 */
406 KPlotAxis* axis( Axis type );
407
408 /**
409 * @return the axis of the specified @p type, or 0 if no axis has been set.
410 * @sa Axis
411 */
412 const KPlotAxis* axis( Axis type ) const;
413
414
415public Q_SLOTS:
416 /**
417 * Toggle whether grid lines are drawn at major tickmarks.
418 * @param show if true, grid lines will be drawn.
419 * @sa isGridShown()
420 */
421 void setShowGrid( bool show );
422
423 /**
424 * Toggle the display of a tooltip for point objects.
425 * @param show whether show the tooltip.
426 * @sa isObjectToolTipShown()
427 */
428 void setObjectToolTipShown( bool show );
429
430protected:
431 /**
432 * Generic event handler.
433 */
434 virtual bool event( QEvent* );
435
436 /**
437 * The paint event handler, executed when update() or repaint() is called.
438 */
439 virtual void paintEvent( QPaintEvent* );
440
441 /**
442 * The resize event handler, called when the widget is resized.
443 */
444 virtual void resizeEvent( QResizeEvent* );
445
446 /**
447 * Draws the plot axes and axis labels.
448 * @internal Internal use only; one should simply call update()
449 * to draw the widget with axes and all objects.
450 * @param p pointer to the painter on which we are drawing
451 */
452 virtual void drawAxes( QPainter *p );
453
454 /**
455 * Synchronize the PixRect with the current widget size and
456 * padding settings.
457 */
458 void setPixRect();
459
460 /**
461 * @return a list of points in the plot which are within 4 pixels
462 * of the screen position given as an argument.
463 * @param p The screen position from which to check for plot points.
464 */
465 QList<KPlotPoint*> pointsUnderPoint( const QPoint& p ) const;
466
467private:
468 class Private;
469 Private * const d;
470
471 Q_DISABLE_COPY( KPlotWidget )
472};
473
474#endif
475