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