File indexing completed on 2025-01-26 03:34:13
0001 /* 0002 File : Plot.h 0003 Project : LabPlot 0004 Description : Base class for all plots like scatter plot, box plot, etc. 0005 -------------------------------------------------------------------- 0006 SPDX-FileCopyrightText: 2020-2023 Alexander Semke <alexander.semke@web.de> 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include "Plot.h" 0011 #include "PlotPrivate.h" 0012 #include "backend/lib/commandtemplates.h" 0013 #include "backend/lib/trace.h" 0014 #include "backend/worksheet/Background.h" 0015 0016 #include <QGraphicsSceneContextMenuEvent> 0017 #include <QMenu> 0018 #include <QPainter> 0019 0020 /** 0021 * \fn bool Plot::hasData() 0022 * \brief returns \c true if a valid data column is set, returns \c false otherwise. 0023 * Used in CartesianPlot to determine whether the curve needs to be taken into account 0024 * when caclulating the data ranges of the plot area. 0025 */ 0026 0027 Plot::Plot(const QString& name, PlotPrivate* dd, AspectType type) 0028 : WorksheetElement(name, dd, type) 0029 , d_ptr(dd) { 0030 } 0031 0032 Plot::~Plot() = default; 0033 0034 // TODO: make this function pure abstract and implement it for all plot types 0035 bool Plot::minMax(const CartesianCoordinateSystem::Dimension, const Range<int>&, Range<double>&, bool) const { 0036 return false; 0037 } 0038 0039 /*! 0040 * \brief Plot::activatePlot 0041 * Checks if the mousepos distance to the plot is less than @p maxDist 0042 * \p mouseScenePos 0043 * \p maxDist Maximum distance the point lies away from the plot 0044 * \return Returns true if the distance is smaller than maxDist. 0045 */ 0046 bool Plot::activatePlot(QPointF mouseScenePos, double maxDist) { 0047 Q_D(Plot); 0048 return d->activatePlot(mouseScenePos, maxDist); 0049 } 0050 0051 // general 0052 BASIC_SHARED_D_READER_IMPL(Plot, bool, legendVisible, legendVisible) 0053 0054 STD_SETTER_CMD_IMPL_S(Plot, SetLegendVisible, bool, legendVisible) 0055 void Plot::setLegendVisible(bool visible) { 0056 Q_D(Plot); 0057 if (visible != d->legendVisible) 0058 exec(new PlotSetLegendVisibleCmd(d, visible, ki18n("%1: legend visibility changed"))); 0059 } 0060 0061 // ############################################################################## 0062 // ####################### Private implementation ############################### 0063 // ############################################################################## 0064 PlotPrivate::PlotPrivate(Plot* owner) 0065 : WorksheetElementPrivate(owner) 0066 , q(owner) { 0067 } 0068 0069 bool PlotPrivate::activatePlot(QPointF mouseScenePos, double /*maxDist*/) { 0070 if (!isVisible()) 0071 return false; 0072 0073 return m_shape.contains(mouseScenePos); 0074 } 0075 0076 void PlotPrivate::contextMenuEvent(QGraphicsSceneContextMenuEvent* event) { 0077 if (q->activatePlot(event->pos())) { 0078 q->createContextMenu()->exec(event->screenPos()); 0079 return; 0080 } 0081 QGraphicsItem::contextMenuEvent(event); 0082 } 0083 0084 void PlotPrivate::drawFillingPollygon(const QPolygonF& polygon, QPainter* painter, const Background* background) const { 0085 PERFTRACE(name() + QLatin1String(Q_FUNC_INFO)); 0086 const QRectF& rect = polygon.boundingRect(); 0087 0088 if (background->type() == Background::Type::Color) { 0089 switch (background->colorStyle()) { 0090 case Background::ColorStyle::SingleColor: { 0091 painter->setBrush(QBrush(background->firstColor())); 0092 break; 0093 } 0094 case Background::ColorStyle::HorizontalLinearGradient: { 0095 QLinearGradient linearGrad(rect.topLeft(), rect.topRight()); 0096 linearGrad.setColorAt(0, background->firstColor()); 0097 linearGrad.setColorAt(1, background->secondColor()); 0098 painter->setBrush(QBrush(linearGrad)); 0099 break; 0100 } 0101 case Background::ColorStyle::VerticalLinearGradient: { 0102 QLinearGradient linearGrad(rect.topLeft(), rect.bottomLeft()); 0103 linearGrad.setColorAt(0, background->firstColor()); 0104 linearGrad.setColorAt(1, background->secondColor()); 0105 painter->setBrush(QBrush(linearGrad)); 0106 break; 0107 } 0108 case Background::ColorStyle::TopLeftDiagonalLinearGradient: { 0109 QLinearGradient linearGrad(rect.topLeft(), rect.bottomRight()); 0110 linearGrad.setColorAt(0, background->firstColor()); 0111 linearGrad.setColorAt(1, background->secondColor()); 0112 painter->setBrush(QBrush(linearGrad)); 0113 break; 0114 } 0115 case Background::ColorStyle::BottomLeftDiagonalLinearGradient: { 0116 QLinearGradient linearGrad(rect.bottomLeft(), rect.topRight()); 0117 linearGrad.setColorAt(0, background->firstColor()); 0118 linearGrad.setColorAt(1, background->secondColor()); 0119 painter->setBrush(QBrush(linearGrad)); 0120 break; 0121 } 0122 case Background::ColorStyle::RadialGradient: { 0123 QRadialGradient radialGrad(rect.center(), rect.width() / 2); 0124 radialGrad.setColorAt(0, background->firstColor()); 0125 radialGrad.setColorAt(1, background->secondColor()); 0126 painter->setBrush(QBrush(radialGrad)); 0127 break; 0128 } 0129 } 0130 } else if (background->type() == Background::Type::Image) { 0131 if (!background->fileName().trimmed().isEmpty()) { 0132 QPixmap pix(background->fileName()); 0133 switch (background->imageStyle()) { 0134 case Background::ImageStyle::ScaledCropped: 0135 pix = pix.scaled(rect.size().toSize(), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); 0136 painter->setBrush(QBrush(pix)); 0137 painter->setBrushOrigin(pix.size().width() / 2, pix.size().height() / 2); 0138 break; 0139 case Background::ImageStyle::Scaled: 0140 pix = pix.scaled(rect.size().toSize(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); 0141 painter->setBrush(QBrush(pix)); 0142 painter->setBrushOrigin(pix.size().width() / 2, pix.size().height() / 2); 0143 break; 0144 case Background::ImageStyle::ScaledAspectRatio: 0145 pix = pix.scaled(rect.size().toSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation); 0146 painter->setBrush(QBrush(pix)); 0147 painter->setBrushOrigin(pix.size().width() / 2, pix.size().height() / 2); 0148 break; 0149 case Background::ImageStyle::Centered: { 0150 QPixmap backpix(rect.size().toSize()); 0151 backpix.fill(); 0152 QPainter p(&backpix); 0153 p.drawPixmap(QPointF(0, 0), pix); 0154 p.end(); 0155 painter->setBrush(QBrush(backpix)); 0156 painter->setBrushOrigin(-pix.size().width() / 2, -pix.size().height() / 2); 0157 break; 0158 } 0159 case Background::ImageStyle::Tiled: 0160 painter->setBrush(QBrush(pix)); 0161 break; 0162 case Background::ImageStyle::CenterTiled: 0163 painter->setBrush(QBrush(pix)); 0164 painter->setBrushOrigin(pix.size().width() / 2, pix.size().height() / 2); 0165 } 0166 } 0167 } else if (background->type() == Background::Type::Pattern) 0168 painter->setBrush(QBrush(background->firstColor(), background->brushStyle())); 0169 0170 painter->drawPolygon(polygon); 0171 }