File indexing completed on 2024-04-28 15:29:30
0001 /* -*- C++ -*- 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2003 Jason Harris <kstars@30doradus.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #ifndef KPLOTWIDGET_H 0009 #define KPLOTWIDGET_H 0010 0011 #include <kplotting_export.h> 0012 0013 #include <QFrame> 0014 #include <QList> 0015 0016 class KPlotAxis; 0017 class KPlotObject; 0018 class KPlotPoint; 0019 0020 /** 0021 *@class KPlotWidget 0022 * 0023 *@short Generic data plotting widget. 0024 * 0025 *Widget for drawing plots. The basic idea behind KPlotWidget is that 0026 *you don't have to worry about any transformation from your data's 0027 *natural units to screen pixel coordinates; this is handled internally 0028 *by the widget. 0029 * 0030 *Data to be plotted are represented by one or more instances of 0031 *KPlotObject. KPlotObject contains a list of QPointFs to be plotted 0032 *(again, in the data's natural units), as well as information about how 0033 *the data are to be rendered in the plot (i.e., as separate points or 0034 *connected by lines? With what color and point style? etc). See 0035 *KPlotObject for more information. 0036 * 0037 *KPlotWidget automatically adds axis labels with tickmarks and tick 0038 *labels. These are encapsulated in the KPlotAxis class. All you have 0039 *to do is set the limits of the plotting area in data units, and 0040 *KPlotWidget will figure out the optimal positions and labels for the 0041 *tickmarks on the axes. 0042 * 0043 *Example of usage: 0044 * 0045 * @code 0046 KPlotWidget *kpw = new KPlotWidget( parent ); 0047 // setting our limits for the plot 0048 kpw->setLimits( 1.0, 5.0, 1.0, 25.0 ); 0049 0050 // creating a plot object whose points are connected by red lines ... 0051 KPlotObject *kpo = new KPlotObject( Qt::red, KPlotObject::Lines ); 0052 // ... adding some points to it ... 0053 for ( float x = 1.0; x <= 5.0; x += 0.1 ) 0054 kpo->addPoint( x, x*x ); 0055 0056 // ... and adding the object to the plot widget 0057 kpw->addPlotObject( kpo ); 0058 * @endcode 0059 * 0060 *@note KPlotWidget will take ownership of the objects added to it, so when 0061 *clearing the objects list (eg with removeAllPlotObjects()) any previous 0062 *reference to a KPlotObject already added to a KPlotWidget will be invalid. 0063 *You can disable this behavior by using setAutoDelete(false). 0064 * 0065 *@author Jason Harris 0066 */ 0067 class KPLOTTING_EXPORT KPlotWidget : public QFrame 0068 { 0069 Q_OBJECT 0070 Q_PROPERTY(int leftPadding READ leftPadding) 0071 Q_PROPERTY(int rightPadding READ rightPadding) 0072 Q_PROPERTY(int topPadding READ topPadding) 0073 Q_PROPERTY(int bottomPadding READ bottomPadding) 0074 Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor) 0075 Q_PROPERTY(QColor foregroundColor READ foregroundColor WRITE setForegroundColor) 0076 Q_PROPERTY(QColor gridColor READ gridColor WRITE setGridColor) 0077 Q_PROPERTY(bool grid READ isGridShown WRITE setShowGrid) 0078 Q_PROPERTY(bool objectToolTip READ isObjectToolTipShown WRITE setObjectToolTipShown) 0079 public: 0080 /** 0081 *@short Constructor. 0082 *@param parent the parent widget 0083 */ 0084 explicit KPlotWidget(QWidget *parent = nullptr); 0085 0086 /** 0087 *@short Destructor. 0088 */ 0089 ~KPlotWidget() override; 0090 0091 /** 0092 * The four types of plot axes. 0093 */ 0094 enum Axis { 0095 LeftAxis = 0, ///< the left axis 0096 BottomAxis, ///< the bottom axis 0097 RightAxis, ///< the right axis 0098 TopAxis, ///< the top axis 0099 }; 0100 0101 /** 0102 *@return suggested minimum size for the plot widget 0103 */ 0104 QSize minimumSizeHint() const override; 0105 0106 /** 0107 *@return suggested size for the plot widget 0108 */ 0109 QSize sizeHint() const override; 0110 0111 /** 0112 * Set new data limits for the plot. 0113 * @param x1 the minimum X value in data units 0114 * @param x2 the maximum X value in data units 0115 * @param y1 the minimum Y value in data units 0116 * @param y2 the maximum Y value in data units 0117 */ 0118 void setLimits(double x1, double x2, double y1, double y2); 0119 0120 /** 0121 * @short Reset the secondary data limits, which control the 0122 * values displayed along the top and right axes. 0123 * 0124 * All data points are *plotted* using the coordinates 0125 * defined by setLimits(), so this function is only useful for 0126 * showing alternate tickmark labels along the top and right 0127 * edges. For example, if you were plotting temperature on the 0128 * X-axis, you could use Centigrade units for the primary 0129 * (bottom) axis, using setLimits( 0.0, 100.0, 0.0, 1.0 ). If 0130 * you also wanted to show Fahrenheit units along the secondary 0131 * (top) axis, you would additionally use 0132 * setSecondaryLimits( 32.0, 212.0, 0.0, 1.0 ). The data 0133 * added to the plot would have x-coordinates in Centigrade degrees. 0134 * 0135 * @param x1 the minimum X value in secondary data units 0136 * @param x2 the maximum X value in secondary data units 0137 * @param y1 the minimum Y value in secondary data units 0138 * @param y2 the maximum Y value in secondary data units 0139 * @sa setLimits() 0140 */ 0141 void setSecondaryLimits(double x1, double x2, double y1, double y2); 0142 0143 /** 0144 * Unset the secondary limits, so the top and right axes 0145 * show the same tickmarks as the bottom and left axes (no tickmark 0146 * labels will be drawn for the top and right axes in this case) 0147 */ 0148 void clearSecondaryLimits(); 0149 0150 /** 0151 * @return the rectangle representing the boundaries of the current plot, 0152 * in natural data units. 0153 * @sa setLimits() 0154 */ 0155 QRectF dataRect() const; 0156 0157 /** 0158 * @return the rectangle representing the boundaries of the secondary 0159 * data limits, if they have been set. Otherwise, this function 0160 * behaves the same as dataRect(). 0161 * @sa setSecondaryLimits() 0162 */ 0163 QRectF secondaryDataRect() const; 0164 0165 /** 0166 * @return the rectangle representing the boundaries of the current plot, 0167 * in screen pixel units. 0168 */ 0169 QRect pixRect() const; 0170 0171 /** 0172 * Add an item to the list of KPlotObjects to be plotted. 0173 * The widget takes ownership of the plot object, unless auto-delete was disabled. 0174 * @param object the KPlotObject to be added 0175 */ 0176 void addPlotObject(KPlotObject *object); 0177 0178 /** 0179 * Add more than one KPlotObject at one time. 0180 * The widget takes ownership of the plot object, unless auto-delete was disabled. 0181 * @param objects the list of KPlotObjects to be added 0182 */ 0183 void addPlotObjects(const QList<KPlotObject *> &objects); 0184 0185 /** 0186 * @return the current list of plot objects 0187 */ 0188 QList<KPlotObject *> plotObjects() const; 0189 0190 /** 0191 * Enables auto-deletion of plot objects if autoDelete is true; otherwise auto-deletion is disabled. 0192 * Auto-deletion is enabled by default. 0193 * @since 5.12 0194 */ 0195 void setAutoDeletePlotObjects(bool autoDelete); 0196 0197 /** 0198 * Removes all plot objects that were added to the widget. 0199 * If auto-delete was not disabled, the plot objects are deleted. 0200 */ 0201 void removeAllPlotObjects(); 0202 0203 /** 0204 * Reset the mask used for non-overlapping labels so that all 0205 * regions of the plot area are considered empty. 0206 */ 0207 void resetPlotMask(); 0208 0209 /** 0210 * Clear the object list, reset the data limits, and remove axis labels 0211 * If auto-delete was not disabled, the plot objects are deleted. 0212 */ 0213 void resetPlot(); 0214 0215 /** 0216 * Replace an item in the KPlotObject list. 0217 * @param i the index of the item to be replaced 0218 * @param o pointer to the replacement KPlotObject 0219 * 0220 * @since 5.12, if auto-deletion is enabled, the previous plot object is deleted. 0221 * Call setAutoDeletePlotObjects(false) if you want to swap between available plot objects 0222 * and therefore you want to handle deletion externally. 0223 */ 0224 void replacePlotObject(int i, KPlotObject *o); 0225 0226 /** 0227 * @return the background color of the plot. 0228 * 0229 * The default color is black. 0230 */ 0231 QColor backgroundColor() const; 0232 0233 /** 0234 * @return the foreground color, used for axes, tickmarks and associated 0235 * labels. 0236 * 0237 * The default color is white. 0238 */ 0239 QColor foregroundColor() const; 0240 0241 /** 0242 * @return the grid color. 0243 * 0244 * The default color is gray. 0245 */ 0246 QColor gridColor() const; 0247 0248 /** 0249 * Set the background color 0250 * @param bg the new background color 0251 */ 0252 void setBackgroundColor(const QColor &bg); 0253 0254 /** 0255 * Set the foreground color 0256 * @param fg the new foreground color 0257 */ 0258 void setForegroundColor(const QColor &fg); 0259 0260 /** 0261 * Set the grid color 0262 * @param gc the new grid color 0263 */ 0264 void setGridColor(const QColor &gc); 0265 0266 /** 0267 * @return whether the grid lines are shown 0268 * Grid lines are not shown by default. 0269 */ 0270 bool isGridShown() const; 0271 0272 /** 0273 * @return whether the tooltip for the point objects is shown. 0274 * Tooltips are enabled by default. 0275 */ 0276 bool isObjectToolTipShown() const; 0277 0278 /** 0279 * @return whether the antialiasing is active 0280 * Antialiasing is not active by default. 0281 */ 0282 bool antialiasing() const; 0283 0284 /** 0285 * Toggle antialiased drawing. 0286 * @param b if true, the plot graphics will be antialiased. 0287 */ 0288 void setAntialiasing(bool b); 0289 0290 /** 0291 * @return the number of pixels to the left of the plot area. 0292 * 0293 * Padding values are set to -1 by default; if unchanged, this 0294 * function will try to guess a good value, based on whether 0295 * ticklabels and/or axis labels need to be drawn. 0296 */ 0297 int leftPadding() const; 0298 0299 /** 0300 * @return the number of pixels to the right of the plot area. 0301 * Padding values are set to -1 by default; if unchanged, this 0302 * function will try to guess a good value, based on whether 0303 * ticklabels and/or axis labels are to be drawn. 0304 */ 0305 int rightPadding() const; 0306 0307 /** 0308 * @return the number of pixels above the plot area. 0309 * Padding values are set to -1 by default; if unchanged, this 0310 * function will try to guess a good value, based on whether 0311 * ticklabels and/or axis labels are to be drawn. 0312 */ 0313 int topPadding() const; 0314 0315 /** 0316 * @return the number of pixels below the plot area. 0317 * Padding values are set to -1 by default; if unchanged, this 0318 * function will try to guess a good value, based on whether 0319 * ticklabels and/or axis labels are to be drawn. 0320 */ 0321 int bottomPadding() const; 0322 0323 /** 0324 * @short Set the number of pixels to the left of the plot area. 0325 * Set this to -1 to revert to automatic determination of padding values. 0326 */ 0327 void setLeftPadding(int padding); 0328 0329 /** 0330 * @short Set the number of pixels to the right of the plot area. 0331 * Set this to -1 to revert to automatic determination of padding values. 0332 */ 0333 void setRightPadding(int padding); 0334 0335 /** 0336 * @short Set the number of pixels above the plot area. 0337 * Set this to -1 to revert to automatic determination of padding values. 0338 */ 0339 void setTopPadding(int padding); 0340 0341 /** 0342 * @short Set the number of pixels below the plot area. 0343 * Set this to -1 to revert to automatic determination of padding values. 0344 */ 0345 void setBottomPadding(int padding); 0346 0347 /** 0348 * @short Revert all four padding values to -1, so that they will be 0349 * automatically determined. 0350 */ 0351 void setDefaultPaddings(); 0352 0353 /** 0354 * @short Map a coordinate @param p from the data rect to the physical 0355 * pixel rect. 0356 * Used mainly when drawing. 0357 * @param p the point to be converted, in natural data units 0358 * @return the coordinate in the pixel coordinate system 0359 */ 0360 QPointF mapToWidget(const QPointF &p) const; 0361 0362 /** 0363 * Indicate that object labels should try to avoid the given 0364 * rectangle in the plot. The rectangle is in pixel coordinates. 0365 * 0366 * @note You should not normally call this function directly. 0367 * It is called by KPlotObject when points, bars and labels are drawn. 0368 * @param r the rectangle defining the region in the plot that 0369 * text labels should avoid (in pixel coordinates) 0370 * @param value Allows you to determine how strongly the rectangle 0371 * should be avoided. Larger values are avoided more strongly. 0372 */ 0373 void maskRect(const QRectF &r, float value = 1.0f); 0374 0375 /** 0376 * Indicate that object labels should try to avoid the line 0377 * joining the two given points (in pixel coordinates). 0378 * 0379 * @note You should not normally call this function directly. 0380 * It is called by KPlotObject when lines are drawn in the plot. 0381 * @param p1 the starting point for the line 0382 * @param p2 the ending point for the line 0383 * @param value Allows you to determine how strongly the line 0384 * should be avoided. Larger values are avoided more strongly. 0385 */ 0386 void maskAlongLine(const QPointF &p1, const QPointF &p2, float value = 1.0f); 0387 0388 /** 0389 * Place an object label optimally in the plot. This function will 0390 * attempt to place the label as close as it can to the point to which 0391 * the label belongs, while avoiding overlap with regions of the plot 0392 * that have been masked. 0393 * 0394 * @note You should not normally call this function directly. 0395 * It is called internally in KPlotObject::draw(). 0396 * 0397 * @param painter Pointer to the painter on which to draw the label 0398 * @param pp pointer to the KPlotPoint whose label is to be drawn. 0399 */ 0400 void placeLabel(QPainter *painter, KPlotPoint *pp); 0401 0402 /** 0403 * @return the axis of the specified @p type, or 0 if no axis has been set. 0404 * @sa Axis 0405 */ 0406 KPlotAxis *axis(Axis type); 0407 0408 /** 0409 * @return the axis of the specified @p type, or 0 if no axis has been set. 0410 * @sa Axis 0411 */ 0412 const KPlotAxis *axis(Axis type) const; 0413 0414 public Q_SLOTS: 0415 /** 0416 * Toggle whether grid lines are drawn at major tickmarks. 0417 * @param show if true, grid lines will be drawn. 0418 * @sa isGridShown() 0419 */ 0420 void setShowGrid(bool show); 0421 0422 /** 0423 * Toggle the display of a tooltip for point objects. 0424 * @param show whether show the tooltip. 0425 * @sa isObjectToolTipShown() 0426 */ 0427 void setObjectToolTipShown(bool show); 0428 0429 protected: 0430 /** 0431 * Generic event handler. 0432 */ 0433 bool event(QEvent *) override; 0434 0435 /** 0436 * The paint event handler, executed when update() or repaint() is called. 0437 */ 0438 void paintEvent(QPaintEvent *) override; 0439 0440 /** 0441 * The resize event handler, called when the widget is resized. 0442 */ 0443 void resizeEvent(QResizeEvent *) override; 0444 0445 /** 0446 * Draws the plot axes and axis labels. 0447 * @internal Internal use only; one should simply call update() 0448 * to draw the widget with axes and all objects. 0449 * @param p pointer to the painter on which we are drawing 0450 */ 0451 virtual void drawAxes(QPainter *p); 0452 0453 /** 0454 * Synchronize the PixRect with the current widget size and 0455 * padding settings. 0456 */ 0457 void setPixRect(); 0458 0459 /** 0460 * @return a list of points in the plot which are within 4 pixels 0461 * of the screen position given as an argument. 0462 * @param p The screen position from which to check for plot points. 0463 */ 0464 QList<KPlotPoint *> pointsUnderPoint(const QPoint &p) const; 0465 0466 private: 0467 class Private; 0468 Private *const d; 0469 0470 Q_DISABLE_COPY(KPlotWidget) 0471 }; 0472 0473 #endif