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 | |
29 | class KPlotAxis; |
30 | class KPlotObject; |
31 | class 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 |
59 | KPlotWidget *kpw = new KPlotWidget( parent ); |
60 | // setting our limits for the plot |
61 | kpw->setLimits( 1.0, 5.0, 1.0, 25.0 ); |
62 | |
63 | // creating a plot object whose points are connected by red lines ... |
64 | KPlotObject *kpo = new KPlotObject( Qt::red, KPlotObject::Lines ); |
65 | // ... adding some points to it ... |
66 | for ( 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 |
70 | kpw->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 | */ |
80 | class 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) |
91 | public: |
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 | |
415 | public 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 | |
430 | protected: |
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 | |
467 | private: |
468 | class Private; |
469 | Private * const d; |
470 | |
471 | Q_DISABLE_COPY( KPlotWidget ) |
472 | }; |
473 | |
474 | #endif |
475 | |