diff --git a/src/backend/worksheet/plots/cartesian/Histogram.cpp b/src/backend/worksheet/plots/cartesian/Histogram.cpp index 5f56ecd78..ffb6aab7d 100644 --- a/src/backend/worksheet/plots/cartesian/Histogram.cpp +++ b/src/backend/worksheet/plots/cartesian/Histogram.cpp @@ -1,1795 +1,1795 @@ /*************************************************************************** File : Histogram.cpp Project : LabPlot Description : Histogram -------------------------------------------------------------------- Copyright : (C) 2016 Anu Mittal (anu22mittal@gmail.com) Copyright : (C) 2016-2017 by Alexander Semke (alexander.semke@web.de) Copyright : (C) 2017-2018 by Garvit Khatri (garvitdelhi@gmail.com) ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ /*! \class Histogram \brief A 2D-curve, provides an interface for editing many properties of the curve. \ingroup worksheet */ #include "Histogram.h" #include "HistogramPrivate.h" #include "backend/core/column/Column.h" #include "backend/worksheet/plots/AbstractCoordinateSystem.h" #include "backend/worksheet/plots/cartesian/CartesianCoordinateSystem.h" #include "backend/worksheet/plots/cartesian/CartesianPlot.h" #include "backend/lib/commandtemplates.h" #include "backend/worksheet/Worksheet.h" #include "backend/lib/XmlStreamReader.h" #include "tools/ImageTools.h" #include "backend/lib/trace.h" #include #include #include #include #include #include extern "C" { #include #include #include } Histogram::Histogram(const QString &name) : WorksheetElement(name), d_ptr(new HistogramPrivate(this)) { init(); } Histogram::Histogram(const QString &name, HistogramPrivate *dd) : WorksheetElement(name), d_ptr(dd) { init(); } void Histogram::init() { Q_D(Histogram); KConfig config; KConfigGroup group = config.group("Histogram"); d->xColumn = NULL; d->histogramType = (Histogram::HistogramType) group.readEntry("histogramType", (int)Histogram::Ordinary); d->histogramOrientation = (Histogram::HistogramOrientation) group.readEntry("histogramOrientation", (int)Histogram::Vertical); - d->binsOption = (Histogram::BinsOption) group.readEntry("binOption", (int)Histogram::Number); + d->binningMethod = (Histogram::BinningMethod) group.readEntry("binOption", (int)Histogram::ByNumber); d->lineSkipGaps = group.readEntry("SkipLineGaps", false); d->lineInterpolationPointsCount = group.readEntry("LineInterpolationPointsCount", 1); d->linePen.setStyle( (Qt::PenStyle) group.readEntry("LineStyle", (int)Qt::SolidLine) ); d->linePen.setColor( group.readEntry("LineColor", QColor(Qt::black)) ); d->linePen.setWidthF( group.readEntry("LineWidth", Worksheet::convertToSceneUnits(1.0, Worksheet::Point)) ); d->lineOpacity = group.readEntry("LineOpacity", 1.0); d->valuesType = (Histogram::ValuesType) group.readEntry("ValuesType", (int)Histogram::NoValues); d->valuesColumn = NULL; d->valuesPosition = (Histogram::ValuesPosition) group.readEntry("ValuesPosition", (int)Histogram::ValuesAbove); d->valuesDistance = group.readEntry("ValuesDistance", Worksheet::convertToSceneUnits(5, Worksheet::Point)); d->valuesRotationAngle = group.readEntry("ValuesRotation", 0.0); d->valuesOpacity = group.readEntry("ValuesOpacity", 1.0); d->valuesPrefix = group.readEntry("ValuesPrefix", ""); d->valuesSuffix = group.readEntry("ValuesSuffix", ""); d->valuesFont = group.readEntry("ValuesFont", QFont()); d->valuesFont.setPixelSize( Worksheet::convertToSceneUnits( 8, Worksheet::Point ) ); d->valuesColor = group.readEntry("ValuesColor", QColor(Qt::black)); d->fillingPosition = (Histogram::FillingPosition) group.readEntry("FillingPosition", (int)Histogram::NoFilling); d->fillingType = (PlotArea::BackgroundType) group.readEntry("FillingType", (int)PlotArea::Color); d->fillingColorStyle = (PlotArea::BackgroundColorStyle) group.readEntry("FillingColorStyle", (int) PlotArea::SingleColor); d->fillingImageStyle = (PlotArea::BackgroundImageStyle) group.readEntry("FillingImageStyle", (int) PlotArea::Scaled); d->fillingBrushStyle = (Qt::BrushStyle) group.readEntry("FillingBrushStyle", (int) Qt::SolidPattern); d->fillingFileName = group.readEntry("FillingFileName", QString()); d->fillingFirstColor = group.readEntry("FillingFirstColor", QColor(Qt::white)); d->fillingSecondColor = group.readEntry("FillingSecondColor", QColor(Qt::black)); d->fillingOpacity = group.readEntry("FillingOpacity", 1.0); this->initActions(); } void Histogram::initActions() { visibilityAction = new QAction(i18n("Visible"), this); visibilityAction->setCheckable(true); connect(visibilityAction, &QAction::triggered, this, &Histogram::visibilityChangedSlot); } QMenu* Histogram::createContextMenu() { QMenu *menu = WorksheetElement::createContextMenu(); QAction* firstAction = menu->actions().at(1); //skip the first action because of the "title-action" visibilityAction->setChecked(isVisible()); menu->insertAction(firstAction, visibilityAction); return menu; } /*! Returns an icon to be used in the project explorer. */ QIcon Histogram::icon() const { return QIcon::fromTheme("labplot-xy-curve"); } QGraphicsItem* Histogram::graphicsItem() const { return d_ptr; } STD_SWAP_METHOD_SETTER_CMD_IMPL(Histogram, SetVisible, bool, swapVisible) void Histogram::setVisible(bool on) { Q_D(Histogram); exec(new HistogramSetVisibleCmd(d, on, on ? ki18n("%1: set visible") : ki18n("%1: set invisible"))); } bool Histogram::isVisible() const { Q_D(const Histogram); return d->isVisible(); } void Histogram::setPrinting(bool on) { Q_D(Histogram); d->m_printing = on; } BASIC_SHARED_D_READER_IMPL(Histogram, Histogram::HistogramType, histogramType, histogramType) BASIC_SHARED_D_READER_IMPL(Histogram, Histogram::HistogramOrientation, histogramOrientation, histogramOrientation) -void Histogram::setbinsOption(Histogram::BinsOption binsOption) { - d_ptr->histogramData.binsOption = binsOption; +void Histogram::setBinningMethod(Histogram::BinningMethod binningMethod) { + d_ptr->histogramData.binningMethod = binningMethod; emit HistogramDataChanged(); } void Histogram::setBinValue(int binValue) { - d_ptr->histogramData.binValue = binValue; + d_ptr->histogramData.binCount = binValue; emit HistogramDataChanged(); } //############################################################################## //########################## getter methods ################################## //############################################################################## BASIC_SHARED_D_READER_IMPL(Histogram, const AbstractColumn*, xColumn, xColumn) QString& Histogram::xColumnPath() const { return d_ptr->xColumnPath; } CLASS_SHARED_D_READER_IMPL(Histogram, QPen, linePen, linePen) BASIC_SHARED_D_READER_IMPL(Histogram, Histogram::HistogramData, histogramData, histogramData) //values BASIC_SHARED_D_READER_IMPL(Histogram, Histogram::ValuesType, valuesType, valuesType) BASIC_SHARED_D_READER_IMPL(Histogram, const AbstractColumn *, valuesColumn, valuesColumn) QString& Histogram::valuesColumnPath() const { return d_ptr->valuesColumnPath; } BASIC_SHARED_D_READER_IMPL(Histogram, Histogram::ValuesPosition, valuesPosition, valuesPosition) BASIC_SHARED_D_READER_IMPL(Histogram, qreal, valuesDistance, valuesDistance) BASIC_SHARED_D_READER_IMPL(Histogram, qreal, valuesRotationAngle, valuesRotationAngle) BASIC_SHARED_D_READER_IMPL(Histogram, qreal, valuesOpacity, valuesOpacity) CLASS_SHARED_D_READER_IMPL(Histogram, QString, valuesPrefix, valuesPrefix) CLASS_SHARED_D_READER_IMPL(Histogram, QString, valuesSuffix, valuesSuffix) CLASS_SHARED_D_READER_IMPL(Histogram, QColor, valuesColor, valuesColor) CLASS_SHARED_D_READER_IMPL(Histogram, QFont, valuesFont, valuesFont) //filling BASIC_SHARED_D_READER_IMPL(Histogram, Histogram::FillingPosition, fillingPosition, fillingPosition) BASIC_SHARED_D_READER_IMPL(Histogram, PlotArea::BackgroundType, fillingType, fillingType) BASIC_SHARED_D_READER_IMPL(Histogram, PlotArea::BackgroundColorStyle, fillingColorStyle, fillingColorStyle) BASIC_SHARED_D_READER_IMPL(Histogram, PlotArea::BackgroundImageStyle, fillingImageStyle, fillingImageStyle) CLASS_SHARED_D_READER_IMPL(Histogram, Qt::BrushStyle, fillingBrushStyle, fillingBrushStyle) CLASS_SHARED_D_READER_IMPL(Histogram, QColor, fillingFirstColor, fillingFirstColor) CLASS_SHARED_D_READER_IMPL(Histogram, QColor, fillingSecondColor, fillingSecondColor) CLASS_SHARED_D_READER_IMPL(Histogram, QString, fillingFileName, fillingFileName) BASIC_SHARED_D_READER_IMPL(Histogram, qreal, fillingOpacity, fillingOpacity) double Histogram::getYMaximum() const { return d_ptr->getYMaximum(); } double Histogram::getYMinimum() const { return d_ptr->getYMinimum(); } double Histogram::getXMaximum() const { return d_ptr->getXMaximum(); } double Histogram::getXMinimum() const { return d_ptr->getXMinimum(); } bool Histogram::isSourceDataChangedSinceLastPlot() const { Q_D(const Histogram); return d->sourceDataChangedSinceLastPlot; } //############################################################################## //################# setter methods and undo commands ########################## //############################################################################## STD_SETTER_CMD_IMPL_F_S(Histogram, SetHistogramData, Histogram::HistogramData, histogramData, recalculate); void Histogram::setHistogramData(const Histogram::HistogramData& histogramData) { Q_D(Histogram); exec(new HistogramSetHistogramDataCmd(d, histogramData, ki18n("%1: set equation"))); } STD_SETTER_CMD_IMPL_F_S(Histogram, SetHistogramType, Histogram::HistogramType, histogramType, retransform) void Histogram::setHistogramType(Histogram::HistogramType histogramType) { Q_D(Histogram); exec(new HistogramSetHistogramTypeCmd(d, histogramType, ki18n("%1: assign histogram type"))); emit HistogramDataChanged(); DEBUG(histogramType); } STD_SETTER_CMD_IMPL_F_S(Histogram, SetHistogramOrientation, Histogram::HistogramOrientation, histogramOrientation, retransform) void Histogram::setHistogramOrientation(Histogram::HistogramOrientation histogramOrientation) { Q_D(Histogram); exec(new HistogramSetHistogramOrientationCmd(d, histogramOrientation, ki18n("%1: assign histogram orientation"))); emit HistogramDataChanged(); DEBUG(histogramOrientation); } STD_SETTER_CMD_IMPL_F_S(Histogram, SetXColumn, const AbstractColumn*, xColumn, retransform) void Histogram::setXColumn(const AbstractColumn* column) { Q_D(Histogram); if (column != d->xColumn) { exec(new HistogramSetXColumnCmd(d, column, ki18n("%1: assign x values"))); emit sourceDataChangedSinceLastPlot(); //emit HistogramDataChanged() in order to notify the plot about the changes emit HistogramDataChanged(); if (column) { connect(column, &AbstractColumn::dataChanged, this, &Histogram::xHistogramDataChanged); connect(column, &AbstractColumn::dataChanged, this, &Histogram::handleSourceDataChanged); //update the curve itself on changes connect(column, &AbstractColumn::dataChanged, this, &Histogram::retransform); connect(column->parentAspect(), &AbstractAspect::aspectAboutToBeRemoved, this, &Histogram::xColumnAboutToBeRemoved); //TODO: add disconnect in the undo-function } } } STD_SETTER_CMD_IMPL_F_S(Histogram, SetLinePen, QPen, linePen, recalcShapeAndBoundingRect) void Histogram::setLinePen(const QPen &pen) { Q_D(Histogram); if (pen != d->linePen) exec(new HistogramSetLinePenCmd(d, pen, ki18n("%1: set line style"))); } //Values-Tab STD_SETTER_CMD_IMPL_F_S(Histogram, SetValuesType, Histogram::ValuesType, valuesType, updateValues) void Histogram::setValuesType(Histogram::ValuesType type) { Q_D(Histogram); if (type != d->valuesType) exec(new HistogramSetValuesTypeCmd(d, type, ki18n("%1: set values type"))); } STD_SETTER_CMD_IMPL_F_S(Histogram, SetValuesColumn, const AbstractColumn*, valuesColumn, updateValues) void Histogram::setValuesColumn(const AbstractColumn* column) { Q_D(Histogram); if (column != d->valuesColumn) { exec(new HistogramSetValuesColumnCmd(d, column, ki18n("%1: set values column"))); if (column) { connect(column, &AbstractColumn::dataChanged, this, &Histogram::updateValues); connect(column->parentAspect(), &AbstractAspect::aspectAboutToBeRemoved, this, &Histogram::valuesColumnAboutToBeRemoved); } } } STD_SETTER_CMD_IMPL_F_S(Histogram, SetValuesPosition, Histogram::ValuesPosition, valuesPosition, updateValues) void Histogram::setValuesPosition(ValuesPosition position) { Q_D(Histogram); if (position != d->valuesPosition) exec(new HistogramSetValuesPositionCmd(d, position, ki18n("%1: set values position"))); } STD_SETTER_CMD_IMPL_F_S(Histogram, SetValuesDistance, qreal, valuesDistance, updateValues) void Histogram::setValuesDistance(qreal distance) { Q_D(Histogram); if (distance != d->valuesDistance) exec(new HistogramSetValuesDistanceCmd(d, distance, ki18n("%1: set values distance"))); } STD_SETTER_CMD_IMPL_F_S(Histogram, SetValuesRotationAngle, qreal, valuesRotationAngle, updateValues) void Histogram::setValuesRotationAngle(qreal angle) { Q_D(Histogram); if (!qFuzzyCompare(1 + angle, 1 + d->valuesRotationAngle)) exec(new HistogramSetValuesRotationAngleCmd(d, angle, ki18n("%1: rotate values"))); } STD_SETTER_CMD_IMPL_F_S(Histogram, SetValuesOpacity, qreal, valuesOpacity, updatePixmap) void Histogram::setValuesOpacity(qreal opacity) { Q_D(Histogram); if (opacity != d->valuesOpacity) exec(new HistogramSetValuesOpacityCmd(d, opacity, ki18n("%1: set values opacity"))); } //TODO: Format, Precision STD_SETTER_CMD_IMPL_F_S(Histogram, SetValuesPrefix, QString, valuesPrefix, updateValues) void Histogram::setValuesPrefix(const QString& prefix) { Q_D(Histogram); if (prefix!= d->valuesPrefix) exec(new HistogramSetValuesPrefixCmd(d, prefix, ki18n("%1: set values prefix"))); } STD_SETTER_CMD_IMPL_F_S(Histogram, SetValuesSuffix, QString, valuesSuffix, updateValues) void Histogram::setValuesSuffix(const QString& suffix) { Q_D(Histogram); if (suffix!= d->valuesSuffix) exec(new HistogramSetValuesSuffixCmd(d, suffix, ki18n("%1: set values suffix"))); } STD_SETTER_CMD_IMPL_F_S(Histogram, SetValuesFont, QFont, valuesFont, updateValues) void Histogram::setValuesFont(const QFont& font) { Q_D(Histogram); if (font!= d->valuesFont) exec(new HistogramSetValuesFontCmd(d, font, ki18n("%1: set values font"))); } STD_SETTER_CMD_IMPL_F_S(Histogram, SetValuesColor, QColor, valuesColor, updatePixmap) void Histogram::setValuesColor(const QColor& color) { Q_D(Histogram); if (color != d->valuesColor) exec(new HistogramSetValuesColorCmd(d, color, ki18n("%1: set values color"))); } //Filling STD_SETTER_CMD_IMPL_F_S(Histogram, SetFillingPosition, Histogram::FillingPosition, fillingPosition, updateFilling) void Histogram::setFillingPosition(FillingPosition position) { Q_D(Histogram); if (position != d->fillingPosition) exec(new HistogramSetFillingPositionCmd(d, position, ki18n("%1: filling position changed"))); } STD_SETTER_CMD_IMPL_F_S(Histogram, SetFillingType, PlotArea::BackgroundType, fillingType, updatePixmap) void Histogram::setFillingType(PlotArea::BackgroundType type) { Q_D(Histogram); if (type != d->fillingType) exec(new HistogramSetFillingTypeCmd(d, type, ki18n("%1: filling type changed"))); } STD_SETTER_CMD_IMPL_F_S(Histogram, SetFillingColorStyle, PlotArea::BackgroundColorStyle, fillingColorStyle, updatePixmap) void Histogram::setFillingColorStyle(PlotArea::BackgroundColorStyle style) { Q_D(Histogram); if (style != d->fillingColorStyle) exec(new HistogramSetFillingColorStyleCmd(d, style, ki18n("%1: filling color style changed"))); } STD_SETTER_CMD_IMPL_F_S(Histogram, SetFillingImageStyle, PlotArea::BackgroundImageStyle, fillingImageStyle, updatePixmap) void Histogram::setFillingImageStyle(PlotArea::BackgroundImageStyle style) { Q_D(Histogram); if (style != d->fillingImageStyle) exec(new HistogramSetFillingImageStyleCmd(d, style, ki18n("%1: filling image style changed"))); } STD_SETTER_CMD_IMPL_F_S(Histogram, SetFillingBrushStyle, Qt::BrushStyle, fillingBrushStyle, updatePixmap) void Histogram::setFillingBrushStyle(Qt::BrushStyle style) { Q_D(Histogram); if (style != d->fillingBrushStyle) exec(new HistogramSetFillingBrushStyleCmd(d, style, ki18n("%1: filling brush style changed"))); } STD_SETTER_CMD_IMPL_F_S(Histogram, SetFillingFirstColor, QColor, fillingFirstColor, updatePixmap) void Histogram::setFillingFirstColor(const QColor& color) { Q_D(Histogram); if (color!= d->fillingFirstColor) exec(new HistogramSetFillingFirstColorCmd(d, color, ki18n("%1: set filling first color"))); } STD_SETTER_CMD_IMPL_F_S(Histogram, SetFillingSecondColor, QColor, fillingSecondColor, updatePixmap) void Histogram::setFillingSecondColor(const QColor& color) { Q_D(Histogram); if (color!= d->fillingSecondColor) exec(new HistogramSetFillingSecondColorCmd(d, color, ki18n("%1: set filling second color"))); } STD_SETTER_CMD_IMPL_F_S(Histogram, SetFillingFileName, QString, fillingFileName, updatePixmap) void Histogram::setFillingFileName(const QString& fileName) { Q_D(Histogram); if (fileName!= d->fillingFileName) exec(new HistogramSetFillingFileNameCmd(d, fileName, ki18n("%1: set filling image"))); } STD_SETTER_CMD_IMPL_F_S(Histogram, SetFillingOpacity, qreal, fillingOpacity, updatePixmap) void Histogram::setFillingOpacity(qreal opacity) { Q_D(Histogram); if (opacity != d->fillingOpacity) exec(new HistogramSetFillingOpacityCmd(d, opacity, ki18n("%1: set filling opacity"))); } //############################################################################## //################################# SLOTS #################################### //############################################################################## void Histogram::retransform() { d_ptr->retransform(); } void Histogram::handleSourceDataChanged() { Q_D(Histogram); d->sourceDataChangedSinceLastPlot = true; emit sourceDataChangedSinceLastPlot(); } //TODO void Histogram::handleResize(double horizontalRatio, double verticalRatio, bool pageResize) { Q_UNUSED(pageResize); Q_UNUSED(verticalRatio); Q_D(const Histogram); //setValuesDistance(d->distance*); QFont font=d->valuesFont; font.setPointSizeF(font.pointSizeF()*horizontalRatio); setValuesFont(font); retransform(); } void Histogram::updateValues() { d_ptr->updateValues(); } void Histogram::xColumnAboutToBeRemoved(const AbstractAspect* aspect) { Q_D(Histogram); if (aspect == d->xColumn) { d->xColumn = 0; d->retransform(); } } void Histogram::valuesColumnAboutToBeRemoved(const AbstractAspect* aspect) { Q_D(Histogram); if (aspect == d->valuesColumn) { d->valuesColumn = 0; d->updateValues(); } } //############################################################################## //###### SLOTs for changes triggered via QActions in the context menu ######## //############################################################################## void Histogram::visibilityChangedSlot() { Q_D(const Histogram); this->setVisible(!d->isVisible()); } //############################################################################## //######################### Private implementation ############################# //############################################################################## HistogramPrivate::HistogramPrivate(Histogram *owner) : m_printing(false), m_hovered(false), m_suppressRecalc(false), m_suppressRetransform(false), m_hoverEffectImageIsDirty(false), m_selectionEffectImageIsDirty(false), q(owner) { setFlag(QGraphicsItem::ItemIsSelectable, true); setAcceptHoverEvents(true); } QString HistogramPrivate::name() const { return q->name(); } QRectF HistogramPrivate::boundingRect() const { return boundingRectangle; } double HistogramPrivate::getMaximumOccuranceofHistogram() { if (m_histogram) { double yMaxRange = -INFINITY; switch(histogramType) { case Histogram::Ordinary: { size_t maxYAddes = gsl_histogram_max_bin(m_histogram); yMaxRange = gsl_histogram_get(m_histogram, maxYAddes); break; } case Histogram::Cumulative: { size_t maxYAddes = gsl_histogram_max_bin(m_histogram); yMaxRange = gsl_histogram_get(m_histogram, maxYAddes); double point =0.0; for(size_t i=0; i < m_bins; ++i) { point+= gsl_histogram_get(m_histogram,i); if (point > yMaxRange) { yMaxRange = point; } } //yMaxRange = xColumn->rowCount(); break; } case Histogram::AvgShift: { //TODO } } return yMaxRange; } return -INFINITY; } double HistogramPrivate::getXMinimum() { switch(histogramOrientation) { case Histogram::Vertical: { return xColumn->minimum(); } case Histogram::Horizontal: { return 0; } } return INFINITY; } double HistogramPrivate::getXMaximum() { switch(histogramOrientation) { case Histogram::Vertical: { return xColumn->maximum(); } case Histogram::Horizontal: { return getMaximumOccuranceofHistogram(); } } return -INFINITY; } double HistogramPrivate::getYMinimum() { switch(histogramOrientation) { case Histogram::Vertical: { return 0; } case Histogram::Horizontal: { return xColumn->minimum(); } } return INFINITY; } double HistogramPrivate::getYMaximum() { switch(histogramOrientation) { case Histogram::Vertical: { return getMaximumOccuranceofHistogram(); } case Histogram::Horizontal: { return xColumn->maximum(); } } return INFINITY; } /*! Returns the shape of the Histogram as a QPainterPath in local coordinates */ QPainterPath HistogramPrivate::shape() const { return curveShape; } void HistogramPrivate::contextMenuEvent(QGraphicsSceneContextMenuEvent* event) { q->createContextMenu()->exec(event->screenPos()); } bool HistogramPrivate::swapVisible(bool on) { bool oldValue = isVisible(); setVisible(on); emit q->visibilityChanged(on); return oldValue; } /*! recalculates the position of the points to be drawn. Called when the data was changed. Triggers the update of lines, drop lines, symbols etc. */ void HistogramPrivate::retransform() { if (m_suppressRetransform) return; //qDebug()<<"HistogramPrivate::retransform() " << q->name(); symbolPointsLogical.clear(); symbolPointsScene.clear(); connectedPointsLogical.clear(); if (NULL == xColumn) { linePath = QPainterPath(); valuesPath = QPainterPath(); // dropLinePath = QPainterPath(); recalcShapeAndBoundingRect(); return; } int startRow = 0; int endRow = xColumn->rowCount() - 1; QPointF tempPoint; AbstractColumn::ColumnMode xColMode = xColumn->columnMode(); //take over only valid and non masked points. for (int row = startRow; row <= endRow; row++ ) { if (xColumn->isValid(row) && !xColumn->isMasked(row)) { switch(xColMode) { case AbstractColumn::Numeric: tempPoint.setX(xColumn->valueAt(row)); break; case AbstractColumn::Integer: //TODO case AbstractColumn::Text: //TODO case AbstractColumn::DateTime: case AbstractColumn::Month: case AbstractColumn::Day: //TODO break; } symbolPointsLogical.append(tempPoint); connectedPointsLogical.push_back(true); } else { if (connectedPointsLogical.size()) connectedPointsLogical[connectedPointsLogical.size()-1] = false; } } //calculate the scene coordinates const AbstractPlot* plot = dynamic_cast(q->parentAspect()); if (!plot) return; const CartesianCoordinateSystem* cSystem = dynamic_cast(plot->coordinateSystem()); Q_ASSERT(cSystem); visiblePoints = std::vector(symbolPointsLogical.count(), false); cSystem->mapLogicalToScene(symbolPointsLogical, symbolPointsScene, visiblePoints); m_suppressRecalc = true; updateLines(); updateValues(); m_suppressRecalc = false; } void HistogramPrivate::verticalOrdinaryHistogram() { QPointF tempPoint,tempPoint1; double xAxisMin = xColumn->minimum(); double xAxisMax = xColumn->maximum(); double width = (xAxisMax-xAxisMin)/m_bins; for(size_t i=0; i < m_bins; ++i) { tempPoint.setX(xAxisMin); tempPoint.setY(0.0); tempPoint1.setX(xAxisMin); tempPoint1.setY(gsl_histogram_get(m_histogram,i)); lines.append(QLineF(tempPoint, tempPoint1)); tempPoint.setX(xAxisMin); tempPoint.setY(gsl_histogram_get(m_histogram,i)); tempPoint1.setX(xAxisMin+width); tempPoint1.setY(gsl_histogram_get(m_histogram,i)); lines.append(QLineF(tempPoint,tempPoint1)); tempPoint.setX(xAxisMin+width); tempPoint.setY(gsl_histogram_get(m_histogram,i)); tempPoint1.setX(xAxisMin+width); tempPoint1.setY(0.0); lines.append(QLineF(tempPoint, tempPoint1)); tempPoint.setX(xAxisMin+width); tempPoint.setY(0.0); tempPoint1.setX(xAxisMin); tempPoint1.setY(0.0); lines.append(QLineF(tempPoint, tempPoint1)); xAxisMin+= width; } } void HistogramPrivate::verticalCumulativeHistogram() { double point =0.0; double xAxisMin = xColumn->minimum(); double xAxisMax = xColumn->maximum(); QPointF tempPoint,tempPoint1; double width = (xAxisMax-xAxisMin)/m_bins; for(size_t i=0; i < m_bins; ++i) { point+= gsl_histogram_get(m_histogram,i); tempPoint.setX(xAxisMin); tempPoint.setY(0.0); tempPoint1.setX(xAxisMin); tempPoint1.setY(point); lines.append(QLineF(tempPoint, tempPoint1)); tempPoint.setX(xAxisMin); tempPoint.setY(point); tempPoint1.setX(xAxisMin+width); tempPoint1.setY(point); lines.append(QLineF(tempPoint,tempPoint1)); tempPoint.setX(xAxisMin+width); tempPoint.setY(point); tempPoint1.setX(xAxisMin+width); tempPoint1.setY(0.0); lines.append(QLineF(tempPoint, tempPoint1)); tempPoint.setX(xAxisMin+width); tempPoint.setY(0.0); tempPoint1.setX(xAxisMin); tempPoint1.setY(0.0); lines.append(QLineF(tempPoint, tempPoint1)); xAxisMin+= width; } } void HistogramPrivate::verticalHistogram() { switch(histogramType) { case Histogram::Ordinary: { verticalOrdinaryHistogram(); break; } case Histogram::Cumulative: { verticalCumulativeHistogram(); break; } case Histogram::AvgShift: { //TODO break; } } } void HistogramPrivate::horizontalOrdinaryHistogram() { QPointF tempPoint,tempPoint1; double yAxisMin = xColumn->minimum(); double yAxisMax = xColumn->maximum(); double width = (yAxisMax-yAxisMin)/m_bins; for(size_t i = 0; i < m_bins; ++i) { tempPoint.setY(yAxisMin); tempPoint.setX(0.0); tempPoint1.setY(yAxisMin); tempPoint1.setX(gsl_histogram_get(m_histogram,i)); lines.append(QLineF(tempPoint, tempPoint1)); tempPoint.setY(yAxisMin); tempPoint.setX(gsl_histogram_get(m_histogram,i)); tempPoint1.setY(yAxisMin + width); tempPoint1.setX(gsl_histogram_get(m_histogram,i)); lines.append(QLineF(tempPoint,tempPoint1)); tempPoint.setY(yAxisMin+width); tempPoint.setX(gsl_histogram_get(m_histogram,i)); tempPoint1.setY(yAxisMin + width); tempPoint1.setX(0.0); lines.append(QLineF(tempPoint, tempPoint1)); tempPoint.setY(yAxisMin + width); tempPoint.setX(0.0); tempPoint1.setY(yAxisMin); tempPoint1.setX(0.0); lines.append(QLineF(tempPoint, tempPoint1)); yAxisMin += width; } } void HistogramPrivate::horizontalCumulativeHistogram() { double point =0.0; double yAxisMin = xColumn->minimum(); double yAxisMax = xColumn->maximum(); QPointF tempPoint,tempPoint1; double width = (yAxisMax-yAxisMin)/m_bins; for(size_t i=0; i < m_bins; ++i) { point+= gsl_histogram_get(m_histogram,i); tempPoint.setY(yAxisMin); tempPoint.setX(0.0); tempPoint1.setY(yAxisMin); tempPoint1.setX(point); lines.append(QLineF(tempPoint, tempPoint1)); tempPoint.setY(yAxisMin); tempPoint.setX(point); tempPoint1.setY(yAxisMin+width); tempPoint1.setX(point); lines.append(QLineF(tempPoint,tempPoint1)); tempPoint.setY(yAxisMin+width); tempPoint.setX(point); tempPoint1.setY(yAxisMin+width); tempPoint1.setX(0.0); lines.append(QLineF(tempPoint, tempPoint1)); tempPoint.setY(yAxisMin+width); tempPoint.setX(0.0); tempPoint1.setY(yAxisMin); tempPoint1.setX(0.0); lines.append(QLineF(tempPoint, tempPoint1)); yAxisMin+= width; } } void HistogramPrivate::horizontalHistogram() { switch(histogramType) { case Histogram::Ordinary: { horizontalOrdinaryHistogram(); break; } case Histogram::Cumulative: { horizontalCumulativeHistogram(); break; } case Histogram::AvgShift: { //TODO break; } } } /*! recalculates the painter path for the lines connecting the data points. Called each time when the type of this connection is changed. */ void HistogramPrivate::updateLines() { linePath = QPainterPath(); lines.clear(); const int count=symbolPointsLogical.count(); //nothing to do, if no data points available if (count<=1) { recalcShapeAndBoundingRect(); return; } double xAxisMin = xColumn->minimum(); double xAxisMax = xColumn->maximum(); - switch (histogramData.binsOption) { - case Histogram::Number: - m_bins = (size_t)histogramData.binValue; + switch (histogramData.binningMethod) { + case Histogram::ByNumber: + m_bins = (size_t)histogramData.binCount; break; case Histogram::SquareRoot: - m_bins = (size_t)sqrt(histogramData.binValue); + m_bins = (size_t)sqrt(histogramData.binCount); break; case Histogram::RiceRule: - m_bins = (size_t)2*cbrt(histogramData.binValue); + m_bins = (size_t)2*cbrt(histogramData.binCount); break; - case Histogram::Width: - m_bins = (size_t) (xAxisMax-xAxisMin)/histogramData.binValue; + case Histogram::ByWidth: + m_bins = (size_t) (xAxisMax-xAxisMin)/histogramData.binCount; break; case Histogram::SturgisRule: - m_bins =(size_t) 1 + 3.33*log(histogramData.binValue); + m_bins =(size_t) 1 + 3.33*log(histogramData.binCount); break; } m_histogram = gsl_histogram_alloc (m_bins); // demo- number of bins gsl_histogram_set_ranges_uniform (m_histogram, xAxisMin,xAxisMax+1); int startRow = 0; int endRow = xColumn->rowCount() - 1; for (int row = startRow; row <= endRow; row++ ) { if ( xColumn->isValid(row) && !xColumn->isMasked(row) ) gsl_histogram_increment(m_histogram, xColumn->valueAt(row)); } switch(histogramOrientation) { case Histogram::Vertical: { verticalHistogram(); break; } case Histogram::Horizontal: { horizontalHistogram(); break; } } //calculate the lines connecting the data points for (int i = 0; i(q->parentAspect()); const AbstractCoordinateSystem* cSystem = plot->coordinateSystem(); lines = cSystem->mapLogicalToScene(lines); //new line path for (const auto& line: lines) { linePath.moveTo(line.p1()); linePath.lineTo(line.p2()); } updateFilling(); recalcShapeAndBoundingRect(); } /*! recreates the value strings to be shown and recalculates their draw position. */ void HistogramPrivate::updateValues() { valuesPath = QPainterPath(); valuesPoints.clear(); valuesStrings.clear(); if (valuesType == Histogram::NoValues) { recalcShapeAndBoundingRect(); return; } //determine the value string for all points that are currently visible in the plot if (valuesType == Histogram::ValuesY || valuesType == Histogram::ValuesYBracketed) { switch(histogramType) { case Histogram::Ordinary: for(size_t i=0; irowCount()); const AbstractColumn::ColumnMode xColMode = valuesColumn->columnMode(); for (int i = 0; i < endRow; ++i) { if (!visiblePoints[i]) continue; if ( !valuesColumn->isValid(i) || valuesColumn->isMasked(i) ) continue; switch (xColMode) { case AbstractColumn::Numeric: valuesStrings << valuesPrefix + QString::number(valuesColumn->valueAt(i)) + valuesSuffix; break; case AbstractColumn::Text: valuesStrings << valuesPrefix + valuesColumn->textAt(i) + valuesSuffix; case AbstractColumn::Integer: case AbstractColumn::DateTime: case AbstractColumn::Month: case AbstractColumn::Day: //TODO break; } } } //Calculate the coordinates where to paint the value strings. //The coordinates depend on the actual size of the string. QPointF tempPoint; QFontMetrics fm(valuesFont); qreal w; qreal h = fm.ascent(); double xAxisMin = xColumn->minimum(); double xAxisMax = xColumn->maximum(); double width = (xAxisMax-xAxisMin)/m_bins; switch(valuesPosition) { case Histogram::ValuesAbove: for (int i = 0; i < valuesStrings.size(); i++) { w=fm.width(valuesStrings.at(i)); tempPoint.setX( symbolPointsScene.at(i).x() -w/2 +xAxisMin); tempPoint.setY( symbolPointsScene.at(i).y() - valuesDistance ); valuesPoints.append(tempPoint); xAxisMin+= 9*width; } break; case Histogram::ValuesUnder: for (int i = 0; i < valuesStrings.size(); i++) { w=fm.width(valuesStrings.at(i)); tempPoint.setX( symbolPointsScene.at(i).x() -w/2+xAxisMin ); tempPoint.setY( symbolPointsScene.at(i).y() + valuesDistance + h/2); valuesPoints.append(tempPoint); xAxisMin+= 9*width; } break; case Histogram::ValuesLeft: for (int i = 0; i < valuesStrings.size(); i++) { w=fm.width(valuesStrings.at(i)); tempPoint.setX( symbolPointsScene.at(i).x() - valuesDistance - w - 1 +xAxisMin); tempPoint.setY( symbolPointsScene.at(i).y()); valuesPoints.append(tempPoint); xAxisMin+= 9*width; } break; case Histogram::ValuesRight: for (int i = 0; i < valuesStrings.size(); i++) { tempPoint.setX( symbolPointsScene.at(i).x() + valuesDistance - 1 +xAxisMin); tempPoint.setY( symbolPointsScene.at(i).y() ); valuesPoints.append(tempPoint); xAxisMin+= 9*width; } break; } QTransform trafo; QPainterPath path; for (int i = 0; i < valuesPoints.size(); i++) { path = QPainterPath(); path.addText( QPoint(0,0), valuesFont, valuesStrings.at(i) ); trafo.reset(); trafo.translate( valuesPoints.at(i).x(), valuesPoints.at(i).y() ); if (valuesRotationAngle!=0) trafo.rotate( -valuesRotationAngle ); valuesPath.addPath(trafo.map(path)); } recalcShapeAndBoundingRect(); } void HistogramPrivate::updateFilling() { fillPolygons.clear(); if (fillingPosition==Histogram::NoFilling) { recalcShapeAndBoundingRect(); return; } QVector fillLines; const CartesianPlot* plot = dynamic_cast(q->parentAspect()); const AbstractCoordinateSystem* cSystem = plot->coordinateSystem(); //if there're no interpolation lines available (Histogram::NoLine selected), create line-interpolation, //use already available lines otherwise. if (lines.size()) fillLines = lines; else { for (int i=0; imapLogicalToScene(fillLines); } //no lines available (no points), nothing to do if (!fillLines.size()) return; //create polygon(s): //1. Depending on the current zoom-level, only a subset of the curve may be visible in the plot //and more of the filling area should be shown than the area defined by the start and end points of the currently visible points. //We check first whether the curve crosses the boundaries of the plot and determine new start and end points and put them to the boundaries. //2. Furthermore, depending on the current filling type we determine the end point (x- or y-coordinate) where all polygons are closed at the end. QPolygonF pol; QPointF start = fillLines.at(0).p1(); //starting point of the current polygon, initialize with the first visible point QPointF end = fillLines.at(fillLines.size()-1).p2(); //starting point of the current polygon, initialize with the last visible point const QPointF& first = symbolPointsLogical.at(0); //first point of the curve, may not be visible currently const QPointF& last = symbolPointsLogical.at(symbolPointsLogical.size()-1);//first point of the curve, may not be visible currently QPointF edge; float xEnd=0, yEnd=0; if (fillingPosition == Histogram::FillingAbove) { edge = cSystem->mapLogicalToScene(QPointF(plot->xMin(), plot->yMin())); //start point if (AbstractCoordinateSystem::essentiallyEqual(start.y(), edge.y())) { if (first.x() < plot->xMin()) start = edge; else if (first.x() > plot->xMax()) start = cSystem->mapLogicalToScene(QPointF(plot->xMax(), plot->yMin())); else start = cSystem->mapLogicalToScene(QPointF(first.x(), plot->yMin())); } //end point if (AbstractCoordinateSystem::essentiallyEqual(end.y(), edge.y())) { if (last.x() < plot->xMin()) end = edge; else if (last.x() > plot->xMax()) end = cSystem->mapLogicalToScene(QPointF(plot->xMax(), plot->yMin())); else end = cSystem->mapLogicalToScene(QPointF(last.x(), plot->yMin())); } //coordinate at which to close all polygons yEnd = cSystem->mapLogicalToScene(QPointF(plot->xMin(), plot->yMax())).y(); } else if (fillingPosition == Histogram::FillingBelow) { edge = cSystem->mapLogicalToScene(QPointF(plot->xMin(), plot->yMax())); //start point if (AbstractCoordinateSystem::essentiallyEqual(start.y(), edge.y())) { if (first.x() < plot->xMin()) start = edge; else if (first.x() > plot->xMax()) start = cSystem->mapLogicalToScene(QPointF(plot->xMax(), plot->yMax())); else start = cSystem->mapLogicalToScene(QPointF(first.x(), plot->yMax())); } //end point if (AbstractCoordinateSystem::essentiallyEqual(end.y(), edge.y())) { if (last.x() < plot->xMin()) end = edge; else if (last.x() > plot->xMax()) end = cSystem->mapLogicalToScene(QPointF(plot->xMax(), plot->yMax())); else end = cSystem->mapLogicalToScene(QPointF(last.x(), plot->yMax())); } //coordinate at which to close all polygons yEnd = cSystem->mapLogicalToScene(QPointF(plot->xMin(), plot->yMin())).y(); } else if (fillingPosition == Histogram::FillingZeroBaseline) { edge = cSystem->mapLogicalToScene(QPointF(plot->xMin(), plot->yMax())); //start point if (AbstractCoordinateSystem::essentiallyEqual(start.y(), edge.y())) { if (plot->yMax()>0) { if (first.x() < plot->xMin()) start = edge; else if (first.x() > plot->xMax()) start = cSystem->mapLogicalToScene(QPointF(plot->xMax(), plot->yMax())); else start = cSystem->mapLogicalToScene(QPointF(first.x(), plot->yMax())); } else { if (first.x() < plot->xMin()) start = edge; else if (first.x() > plot->xMax()) start = cSystem->mapLogicalToScene(QPointF(plot->xMax(), plot->yMin())); else start = cSystem->mapLogicalToScene(QPointF(first.x(), plot->yMin())); } } //end point if (AbstractCoordinateSystem::essentiallyEqual(end.y(), edge.y())) { if (plot->yMax()>0) { if (last.x() < plot->xMin()) end = edge; else if (last.x() > plot->xMax()) end = cSystem->mapLogicalToScene(QPointF(plot->xMax(), plot->yMax())); else end = cSystem->mapLogicalToScene(QPointF(last.x(), plot->yMax())); } else { if (last.x() < plot->xMin()) end = edge; else if (last.x() > plot->xMax()) end = cSystem->mapLogicalToScene(QPointF(plot->xMax(), plot->yMin())); else end = cSystem->mapLogicalToScene(QPointF(last.x(), plot->yMin())); } } yEnd = cSystem->mapLogicalToScene(QPointF(plot->xMin(), plot->yMin()>0 ? plot->yMin() : 0)).y(); } else if (fillingPosition == Histogram::FillingLeft) { edge = cSystem->mapLogicalToScene(QPointF(plot->xMax(), plot->yMin())); //start point if (AbstractCoordinateSystem::essentiallyEqual(start.x(), edge.x())) { if (first.y() < plot->yMin()) start = edge; else if (first.y() > plot->yMax()) start = cSystem->mapLogicalToScene(QPointF(plot->xMax(), plot->yMax())); else start = cSystem->mapLogicalToScene(QPointF(plot->xMax(), first.y())); } //end point if (AbstractCoordinateSystem::essentiallyEqual(end.x(), edge.x())) { if (last.y() < plot->yMin()) end = edge; else if (last.y() > plot->yMax()) end = cSystem->mapLogicalToScene(QPointF(plot->xMax(), plot->yMax())); else end = cSystem->mapLogicalToScene(QPointF(plot->xMax(), last.y())); } //coordinate at which to close all polygons xEnd = cSystem->mapLogicalToScene(QPointF(plot->xMin(), plot->yMin())).x(); } else { //FillingRight edge = cSystem->mapLogicalToScene(QPointF(plot->xMin(), plot->yMin())); //start point if (AbstractCoordinateSystem::essentiallyEqual(start.x(), edge.x())) { if (first.y() < plot->yMin()) start = edge; else if (first.y() > plot->yMax()) start = cSystem->mapLogicalToScene(QPointF(plot->xMin(), plot->yMax())); else start = cSystem->mapLogicalToScene(QPointF(plot->xMin(), first.y())); } //end point if (AbstractCoordinateSystem::essentiallyEqual(end.x(), edge.x())) { if (last.y() < plot->yMin()) end = edge; else if (last.y() > plot->yMax()) end = cSystem->mapLogicalToScene(QPointF(plot->xMin(), plot->yMax())); else end = cSystem->mapLogicalToScene(QPointF(plot->xMin(), last.y())); } //coordinate at which to close all polygons xEnd = cSystem->mapLogicalToScene(QPointF(plot->xMax(), plot->yMin())).x(); } if (start != fillLines.at(0).p1()) pol << start; QPointF p1, p2; for (int i=0; icheck whether we have a break in between. const bool gap = false; //TODO if (!gap) { //-> we have no break in the curve -> connect the points by a horizontal/vertical line pol << fillLines.at(i-1).p2() << p1; } else { //-> we have a break in the curve -> close the polygon add it to the polygon list and start a new polygon if (fillingPosition==Histogram::FillingAbove || fillingPosition==Histogram::FillingBelow || fillingPosition==Histogram::FillingZeroBaseline) { pol << QPointF(fillLines.at(i-1).p2().x(), yEnd); pol << QPointF(start.x(), yEnd); } else { pol << QPointF(xEnd, fillLines.at(i-1).p2().y()); pol << QPointF(xEnd, start.y()); } fillPolygons << pol; pol.clear(); start = p1; } } pol << p1 << p2; } if (p2!=end) pol << end; //close the last polygon if (fillingPosition==Histogram::FillingAbove || fillingPosition==Histogram::FillingBelow || fillingPosition==Histogram::FillingZeroBaseline) { pol << QPointF(end.x(), yEnd); pol << QPointF(start.x(), yEnd); } else { pol << QPointF(xEnd, end.y()); pol << QPointF(xEnd, start.y()); } fillPolygons << pol; recalcShapeAndBoundingRect(); } /*! recalculates the outer bounds and the shape of the curve. */ void HistogramPrivate::recalcShapeAndBoundingRect() { //if (m_suppressRecalc) // return; prepareGeometryChange(); curveShape = QPainterPath(); curveShape.addPath(WorksheetElement::shapeFromPath(linePath, linePen)); if (valuesType != Histogram::NoValues) curveShape.addPath(valuesPath); boundingRectangle = curveShape.boundingRect(); for (const auto& pol : fillPolygons) boundingRectangle = boundingRectangle.united(pol.boundingRect()); //TODO: when the selection is painted, line intersections are visible. //simplified() removes those artifacts but is horrible slow for curves with large number of points. //search for an alternative. //curveShape = curveShape.simplified(); updatePixmap(); } void HistogramPrivate::draw(QPainter *painter) { //drawing line painter->setOpacity(lineOpacity); painter->setPen(linePen); painter->setBrush(Qt::NoBrush); painter->drawPath(linePath); //draw filling if (fillingPosition != Histogram::NoFilling) { painter->setOpacity(fillingOpacity); painter->setPen(Qt::SolidLine); drawFilling(painter); } //draw values if (valuesType != Histogram::NoValues) { painter->setOpacity(valuesOpacity); painter->setPen(valuesColor); painter->setBrush(Qt::SolidPattern); drawValues(painter); } } void HistogramPrivate::updatePixmap() { QPixmap pixmap(boundingRectangle.width(), boundingRectangle.height()); if (boundingRectangle.width()==0 || boundingRectangle.width()==0) { m_pixmap = pixmap; m_hoverEffectImageIsDirty = true; m_selectionEffectImageIsDirty = true; return; } pixmap.fill(Qt::transparent); QPainter painter(&pixmap); painter.setRenderHint(QPainter::Antialiasing, true); painter.translate(-boundingRectangle.topLeft()); draw(&painter); painter.end(); m_pixmap = pixmap; m_hoverEffectImageIsDirty = true; m_selectionEffectImageIsDirty = true; } /*! Reimplementation of QGraphicsItem::paint(). This function does the actual painting of the curve. \sa QGraphicsItem::paint(). */ void HistogramPrivate::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { Q_UNUSED(option); Q_UNUSED(widget); if (!isVisible()) return; painter->setPen(Qt::NoPen); painter->setBrush(Qt::NoBrush); painter->setRenderHint(QPainter::SmoothPixmapTransform, true); draw(painter); if (m_hovered && !isSelected() && !m_printing) { if (m_hoverEffectImageIsDirty) { QPixmap pix = m_pixmap; pix.fill(QApplication::palette().color(QPalette::Shadow)); pix.setAlphaChannel(m_pixmap.alphaChannel()); m_hoverEffectImage = ImageTools::blurred(pix.toImage(), m_pixmap.rect(), 5); m_hoverEffectImageIsDirty = false; } painter->drawImage(boundingRectangle.topLeft(), m_hoverEffectImage, m_pixmap.rect()); return; } if (isSelected() && !m_printing) { if (m_selectionEffectImageIsDirty) { QPixmap pix = m_pixmap; pix.fill(QApplication::palette().color(QPalette::Highlight)); pix.setAlphaChannel(m_pixmap.alphaChannel()); m_selectionEffectImage = ImageTools::blurred(pix.toImage(), m_pixmap.rect(), 5); m_selectionEffectImageIsDirty = false; } painter->drawImage(boundingRectangle.topLeft(), m_selectionEffectImage, m_pixmap.rect()); return; } } /*! Drawing of symbolsPath is very slow, so we draw every symbol in the loop which us much faster (factor 10) */ void HistogramPrivate::drawValues(QPainter* painter) { QTransform trafo; QPainterPath path; for (int i=0; idrawPath(trafo.map(path)); } } void HistogramPrivate::drawFilling(QPainter* painter) { for (const auto& pol : fillPolygons) { QRectF rect = pol.boundingRect(); if (fillingType == PlotArea::Color) { switch (fillingColorStyle) { case PlotArea::SingleColor: { painter->setBrush(QBrush(fillingFirstColor)); break; } case PlotArea::HorizontalLinearGradient: { QLinearGradient linearGrad(rect.topLeft(), rect.topRight()); linearGrad.setColorAt(0, fillingFirstColor); linearGrad.setColorAt(1, fillingSecondColor); painter->setBrush(QBrush(linearGrad)); break; } case PlotArea::VerticalLinearGradient: { QLinearGradient linearGrad(rect.topLeft(), rect.bottomLeft()); linearGrad.setColorAt(0, fillingFirstColor); linearGrad.setColorAt(1, fillingSecondColor); painter->setBrush(QBrush(linearGrad)); break; } case PlotArea::TopLeftDiagonalLinearGradient: { QLinearGradient linearGrad(rect.topLeft(), rect.bottomRight()); linearGrad.setColorAt(0, fillingFirstColor); linearGrad.setColorAt(1, fillingSecondColor); painter->setBrush(QBrush(linearGrad)); break; } case PlotArea::BottomLeftDiagonalLinearGradient: { QLinearGradient linearGrad(rect.bottomLeft(), rect.topRight()); linearGrad.setColorAt(0, fillingFirstColor); linearGrad.setColorAt(1, fillingSecondColor); painter->setBrush(QBrush(linearGrad)); break; } case PlotArea::RadialGradient: { QRadialGradient radialGrad(rect.center(), rect.width()/2); radialGrad.setColorAt(0, fillingFirstColor); radialGrad.setColorAt(1, fillingSecondColor); painter->setBrush(QBrush(radialGrad)); break; } } } else if (fillingType == PlotArea::Image) { if ( !fillingFileName.trimmed().isEmpty() ) { QPixmap pix(fillingFileName); switch (fillingImageStyle) { case PlotArea::ScaledCropped: pix = pix.scaled(rect.size().toSize(),Qt::KeepAspectRatioByExpanding,Qt::SmoothTransformation); painter->setBrush(QBrush(pix)); painter->setBrushOrigin(pix.size().width()/2,pix.size().height()/2); break; case PlotArea::Scaled: pix = pix.scaled(rect.size().toSize(),Qt::IgnoreAspectRatio,Qt::SmoothTransformation); painter->setBrush(QBrush(pix)); painter->setBrushOrigin(pix.size().width()/2,pix.size().height()/2); break; case PlotArea::ScaledAspectRatio: pix = pix.scaled(rect.size().toSize(),Qt::KeepAspectRatio,Qt::SmoothTransformation); painter->setBrush(QBrush(pix)); painter->setBrushOrigin(pix.size().width()/2,pix.size().height()/2); break; case PlotArea::Centered: { QPixmap backpix(rect.size().toSize()); backpix.fill(); QPainter p(&backpix); p.drawPixmap(QPointF(0,0),pix); p.end(); painter->setBrush(QBrush(backpix)); painter->setBrushOrigin(-pix.size().width()/2,-pix.size().height()/2); break; } case PlotArea::Tiled: painter->setBrush(QBrush(pix)); break; case PlotArea::CenterTiled: painter->setBrush(QBrush(pix)); painter->setBrushOrigin(pix.size().width()/2,pix.size().height()/2); } } } else if (fillingType == PlotArea::Pattern) painter->setBrush(QBrush(fillingFirstColor,fillingBrushStyle)); painter->drawPolygon(pol); } } void HistogramPrivate::hoverEnterEvent(QGraphicsSceneHoverEvent*) { const CartesianPlot* plot = dynamic_cast(q->parentAspect()); if (plot->mouseMode() == CartesianPlot::SelectionMode && !isSelected()) { m_hovered = true; emit q->hovered(); update(); } } void HistogramPrivate::hoverLeaveEvent(QGraphicsSceneHoverEvent*) { const CartesianPlot* plot = dynamic_cast(q->parentAspect()); if (plot->mouseMode() == CartesianPlot::SelectionMode && m_hovered) { m_hovered = false; emit q->unhovered(); update(); } } void HistogramPrivate::recalculate() { emit q->HistogramDataChanged(); } //############################################################################## //################## Serialization/Deserialization ########################### //############################################################################## //! Save as XML void Histogram::save(QXmlStreamWriter* writer) const { Q_D(const Histogram); writer->writeStartElement( "Histogram" ); writeBasicAttributes( writer ); writeCommentElement( writer ); //general writer->writeStartElement( "general" ); WRITE_COLUMN(d->xColumn, xColumn); writer->writeAttribute( "visible", QString::number(d->isVisible()) ); writer->writeEndElement(); //Line writer->writeStartElement( "lines" ); WRITE_QPEN(d->linePen); writer->writeEndElement(); //Values writer->writeStartElement( "values" ); writer->writeAttribute( "type", QString::number(d->valuesType) ); WRITE_COLUMN(d->valuesColumn, valuesColumn); writer->writeAttribute( "position", QString::number(d->valuesPosition) ); writer->writeAttribute( "distance", QString::number(d->valuesDistance) ); writer->writeAttribute( "rotation", QString::number(d->valuesRotationAngle) ); writer->writeAttribute( "opacity", QString::number(d->valuesOpacity) ); //TODO values format and precision writer->writeAttribute( "prefix", d->valuesPrefix ); writer->writeAttribute( "suffix", d->valuesSuffix ); WRITE_QCOLOR(d->valuesColor); WRITE_QFONT(d->valuesFont); writer->writeEndElement(); //Filling writer->writeStartElement( "filling" ); writer->writeAttribute( "position", QString::number(d->fillingPosition) ); writer->writeAttribute( "type", QString::number(d->fillingType) ); writer->writeAttribute( "colorStyle", QString::number(d->fillingColorStyle) ); writer->writeAttribute( "imageStyle", QString::number(d->fillingImageStyle) ); writer->writeAttribute( "brushStyle", QString::number(d->fillingBrushStyle) ); writer->writeAttribute( "firstColor_r", QString::number(d->fillingFirstColor.red()) ); writer->writeAttribute( "firstColor_g", QString::number(d->fillingFirstColor.green()) ); writer->writeAttribute( "firstColor_b", QString::number(d->fillingFirstColor.blue()) ); writer->writeAttribute( "secondColor_r", QString::number(d->fillingSecondColor.red()) ); writer->writeAttribute( "secondColor_g", QString::number(d->fillingSecondColor.green()) ); writer->writeAttribute( "secondColor_b", QString::number(d->fillingSecondColor.blue()) ); writer->writeAttribute( "fileName", d->fillingFileName ); writer->writeAttribute( "opacity", QString::number(d->fillingOpacity) ); writer->writeEndElement(); //write Histogram specific information writer->writeStartElement( "typeChanged" ); writer->writeAttribute( "Histogramtype", QString::number(d->histogramData.type) ); - writer->writeAttribute( "BinsOption", QString::number(d->histogramData.binsOption) ); - writer->writeAttribute( "binValue", QString::number(d->histogramData.binValue)); + writer->writeAttribute( "BinningMethod", QString::number(d->histogramData.binningMethod) ); + writer->writeAttribute( "binValue", QString::number(d->histogramData.binCount)); writer->writeEndElement(); if (d->xColumn) d->xColumn->save(writer); writer->writeEndElement(); //close "Histogram" section } //! Load from XML bool Histogram::load(XmlStreamReader* reader, bool preview) { Q_D(Histogram); if (!readBasicAttributes(reader)) return false; KLocalizedString attributeWarning = ki18n("Attribute '%1' missing or empty, default value is used"); QXmlStreamAttributes attribs; QString str; while (!reader->atEnd()) { reader->readNext(); if (reader->isEndElement() && reader->name() == "Histogram") break; if (!reader->isStartElement()) continue; if (reader->name() == "comment") { if (!readCommentElement(reader)) return false; } else if (!preview && reader->name() == "general") { attribs = reader->attributes(); READ_COLUMN(xColumn); str = attribs.value("visible").toString(); if(str.isEmpty()) reader->raiseWarning(attributeWarning.subs("visible").toString()); else d->setVisible(str.toInt()); } else if (!preview && reader->name() == "typeChanged") { attribs = reader->attributes(); str = attribs.value("type").toString(); if(str.isEmpty()) reader->raiseWarning(attributeWarning.subs("type").toString()); else d->histogramType = (Histogram::HistogramType)str.toInt(); - str = attribs.value("BinsOption").toString(); - d->binsOption = (Histogram::BinsOption)str.toInt(); + str = attribs.value("BinningMethod").toString(); + d->binningMethod = (Histogram::BinningMethod)str.toInt(); str = attribs.value("binValue").toString(); - d->histogramData.binValue = str.toInt(); + d->histogramData.binCount = str.toInt(); } else if (!preview && reader->name() == "values") { attribs = reader->attributes(); str = attribs.value("type").toString(); if(str.isEmpty()) reader->raiseWarning(attributeWarning.subs("type").toString()); else d->valuesType = (Histogram::ValuesType)str.toInt(); READ_COLUMN(valuesColumn); str = attribs.value("position").toString(); if(str.isEmpty()) reader->raiseWarning(attributeWarning.subs("position").toString()); else d->valuesPosition = (Histogram::ValuesPosition)str.toInt(); str = attribs.value("distance").toString(); if(str.isEmpty()) reader->raiseWarning(attributeWarning.subs("distance").toString()); else d->valuesDistance = str.toDouble(); str = attribs.value("rotation").toString(); if(str.isEmpty()) reader->raiseWarning(attributeWarning.subs("rotation").toString()); else d->valuesRotationAngle = str.toDouble(); str = attribs.value("opacity").toString(); if(str.isEmpty()) reader->raiseWarning(attributeWarning.subs("opacity").toString()); else d->valuesOpacity = str.toDouble(); //don't produce any warning if no prefix or suffix is set (empty string is allowd here in xml) d->valuesPrefix = attribs.value("prefix").toString(); d->valuesSuffix = attribs.value("suffix").toString(); READ_QCOLOR(d->valuesColor); READ_QFONT(d->valuesFont); str = attribs.value("opacity").toString(); if(str.isEmpty()) reader->raiseWarning(attributeWarning.subs("opacity").toString()); else d->valuesOpacity = str.toDouble(); } else if (!preview && reader->name() == "filling") { attribs = reader->attributes(); str = attribs.value("position").toString(); if(str.isEmpty()) reader->raiseWarning(attributeWarning.subs("position").toString()); else d->fillingPosition = Histogram::FillingPosition(str.toInt()); str = attribs.value("type").toString(); if(str.isEmpty()) reader->raiseWarning(attributeWarning.subs("type").toString()); else d->fillingType = PlotArea::BackgroundType(str.toInt()); str = attribs.value("colorStyle").toString(); if(str.isEmpty()) reader->raiseWarning(attributeWarning.subs("colorStyle").toString()); else d->fillingColorStyle = PlotArea::BackgroundColorStyle(str.toInt()); str = attribs.value("imageStyle").toString(); if(str.isEmpty()) reader->raiseWarning(attributeWarning.subs("imageStyle").toString()); else d->fillingImageStyle = PlotArea::BackgroundImageStyle(str.toInt()); str = attribs.value("brushStyle").toString(); if(str.isEmpty()) reader->raiseWarning(attributeWarning.subs("brushStyle").toString()); else d->fillingBrushStyle = Qt::BrushStyle(str.toInt()); str = attribs.value("firstColor_r").toString(); if(str.isEmpty()) reader->raiseWarning(attributeWarning.subs("firstColor_r").toString()); else d->fillingFirstColor.setRed(str.toInt()); str = attribs.value("firstColor_g").toString(); if(str.isEmpty()) reader->raiseWarning(attributeWarning.subs("firstColor_g").toString()); else d->fillingFirstColor.setGreen(str.toInt()); str = attribs.value("firstColor_b").toString(); if(str.isEmpty()) reader->raiseWarning(attributeWarning.subs("firstColor_b").toString()); else d->fillingFirstColor.setBlue(str.toInt()); str = attribs.value("secondColor_r").toString(); if(str.isEmpty()) reader->raiseWarning(attributeWarning.subs("secondColor_r").toString()); else d->fillingSecondColor.setRed(str.toInt()); str = attribs.value("secondColor_g").toString(); if(str.isEmpty()) reader->raiseWarning(attributeWarning.subs("secondColor_g").toString()); else d->fillingSecondColor.setGreen(str.toInt()); str = attribs.value("secondColor_b").toString(); if(str.isEmpty()) reader->raiseWarning(attributeWarning.subs("secondColor_b").toString()); else d->fillingSecondColor.setBlue(str.toInt()); str = attribs.value("fileName").toString(); d->fillingFileName = str; str = attribs.value("opacity").toString(); if(str.isEmpty()) reader->raiseWarning(attributeWarning.subs("opacity").toString()); else d->fillingOpacity = str.toDouble(); } else if(reader->name() == "column") { Column* column = new Column("", AbstractColumn::Numeric); if (!column->load(reader, preview)) { delete column; return false; } d->xColumn = column; } } return true; } diff --git a/src/backend/worksheet/plots/cartesian/Histogram.h b/src/backend/worksheet/plots/cartesian/Histogram.h index 2378ff8d2..00617e9eb 100644 --- a/src/backend/worksheet/plots/cartesian/Histogram.h +++ b/src/backend/worksheet/plots/cartesian/Histogram.h @@ -1,207 +1,208 @@ /*************************************************************************** File : Histogram.h Project : LabPlot Description : Histogram -------------------------------------------------------------------- Copyright : (C) 2016 Anu Mittal (anu22mittal@gmail.com) ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #ifndef HISTOGRAM_H #define HISTOGRAM_H #include "backend/worksheet/WorksheetElement.h" #include "backend/worksheet/plots/PlotArea.h" #include "backend/core/AbstractColumn.h" #include "backend/lib/macros.h" class HistogramPrivate; class Histogram: public WorksheetElement { Q_OBJECT public: - enum BinsOption {Number,Width,SquareRoot,RiceRule,SturgisRule}; + enum BinningMethod {ByNumber, ByWidth, SquareRoot, RiceRule, SturgisRule}; enum ValuesType {NoValues, ValuesY, ValuesYBracketed, ValuesCustomColumn}; enum ValuesPosition {ValuesAbove, ValuesUnder, ValuesLeft, ValuesRight}; enum FillingPosition {NoFilling, FillingAbove, FillingBelow, FillingZeroBaseline, FillingLeft, FillingRight}; enum HistogramType {Ordinary,Cumulative, AvgShift}; enum HistogramOrientation {Vertical, Horizontal}; struct HistogramData { - HistogramData() : type(Ordinary),binsOption(Number), binValue(10) {}; + HistogramData() : type(Ordinary), binningMethod(ByNumber), binCount(10), binWidth(1.0) {}; HistogramType type; - BinsOption binsOption; - int binValue; + BinningMethod binningMethod; + int binCount; + double binWidth; }; explicit Histogram(const QString &name); //size_t bins; QIcon icon() const override; QMenu* createContextMenu() override; QGraphicsItem* graphicsItem() const override; void save(QXmlStreamWriter*) const override; bool load(XmlStreamReader*, bool preview) override; CLASS_D_ACCESSOR_DECL(HistogramData, histogramData, HistogramData) BASIC_D_ACCESSOR_DECL(Histogram::HistogramType, histogramType, HistogramType) BASIC_D_ACCESSOR_DECL(Histogram::HistogramOrientation, histogramOrientation, HistogramOrientation) POINTER_D_ACCESSOR_DECL(const AbstractColumn, xColumn, XColumn) POINTER_D_ACCESSOR_DECL(const AbstractColumn, yColumn, YColumn) QString& xColumnPath() const; QString& yColumnPath() const; BASIC_D_ACCESSOR_DECL(float, xMin, XMin) BASIC_D_ACCESSOR_DECL(float, xMax, XMax) BASIC_D_ACCESSOR_DECL(float, yMin, YMin) BASIC_D_ACCESSOR_DECL(float, yMax, YMax) BASIC_D_ACCESSOR_DECL(ValuesType, valuesType, ValuesType) POINTER_D_ACCESSOR_DECL(const AbstractColumn, valuesColumn, ValuesColumn) QString& valuesColumnPath() const; CLASS_D_ACCESSOR_DECL(QPen, linePen, LinePen) BASIC_D_ACCESSOR_DECL(ValuesPosition, valuesPosition, ValuesPosition) BASIC_D_ACCESSOR_DECL(qreal, valuesDistance, ValuesDistance) BASIC_D_ACCESSOR_DECL(qreal, valuesRotationAngle, ValuesRotationAngle) BASIC_D_ACCESSOR_DECL(qreal, valuesOpacity, ValuesOpacity) CLASS_D_ACCESSOR_DECL(QString, valuesPrefix, ValuesPrefix) CLASS_D_ACCESSOR_DECL(QString, valuesSuffix, ValuesSuffix) CLASS_D_ACCESSOR_DECL(QColor, valuesColor, ValuesColor) CLASS_D_ACCESSOR_DECL(QFont, valuesFont, ValuesFont) BASIC_D_ACCESSOR_DECL(FillingPosition, fillingPosition, FillingPosition) BASIC_D_ACCESSOR_DECL(PlotArea::BackgroundType, fillingType, FillingType) BASIC_D_ACCESSOR_DECL(PlotArea::BackgroundColorStyle, fillingColorStyle, FillingColorStyle) BASIC_D_ACCESSOR_DECL(PlotArea::BackgroundImageStyle, fillingImageStyle, FillingImageStyle) BASIC_D_ACCESSOR_DECL(Qt::BrushStyle, fillingBrushStyle, FillingBrushStyle) CLASS_D_ACCESSOR_DECL(QColor, fillingFirstColor, FillingFirstColor) CLASS_D_ACCESSOR_DECL(QColor, fillingSecondColor, FillingSecondColor) CLASS_D_ACCESSOR_DECL(QString, fillingFileName, FillingFileName) BASIC_D_ACCESSOR_DECL(qreal, fillingOpacity, FillingOpacity) void setVisible(bool on) override; bool isVisible() const override; void setPrinting(bool on) override; void suppressRetransform(bool); double getYMaximum() const; double getYMinimum() const; double getXMaximum() const; double getXMinimum() const; - void setbinsOption(Histogram::BinsOption); + void setBinningMethod(Histogram::BinningMethod); void setBinValue(int); typedef WorksheetElement BaseClass; typedef HistogramPrivate Private; bool isSourceDataChangedSinceLastPlot() const; public slots: void retransform() override; void handleResize(double horizontalRatio, double verticalRatio, bool pageResize) override; private slots: void updateValues(); void xColumnAboutToBeRemoved(const AbstractAspect*); void valuesColumnAboutToBeRemoved(const AbstractAspect*); //SLOTs for changes triggered via QActions in the context menu void visibilityChangedSlot(); void handleSourceDataChanged(); protected: Histogram(const QString& name, HistogramPrivate* dd); HistogramPrivate* const d_ptr; private: Q_DECLARE_PRIVATE(Histogram) void init(); void initActions(); QAction* visibilityAction; signals: //General-Tab void HistogramDataChanged(); void xHistogramDataChanged(); void yHistogramDataChanged(); void visibilityChanged(bool); friend class HistogramSetHistogramTypeCmd; friend class HistogramSetHistogramOrientationCmd; friend class HistogramSetXColumnCmd; friend class HistogramSetYColumnCmd; friend class HistogramSetLinePenCmd; void histogramTypeChanged(Histogram::HistogramType); void histogramOrientationChanged(Histogram::HistogramOrientation); void xColumnChanged(const AbstractColumn*); void yColumnChanged(const AbstractColumn*); //Values-Tab friend class HistogramSetValuesColumnCmd; friend class HistogramSetValuesTypeCmd; friend class HistogramSetValuesPositionCmd; friend class HistogramSetValuesDistanceCmd; friend class HistogramSetValuesRotationAngleCmd; friend class HistogramSetValuesOpacityCmd; friend class HistogramSetValuesPrefixCmd; friend class HistogramSetValuesSuffixCmd; friend class HistogramSetValuesFontCmd; friend class HistogramSetValuesColorCmd; void valuesTypeChanged(Histogram::ValuesType); void valuesColumnChanged(const AbstractColumn*); void valuesPositionChanged(Histogram::ValuesPosition); void valuesDistanceChanged(qreal); void valuesRotationAngleChanged(qreal); void valuesOpacityChanged(qreal); void valuesPrefixChanged(QString); void valuesSuffixChanged(QString); void valuesFontChanged(QFont); void valuesColorChanged(QColor); void linePenChanged(const QPen&); //Filling friend class HistogramSetFillingPositionCmd; friend class HistogramSetFillingTypeCmd; friend class HistogramSetFillingColorStyleCmd; friend class HistogramSetFillingImageStyleCmd; friend class HistogramSetFillingBrushStyleCmd; friend class HistogramSetFillingFirstColorCmd; friend class HistogramSetFillingSecondColorCmd; friend class HistogramSetFillingFileNameCmd; friend class HistogramSetFillingOpacityCmd; void fillingPositionChanged(Histogram::FillingPosition); void fillingTypeChanged(PlotArea::BackgroundType); void fillingColorStyleChanged(PlotArea::BackgroundColorStyle); void fillingImageStyleChanged(PlotArea::BackgroundImageStyle); void fillingBrushStyleChanged(Qt::BrushStyle); void fillingFirstColorChanged(QColor&); void fillingSecondColorChanged(QColor&); void fillingFileNameChanged(QString&); void fillingOpacityChanged(float); friend class HistogramSetDataCmd; void histogramDataChanged(const Histogram::HistogramData&); void sourceDataChangedSinceLastPlot(); }; #endif diff --git a/src/backend/worksheet/plots/cartesian/HistogramPrivate.h b/src/backend/worksheet/plots/cartesian/HistogramPrivate.h index baf6822eb..5790c89ef 100644 --- a/src/backend/worksheet/plots/cartesian/HistogramPrivate.h +++ b/src/backend/worksheet/plots/cartesian/HistogramPrivate.h @@ -1,162 +1,161 @@ /*************************************************************************** File : HistogramPrivate.h Project : LabPlot Description : Private members of Histogram -------------------------------------------------------------------- Copyright : (C) 2016 Anu Mittal (anu22mittal@gmail.com) ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #ifndef HISTOGRAMPRIVATE_H #define HISTOGRAMPRIVATE_H #include #include #include #include extern "C" { #include } class HistogramPrivate : public QGraphicsItem { public: explicit HistogramPrivate(Histogram *owner); QString name() const; QRectF boundingRect() const override; QPainterPath shape() const override; bool m_printing; bool m_hovered; bool m_suppressRecalc; bool m_suppressRetransform; QPixmap m_pixmap; QImage m_hoverEffectImage; QImage m_selectionEffectImage; bool m_hoverEffectImageIsDirty; bool m_selectionEffectImageIsDirty; void retransform(); void updateLines(); void verticalOrdinaryHistogram(); void verticalCumulativeHistogram(); void verticalHistogram(); void horizontalOrdinaryHistogram(); void horizontalCumulativeHistogram(); void horizontalHistogram(); void updateValues(); void updateFilling(); bool swapVisible(bool on); void recalcShapeAndBoundingRect(); void drawSymbols(QPainter*); void drawValues(QPainter*); void drawFilling(QPainter*); void draw(QPainter*); void updatePixmap(); double getYMaximum(); double getYMinimum(); double getXMinimum(); double getXMaximum(); double getMaximumOccuranceofHistogram(); bool autoScaleX, autoScaleY; Histogram::HistogramType histogramType; Histogram::HistogramOrientation histogramOrientation; - Histogram::BinsOption binsOption; + Histogram::BinningMethod binningMethod; void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget* widget = 0) override; //data columns const AbstractColumn* xColumn; QString xColumnPath; - QString yColumnPath; void recalculate(); Histogram::HistogramData histogramData; //line bool lineSkipGaps; int lineInterpolationPointsCount; QPen linePen; qreal lineOpacity; //values int value; Histogram::ValuesType valuesType; const AbstractColumn* valuesColumn; QString valuesColumnPath; Histogram::ValuesPosition valuesPosition; qreal valuesDistance; qreal valuesRotationAngle; qreal valuesOpacity; QString valuesPrefix; QString valuesSuffix; QFont valuesFont; QColor valuesColor; //filling Histogram::FillingPosition fillingPosition; PlotArea::BackgroundType fillingType; PlotArea::BackgroundColorStyle fillingColorStyle; PlotArea::BackgroundImageStyle fillingImageStyle; Qt::BrushStyle fillingBrushStyle; QColor fillingFirstColor; QColor fillingSecondColor; QString fillingFileName; qreal fillingOpacity; QPainterPath linePath; //long long int bins; QPainterPath valuesPath; QRectF boundingRectangle; QPainterPath curveShape; QVector lines; QVector symbolPointsLogical; //points in logical coordinates QVector symbolPointsScene; //points in scene coordinates std::vector visiblePoints; //vector of the size of symbolPointsLogical with true of false for the points currently visible or not in the plot QVector valuesPoints; std::vector connectedPointsLogical; //vector of the size of symbolPointsLogical with true for points connected with the consecutive point and //false otherwise (don't connect because of a gap (NAN) in-between) QVector valuesStrings; QVector fillPolygons; //cached values of minimum and maximum for all visible curves bool curvesXMinMaxIsDirty, curvesYMinMaxIsDirty; double curvesXMin, curvesXMax, curvesYMin, curvesYMax; float xMin, xMax; float xMinPrev, xMaxPrev; bool autoScaleHistogramX; Histogram* const q; bool sourceDataChangedSinceLastPlot; // #include #include #include #include #include #include #include #include #include /*! \class HistogramDock \brief Provides a widget for editing the properties of the Histograms (2D-curves) currently selected in the project explorer. If more than one curves are set, the properties of the first column are shown. The changes of the properties are applied to all curves. The exclusions are the name, the comment and the datasets (columns) of the curves - these properties can only be changed if there is only one single curve. \ingroup kdefrontend */ HistogramDock::HistogramDock(QWidget* parent) : QWidget(parent), cbXColumn(nullptr), m_curve(nullptr), m_aspectTreeModel(nullptr), m_initializing(false) { ui.setupUi(this); // Tab "General" QGridLayout* gridLayout = qobject_cast(ui.tabGeneral->layout()); cbXColumn = new TreeViewComboBox(ui.tabGeneral); gridLayout->addWidget(cbXColumn, 3, 2, 1, 1); //Tab "Values" gridLayout = qobject_cast(ui.tabValues->layout()); cbValuesColumn = new TreeViewComboBox(ui.tabValues); gridLayout->addWidget(cbValuesColumn, 2, 2, 1, 1); //Tab "Filling" ui.cbFillingColorStyle->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon); ui.bFillingOpen->setIcon( QIcon::fromTheme("document-open") ); QCompleter* completer = new QCompleter(this); completer->setModel(new QDirModel); ui.leFillingFileName->setCompleter(completer); //adjust layouts in the tabs for (int i=0; icount(); ++i){ QGridLayout* layout = dynamic_cast(ui.tabWidget->widget(i)->layout()); if (!layout) continue; layout->setContentsMargins(2,2,2,2); layout->setHorizontalSpacing(2); layout->setVerticalSpacing(2); } + ui.leBinWidth->setValidator(new QDoubleValidator(ui.leBinWidth)); + //Slots //General connect(ui.leName, &QLineEdit::textChanged, this, &HistogramDock::nameChanged); connect(ui.leComment, &QLineEdit::textChanged, this, &HistogramDock::commentChanged); connect( ui.chkVisible, SIGNAL(clicked(bool)), this, SLOT(visibilityChanged(bool)) ); connect( cbXColumn, SIGNAL(currentModelIndexChanged(QModelIndex)), this, SLOT(xColumnChanged(QModelIndex)) ); connect( ui.cbHistogramType, SIGNAL(currentIndexChanged(int)), this, SLOT(histogramTypeChanged(int)) ); connect( ui.cbHistogramOrientation, SIGNAL(currentIndexChanged(int)), this, SLOT(histogramOrientationChanged(int))); - connect( ui.cbBins, SIGNAL(currentIndexChanged(int)), this, SLOT(binsOptionChanged(int)) ); - connect( ui.sbBins, SIGNAL(valueChanged(int)), this, SLOT(binValueChanged(int)) ); + connect( ui.cbBinningMethod, SIGNAL(currentIndexChanged(int)), this, SLOT(binningMethodChanged(int)) ); + connect( ui.sbBinCount, SIGNAL(valueChanged(int)), this, SLOT(binValueChanged(int)) ); //Line connect( ui.kcbLineColor, SIGNAL(changed(QColor)), this, SLOT(lineColorChanged(QColor)) ); //Values connect( ui.cbValuesType, SIGNAL(currentIndexChanged(int)), this, SLOT(valuesTypeChanged(int)) ); connect( cbValuesColumn, SIGNAL(currentModelIndexChanged(QModelIndex)), this, SLOT(valuesColumnChanged(QModelIndex)) ); connect( ui.cbValuesPosition, SIGNAL(currentIndexChanged(int)), this, SLOT(valuesPositionChanged(int)) ); connect( ui.sbValuesDistance, SIGNAL(valueChanged(double)), this, SLOT(valuesDistanceChanged(double)) ); connect( ui.sbValuesRotation, SIGNAL(valueChanged(int)), this, SLOT(valuesRotationChanged(int)) ); connect( ui.sbValuesOpacity, SIGNAL(valueChanged(int)), this, SLOT(valuesOpacityChanged(int)) ); //TODO connect( ui.cbValuesFormat, SIGNAL(currentIndexChanged(int)), this, SLOT(valuesColumnFormatChanged(int)) ); connect( ui.leValuesPrefix, SIGNAL(returnPressed()), this, SLOT(valuesPrefixChanged()) ); connect( ui.leValuesSuffix, SIGNAL(returnPressed()), this, SLOT(valuesSuffixChanged()) ); connect( ui.kfrValuesFont, SIGNAL(fontSelected(QFont)), this, SLOT(valuesFontChanged(QFont)) ); connect( ui.kcbValuesColor, SIGNAL(changed(QColor)), this, SLOT(valuesColorChanged(QColor)) ); //Filling connect( ui.cbFillingPosition, SIGNAL(currentIndexChanged(int)), this, SLOT(fillingPositionChanged(int)) ); connect( ui.cbFillingType, SIGNAL(currentIndexChanged(int)), this, SLOT(fillingTypeChanged(int)) ); connect( ui.cbFillingColorStyle, SIGNAL(currentIndexChanged(int)), this, SLOT(fillingColorStyleChanged(int)) ); connect( ui.cbFillingImageStyle, SIGNAL(currentIndexChanged(int)), this, SLOT(fillingImageStyleChanged(int)) ); connect( ui.cbFillingBrushStyle, SIGNAL(currentIndexChanged(int)), this, SLOT(fillingBrushStyleChanged(int)) ); connect( ui.bFillingOpen, SIGNAL(clicked(bool)), this, SLOT(selectFile())); connect( ui.leFillingFileName, SIGNAL(returnPressed()), this, SLOT(fileNameChanged()) ); connect( ui.leFillingFileName, SIGNAL(textChanged(QString)), this, SLOT(fileNameChanged()) ); connect( ui.kcbFillingFirstColor, SIGNAL(changed(QColor)), this, SLOT(fillingFirstColorChanged(QColor)) ); connect( ui.kcbFillingSecondColor, SIGNAL(changed(QColor)), this, SLOT(fillingSecondColorChanged(QColor)) ); connect( ui.sbFillingOpacity, SIGNAL(valueChanged(int)), this, SLOT(fillingOpacityChanged(int)) ); //template handler TemplateHandler* templateHandler = new TemplateHandler(this, TemplateHandler::Histogram); ui.verticalLayout->addWidget(templateHandler); templateHandler->show(); connect(templateHandler, SIGNAL(loadConfigRequested(KConfig&)), this, SLOT(loadConfigFromTemplate(KConfig&))); connect(templateHandler, SIGNAL(saveConfigRequested(KConfig&)), this, SLOT(saveConfigAsTemplate(KConfig&))); connect(templateHandler, SIGNAL(info(QString)), this, SIGNAL(info(QString))); retranslateUi(); init(); } HistogramDock::~HistogramDock() { if (m_aspectTreeModel) delete m_aspectTreeModel; } //TODO: very similiar to ColumnDock void HistogramDock::updateValuesFormatWidgets(const AbstractColumn::ColumnMode columnMode) { ui.cbValuesFormat->clear(); switch (columnMode) { case AbstractColumn::Numeric: ui.cbValuesFormat->addItem(i18n("Decimal"), QVariant('f')); ui.cbValuesFormat->addItem(i18n("Scientific (e)"), QVariant('e')); ui.cbValuesFormat->addItem(i18n("Scientific (E)"), QVariant('E')); ui.cbValuesFormat->addItem(i18n("Automatic (e)"), QVariant('g')); ui.cbValuesFormat->addItem(i18n("Automatic (E)"), QVariant('G')); break; case AbstractColumn::Integer: break; case AbstractColumn::Text: ui.cbValuesFormat->addItem(i18n("Text"), QVariant()); break; case AbstractColumn::Month: ui.cbValuesFormat->addItem(i18n("Number without Leading Zero"), QVariant("M")); ui.cbValuesFormat->addItem(i18n("Number with Leading Zero"), QVariant("MM")); ui.cbValuesFormat->addItem(i18n("Abbreviated Month Name"), QVariant("MMM")); ui.cbValuesFormat->addItem(i18n("Full Month Name"), QVariant("MMMM")); break; case AbstractColumn::Day: ui.cbValuesFormat->addItem(i18n("Number without Leading Zero"), QVariant("d")); ui.cbValuesFormat->addItem(i18n("Number with Leading Zero"), QVariant("dd")); ui.cbValuesFormat->addItem(i18n("Abbreviated Day Name"), QVariant("ddd")); ui.cbValuesFormat->addItem(i18n("Full Day Name"), QVariant("dddd")); break; case AbstractColumn::DateTime: for (const auto& s: AbstractColumn::dateFormats()) ui.cbValuesFormat->addItem(s, QVariant(s)); for (const auto& s: AbstractColumn::timeFormats()) ui.cbValuesFormat->addItem(s, QVariant(s)); for (const auto& s1: AbstractColumn::dateFormats()) for (const auto& s2: AbstractColumn::timeFormats()) ui.cbValuesFormat->addItem(s1 + ' ' + s2, QVariant(s1 + ' ' + s2)); break; } ui.cbValuesFormat->setCurrentIndex(0); if (columnMode == AbstractColumn::Numeric) { ui.lValuesPrecision->show(); ui.sbValuesPrecision->show(); } else { ui.lValuesPrecision->hide(); ui.sbValuesPrecision->hide(); } if (columnMode == AbstractColumn::Text) { ui.lValuesFormatTop->hide(); ui.lValuesFormat->hide(); ui.cbValuesFormat->hide(); } else { ui.lValuesFormatTop->show(); ui.lValuesFormat->show(); ui.cbValuesFormat->show(); ui.cbValuesFormat->setCurrentIndex(0); } if (columnMode == AbstractColumn::DateTime) { ui.cbValuesFormat->setEditable(true); } else { ui.cbValuesFormat->setEditable(false); } } //TODO: very similiar to ColumnDock void HistogramDock::showValuesColumnFormat(const Column* column){ if (!column){ // no valid column is available // -> hide all the format properties widgets (equivalent to showing the properties of the column mode "Text") this->updateValuesFormatWidgets(AbstractColumn::Text); }else{ AbstractColumn::ColumnMode columnMode = column->columnMode(); //update the format widgets for the new column mode this->updateValuesFormatWidgets(columnMode); //show the actuall formating properties switch(columnMode) { case AbstractColumn::Numeric:{ Double2StringFilter * filter = static_cast(column->outputFilter()); ui.cbValuesFormat->setCurrentIndex(ui.cbValuesFormat->findData(filter->numericFormat())); ui.sbValuesPrecision->setValue(filter->numDigits()); break; } case AbstractColumn::Text: case AbstractColumn::Integer: break; case AbstractColumn::Month: case AbstractColumn::Day: case AbstractColumn::DateTime: { DateTime2StringFilter * filter = static_cast(column->outputFilter()); ui.cbValuesFormat->setCurrentIndex(ui.cbValuesFormat->findData(filter->format())); break; } } } } void HistogramDock::setModelIndexFromColumn(TreeViewComboBox* cb, const AbstractColumn* column) { if (column) cb->setCurrentModelIndex(m_aspectTreeModel->modelIndexOfAspect(column)); else cb->setCurrentModelIndex(QModelIndex()); } void HistogramDock::retranslateUi() { //TODO: // ui.lName->setText(i18n("Name")); // ui.lComment->setText(i18n("Comment")); // ui.chkVisible->setText(i18n("Visible")); // ui.lXColumn->setText(i18n("x-data")); // ui.lYColumn->setText(i18n("y-data")); //TODO updatePenStyles, updateBrushStyles for all comboboxes } // "General"-tab void HistogramDock::nameChanged() { if (m_initializing) return; m_curve->setName(ui.leName->text()); } void HistogramDock::commentChanged() { if (m_initializing) return; m_curve->setComment(ui.leComment->text()); } void HistogramDock::visibilityChanged(bool state){ if (m_initializing) return; for (auto* curve: m_curvesList) curve->setVisible(state); } void HistogramDock::valuesColorChanged(const QColor& color){ if (m_initializing) return; for (auto* curve: m_curvesList) curve->setValuesColor(color); } void HistogramDock::init(){ //General //bins option - ui.cbBins->addItem(i18n("By Number")); - ui.cbBins->addItem(i18n("By width")); - ui.cbBins->addItem(i18n("Square-root rule")); - ui.cbBins->addItem(i18n("Rice rule")); - ui.cbBins->addItem(i18n("Sturgis rule")); + ui.cbBinningMethod->addItem(i18n("By Number")); + ui.cbBinningMethod->addItem(i18n("By Width")); + ui.cbBinningMethod->addItem(i18n("Square-root Rule")); + ui.cbBinningMethod->addItem(i18n("Rice Rule")); + ui.cbBinningMethod->addItem(i18n("Sturgis Rule")); //histogram type ui.cbHistogramType->addItem(i18n("Ordinary Histogram")); ui.cbHistogramType->addItem(i18n("Cumulative Histogram")); ui.cbHistogramType->addItem(i18n("AvgShifted Histogram")); //Orientation ui.cbHistogramOrientation->addItem(i18n("Vertical")); ui.cbHistogramOrientation->addItem(i18n("Horizontal")); //Line GuiTools::updatePenStyles(ui.cbLineStyle, Qt::black); //Drop lines ui.cbDropLineType->addItem(i18n("No Drop Lines")); ui.cbDropLineType->addItem(i18n("Drop Lines, X")); ui.cbDropLineType->addItem(i18n("Drop Lines, Y")); ui.cbDropLineType->addItem(i18n("Drop Lines, XY")); ui.cbDropLineType->addItem(i18n("Drop Lines, X, Zero Baseline")); ui.cbDropLineType->addItem(i18n("Drop Lines, X, Min Baseline")); ui.cbDropLineType->addItem(i18n("Drop Lines, X, Max Baseline")); GuiTools::updatePenStyles(ui.cbDropLineStyle, Qt::black); //Symbols GuiTools::updatePenStyles(ui.cbSymbolBorderStyle, Qt::black); QPainter pa; //TODO size of the icon depending on the actuall height of the combobox? int iconSize = 20; QPixmap pm(iconSize, iconSize); ui.cbSymbolStyle->setIconSize(QSize(iconSize, iconSize)); QTransform trafo; trafo.scale(15, 15); QPen pen(Qt::SolidPattern, 0); const QColor& color = (palette().color(QPalette::Base).lightness() < 128) ? Qt::white : Qt::black; pen.setColor(color); pa.setPen( pen ); ui.cbSymbolStyle->addItem(i18n("None")); for (int i = 1; i < 19; ++i) { //TODO: use enum count Symbol::Style style = (Symbol::Style)i; pm.fill(Qt::transparent); pa.begin(&pm); pa.setPen(pen); pa.setRenderHint(QPainter::Antialiasing); pa.translate(iconSize/2,iconSize/2); pa.drawPath(trafo.map(Symbol::pathFromStyle(style))); pa.end(); ui.cbSymbolStyle->addItem(QIcon(pm), Symbol::nameFromStyle(style)); } GuiTools::updateBrushStyles(ui.cbSymbolFillingStyle, Qt::black); m_initializing = false; //Values ui.cbValuesType->addItem(i18n("No Values")); ui.cbValuesType->addItem("y"); ui.cbValuesType->addItem(i18n("Custom Column")); ui.cbValuesPosition->addItem(i18n("Above")); ui.cbValuesPosition->addItem(i18n("Below")); ui.cbValuesPosition->addItem(i18n("Left")); ui.cbValuesPosition->addItem(i18n("Right")); //Filling ui.cbFillingPosition->clear(); ui.cbFillingPosition->addItem(i18n("None")); ui.cbFillingPosition->addItem(i18n("Above")); ui.cbFillingPosition->addItem(i18n("Below")); ui.cbFillingPosition->addItem(i18n("Zero Baseline")); ui.cbFillingPosition->addItem(i18n("Left")); ui.cbFillingPosition->addItem(i18n("Right")); ui.cbFillingType->clear(); ui.cbFillingType->addItem(i18n("Color")); ui.cbFillingType->addItem(i18n("Image")); ui.cbFillingType->addItem(i18n("Pattern")); ui.cbFillingColorStyle->clear(); ui.cbFillingColorStyle->addItem(i18n("Single Color")); ui.cbFillingColorStyle->addItem(i18n("Horizontal Linear Gradient")); ui.cbFillingColorStyle->addItem(i18n("Vertical Linear Gradient")); ui.cbFillingColorStyle->addItem(i18n("Diagonal Linear Gradient (Start From Top Left)")); ui.cbFillingColorStyle->addItem(i18n("Diagonal Linear Gradient (Start From Bottom Left)")); ui.cbFillingColorStyle->addItem(i18n("Radial Gradient")); ui.cbFillingImageStyle->clear(); ui.cbFillingImageStyle->addItem(i18n("Scaled and Cropped")); ui.cbFillingImageStyle->addItem(i18n("Scaled")); ui.cbFillingImageStyle->addItem(i18n("Scaled, Keep Proportions")); ui.cbFillingImageStyle->addItem(i18n("Centered")); ui.cbFillingImageStyle->addItem(i18n("Tiled")); ui.cbFillingImageStyle->addItem(i18n("Center Tiled")); GuiTools::updateBrushStyles(ui.cbFillingBrushStyle, Qt::SolidPattern); //Error-bars pm.fill(Qt::transparent); pa.begin( &pm ); pa.setRenderHint(QPainter::Antialiasing); pa.drawLine(3,10,17,10);//vert. line pa.drawLine(10,3,10,17);//hor. line pa.end(); ui.cbErrorBarsType->addItem(i18n("Bars")); ui.cbErrorBarsType->setItemIcon(0, pm); pm.fill(Qt::transparent); pa.begin( &pm ); pa.setRenderHint(QPainter::Antialiasing); pa.setBrush(Qt::SolidPattern); pa.drawLine(3,10,17,10); //vert. line pa.drawLine(10,3,10,17); //hor. line pa.drawLine(7,3,13,3); //upper cap pa.drawLine(7,17,13,17); //bottom cap pa.drawLine(3,7,3,13); //left cap pa.drawLine(17,7,17,13); //right cap pa.end(); ui.cbErrorBarsType->addItem(i18n("Bars with Ends")); ui.cbErrorBarsType->setItemIcon(1, pm); GuiTools::updatePenStyles(ui.cbErrorBarsStyle, Qt::black); } void HistogramDock::setModel() { QList list; list<<"Folder"<<"Workbook"<<"Datapicker"<<"DatapickerCurve"<<"Spreadsheet" <<"FileDataSource"<<"Column"<<"Worksheet"<<"CartesianPlot"<< "Histogram" <<"XYInterpolationCurve"<<"XYFitCurve"<<"XYFourierFilterCurve"; if (cbXColumn) { cbXColumn->setTopLevelClasses(list); } cbValuesColumn->setTopLevelClasses(list); list.clear(); list<<"Column"; m_aspectTreeModel->setSelectableAspects(list); if (cbXColumn) cbXColumn->setModel(m_aspectTreeModel); cbValuesColumn->setModel(m_aspectTreeModel); } void HistogramDock::setCurves(QList list){ m_initializing = true; m_curvesList = list; m_curve = list.first(); Q_ASSERT(m_curve); m_aspectTreeModel = new AspectTreeModel(m_curve->project()); setModel(); //if there are more then one curve in the list, disable the content in the tab "general" if (m_curvesList.size()==1){ ui.lName->setEnabled(true); ui.leName->setEnabled(true); ui.lComment->setEnabled(true); ui.leComment->setEnabled(true); ui.lXColumn->setEnabled(true); cbXColumn->setEnabled(true); this->setModelIndexFromColumn(cbXColumn, m_curve->xColumn()); this->setModelIndexFromColumn(cbValuesColumn, m_curve->valuesColumn()); ui.leName->setText(m_curve->name()); ui.leComment->setText(m_curve->comment()); }else { ui.lName->setEnabled(false); ui.leName->setEnabled(false); ui.lComment->setEnabled(false); ui.leComment->setEnabled(false); ui.lXColumn->setEnabled(false); cbXColumn->setEnabled(false); cbXColumn->setCurrentModelIndex(QModelIndex()); cbValuesColumn->setCurrentModelIndex(QModelIndex()); ui.leName->setText(""); ui.leComment->setText(""); } //show the properties of the first curve const Histogram::HistogramData& data = m_curve->histogramData(); ui.cbHistogramType->setCurrentIndex(data.type); - ui.cbBins->setCurrentIndex(data.binsOption); + ui.cbBinningMethod->setCurrentIndex(data.binningMethod); ui.chkVisible->setChecked( m_curve->isVisible() ); KConfig config("", KConfig::SimpleConfig); loadConfig(config); //Slots //General-tab connect(m_curve, SIGNAL(aspectDescriptionChanged(const AbstractAspect*)), this, SLOT(curveDescriptionChanged(const AbstractAspect*))); connect(m_curve, SIGNAL(histogramDataChanged(Histogram::HistogramData)), this, SLOT(curveHistogramDataChanged(Histogram::HistogramData))); connect(m_curve, SIGNAL(visibilityChanged(bool)), this, SLOT(curveVisibilityChanged(bool))); //Line-tab connect(m_curve, SIGNAL(linePenChanged(QPen)), this, SLOT(curveLinePenChanged(QPen))); //Values-Tab connect(m_curve, SIGNAL(valuesTypeChanged(Histogram::ValuesType)), this, SLOT(curveValuesTypeChanged(Histogram::ValuesType))); connect(m_curve, SIGNAL(valuesColumnChanged(const AbstractColumn*)), this, SLOT(curveValuesColumnChanged(const AbstractColumn*))); connect(m_curve, SIGNAL(valuesPositionChanged(Histogram::ValuesPosition)), this, SLOT(curveValuesPositionChanged(Histogram::ValuesPosition))); connect(m_curve, SIGNAL(valuesDistanceChanged(qreal)), this, SLOT(curveValuesDistanceChanged(qreal))); connect(m_curve, SIGNAL(valuesOpacityChanged(qreal)), this, SLOT(curveValuesOpacityChanged(qreal))); connect(m_curve, SIGNAL(valuesRotationAngleChanged(qreal)), this, SLOT(curveValuesRotationAngleChanged(qreal))); connect(m_curve, SIGNAL(valuesPrefixChanged(QString)), this, SLOT(curveValuesPrefixChanged(QString))); connect(m_curve, SIGNAL(valuesSuffixChanged(QString)), this, SLOT(curveValuesSuffixChanged(QString))); connect(m_curve, SIGNAL(valuesFontChanged(QFont)), this, SLOT(curveValuesFontChanged(QFont))); connect(m_curve, SIGNAL(valuesColorChanged(QColor)), this, SLOT(curveValuesColorChanged(QColor))); //Filling-Tab connect( m_curve, SIGNAL(fillingPositionChanged(Histogram::FillingPosition)), this, SLOT(curveFillingPositionChanged(Histogram::FillingPosition)) ); connect( m_curve, SIGNAL(fillingTypeChanged(PlotArea::BackgroundType)), this, SLOT(curveFillingTypeChanged(PlotArea::BackgroundType)) ); connect( m_curve, SIGNAL(fillingColorStyleChanged(PlotArea::BackgroundColorStyle)), this, SLOT(curveFillingColorStyleChanged(PlotArea::BackgroundColorStyle)) ); connect( m_curve, SIGNAL(fillingImageStyleChanged(PlotArea::BackgroundImageStyle)), this, SLOT(curveFillingImageStyleChanged(PlotArea::BackgroundImageStyle)) ); connect( m_curve, SIGNAL(fillingBrushStyleChanged(Qt::BrushStyle)), this, SLOT(curveFillingBrushStyleChanged(Qt::BrushStyle)) ); connect( m_curve, SIGNAL(fillingFirstColorChanged(QColor&)), this, SLOT(curveFillingFirstColorChanged(QColor&)) ); connect( m_curve, SIGNAL(fillingSecondColorChanged(QColor&)), this, SLOT(curveFillingSecondColorChanged(QColor&)) ); connect( m_curve, SIGNAL(fillingFileNameChanged(QString&)), this, SLOT(curveFillingFileNameChanged(QString&)) ); connect( m_curve, SIGNAL(fillingOpacityChanged(float)), this, SLOT(curveFillingOpacityChanged(float)) ); m_initializing=false; } //************************************************************* //**** SLOTs for changes triggered in HistogramDock ***** //************************************************************* void HistogramDock::curveLinePenChanged(const QPen& pen) { m_initializing = true; ui.kcbLineColor->setColor( pen.color()); m_initializing = false; } //Values-Tab void HistogramDock::curveValuesTypeChanged(Histogram::ValuesType type) { m_initializing = true; ui.cbValuesType->setCurrentIndex((int) type); m_initializing = false; } void HistogramDock::curveValuesColumnChanged(const AbstractColumn* column) { m_initializing = true; this->setModelIndexFromColumn(cbValuesColumn, column); m_initializing = false; } void HistogramDock::curveValuesPositionChanged(Histogram::ValuesPosition position) { m_initializing = true; ui.cbValuesPosition->setCurrentIndex((int) position); m_initializing = false; } void HistogramDock::curveValuesDistanceChanged(qreal distance) { m_initializing = true; ui.sbValuesDistance->setValue( Worksheet::convertFromSceneUnits(distance, Worksheet::Point) ); m_initializing = false; } void HistogramDock::curveValuesRotationAngleChanged(qreal angle) { m_initializing = true; ui.sbValuesRotation->setValue(angle); m_initializing = false; } void HistogramDock::curveValuesOpacityChanged(qreal opacity) { m_initializing = true; ui.sbValuesOpacity->setValue( round(opacity*100.0) ); m_initializing = false; } void HistogramDock::curveValuesPrefixChanged(const QString& prefix) { m_initializing = true; ui.leValuesPrefix->setText(prefix); m_initializing = false; } void HistogramDock::curveValuesSuffixChanged(const QString& suffix) { m_initializing = true; ui.leValuesSuffix->setText(suffix); m_initializing = false; } void HistogramDock::curveValuesFontChanged(QFont font) { m_initializing = true; font.setPointSizeF( round(Worksheet::convertFromSceneUnits(font.pixelSize(), Worksheet::Point)) ); ui.kfrValuesFont->setFont(font); m_initializing = false; } void HistogramDock::curveValuesColorChanged(QColor color) { m_initializing = true; ui.kcbValuesColor->setColor(color); m_initializing = false; } /*! called when the type of the values (none, x, y, (x,y) etc.) was changed. */ void HistogramDock::valuesTypeChanged(int index) { Histogram::ValuesType valuesType = Histogram::ValuesType(index); if (valuesType == Histogram::NoValues){ //no values are to paint -> deactivate all the pertinent widgets ui.cbValuesPosition->setEnabled(false); ui.lValuesColumn->hide(); cbValuesColumn->hide(); ui.sbValuesDistance->setEnabled(false); ui.sbValuesRotation->setEnabled(false); ui.sbValuesOpacity->setEnabled(false); ui.cbValuesFormat->setEnabled(false); ui.cbValuesFormat->setEnabled(false); ui.sbValuesPrecision->setEnabled(false); ui.leValuesPrefix->setEnabled(false); ui.leValuesSuffix->setEnabled(false); ui.kfrValuesFont->setEnabled(false); ui.kcbValuesColor->setEnabled(false); } else { ui.cbValuesPosition->setEnabled(true); ui.sbValuesDistance->setEnabled(true); ui.sbValuesRotation->setEnabled(true); ui.sbValuesOpacity->setEnabled(true); ui.cbValuesFormat->setEnabled(true); ui.sbValuesPrecision->setEnabled(true); ui.leValuesPrefix->setEnabled(true); ui.leValuesSuffix->setEnabled(true); ui.kfrValuesFont->setEnabled(true); ui.kcbValuesColor->setEnabled(true); const Column* column; if (valuesType == Histogram::ValuesCustomColumn) { ui.lValuesColumn->show(); cbValuesColumn->show(); column= static_cast(cbValuesColumn->currentModelIndex().internalPointer()); } else { ui.lValuesColumn->hide(); cbValuesColumn->hide(); column = static_cast(m_curve->xColumn()); } this->showValuesColumnFormat(column); } if (m_initializing) return; for (auto* curve: m_curvesList) curve->setValuesType(valuesType); } /*! called when the custom column for the values was changed. */ void HistogramDock::valuesColumnChanged(const QModelIndex& index){ if (m_initializing) return; Column* column = static_cast(index.internalPointer()); this->showValuesColumnFormat(column); for (auto* curve: m_curvesList) { //TODO save also the format of the currently selected column for the values (precision etc.) curve->setValuesColumn(column); } } void HistogramDock::curveVisibilityChanged(bool on) { m_initializing = true; ui.chkVisible->setChecked(on); m_initializing = false; } void HistogramDock::valuesPositionChanged(int index){ if (m_initializing) return; for (auto* curve : m_curvesList) curve->setValuesPosition(Histogram::ValuesPosition(index)); } void HistogramDock::valuesDistanceChanged(double value){ if (m_initializing) return; for (auto* curve: m_curvesList) curve->setValuesDistance( Worksheet::convertToSceneUnits(value, Worksheet::Point) ); } void HistogramDock::valuesRotationChanged(int value){ if (m_initializing) return; for (auto* curve: m_curvesList) curve->setValuesRotationAngle(value); } void HistogramDock::valuesOpacityChanged(int value){ if (m_initializing) return; qreal opacity = (float)value/100.; for (auto* curve: m_curvesList) curve->setValuesOpacity(opacity); } void HistogramDock::valuesPrefixChanged(){ if (m_initializing) return; QString prefix = ui.leValuesPrefix->text(); for (auto* curve: m_curvesList) curve->setValuesPrefix(prefix); } void HistogramDock::valuesSuffixChanged(){ if (m_initializing) return; QString suffix = ui.leValuesSuffix->text(); for (auto* curve: m_curvesList) curve->setValuesSuffix(suffix); } void HistogramDock::valuesFontChanged(const QFont& font){ if (m_initializing) return; QFont valuesFont = font; valuesFont.setPixelSize( Worksheet::convertToSceneUnits(font.pointSizeF(), Worksheet::Point) ); for (auto* curve: m_curvesList) curve->setValuesFont(valuesFont); } //Filling void HistogramDock::curveFillingPositionChanged(Histogram::FillingPosition position) { m_initializing = true; ui.cbFillingPosition->setCurrentIndex((int)position); m_initializing = false; } void HistogramDock::curveFillingTypeChanged(PlotArea::BackgroundType type){ m_initializing = true; ui.cbFillingType->setCurrentIndex(type); m_initializing = false; } void HistogramDock::curveFillingColorStyleChanged(PlotArea::BackgroundColorStyle style){ m_initializing = true; ui.cbFillingColorStyle->setCurrentIndex(style); m_initializing = false; } void HistogramDock::curveFillingImageStyleChanged(PlotArea::BackgroundImageStyle style){ m_initializing = true; ui.cbFillingImageStyle->setCurrentIndex(style); m_initializing = false; } void HistogramDock::curveFillingBrushStyleChanged(Qt::BrushStyle style){ m_initializing = true; ui.cbFillingBrushStyle->setCurrentIndex(style); m_initializing = false; } void HistogramDock::curveFillingFirstColorChanged(QColor& color){ m_initializing = true; ui.kcbFillingFirstColor->setColor(color); m_initializing = false; } void HistogramDock::curveFillingSecondColorChanged(QColor& color){ m_initializing = true; ui.kcbFillingSecondColor->setColor(color); m_initializing = false; } void HistogramDock::curveFillingFileNameChanged(QString& filename){ m_initializing = true; ui.leFillingFileName->setText(filename); m_initializing = false; } void HistogramDock::curveFillingOpacityChanged(float opacity){ m_initializing = true; ui.sbFillingOpacity->setValue( round(opacity*100.0) ); m_initializing = false; } //Filling-tab void HistogramDock::fillingPositionChanged(int index){ Histogram::FillingPosition fillingPosition = Histogram::FillingPosition(index); bool b = (fillingPosition != Histogram::NoFilling); ui.cbFillingType->setEnabled(b); ui.cbFillingColorStyle->setEnabled(b); ui.cbFillingBrushStyle->setEnabled(b); ui.cbFillingImageStyle->setEnabled(b); ui.kcbFillingFirstColor->setEnabled(b); ui.kcbFillingSecondColor->setEnabled(b); ui.leFillingFileName->setEnabled(b); ui.bFillingOpen->setEnabled(b); ui.sbFillingOpacity->setEnabled(b); if (m_initializing) return; for (auto* curve: m_curvesList) curve->setFillingPosition(fillingPosition); } void HistogramDock::fillingTypeChanged(int index){ PlotArea::BackgroundType type = (PlotArea::BackgroundType)index; if (type == PlotArea::Color){ ui.lFillingColorStyle->show(); ui.cbFillingColorStyle->show(); ui.lFillingImageStyle->hide(); ui.cbFillingImageStyle->hide(); ui.lFillingBrushStyle->hide(); ui.cbFillingBrushStyle->hide(); ui.lFillingFileName->hide(); ui.leFillingFileName->hide(); ui.bFillingOpen->hide(); ui.lFillingFirstColor->show(); ui.kcbFillingFirstColor->show(); PlotArea::BackgroundColorStyle style = (PlotArea::BackgroundColorStyle) ui.cbFillingColorStyle->currentIndex(); if (style == PlotArea::SingleColor){ ui.lFillingFirstColor->setText(i18n("Color:")); ui.lFillingSecondColor->hide(); ui.kcbFillingSecondColor->hide(); }else{ ui.lFillingFirstColor->setText(i18n("First color:")); ui.lFillingSecondColor->show(); ui.kcbFillingSecondColor->show(); } }else if(type == PlotArea::Image){ ui.lFillingColorStyle->hide(); ui.cbFillingColorStyle->hide(); ui.lFillingImageStyle->show(); ui.cbFillingImageStyle->show(); ui.lFillingBrushStyle->hide(); ui.cbFillingBrushStyle->hide(); ui.lFillingFileName->show(); ui.leFillingFileName->show(); ui.bFillingOpen->show(); ui.lFillingFirstColor->hide(); ui.kcbFillingFirstColor->hide(); ui.lFillingSecondColor->hide(); ui.kcbFillingSecondColor->hide(); }else if(type == PlotArea::Pattern) { ui.lFillingFirstColor->setText(i18n("Color:")); ui.lFillingColorStyle->hide(); ui.cbFillingColorStyle->hide(); ui.lFillingImageStyle->hide(); ui.cbFillingImageStyle->hide(); ui.lFillingBrushStyle->show(); ui.cbFillingBrushStyle->show(); ui.lFillingFileName->hide(); ui.leFillingFileName->hide(); ui.bFillingOpen->hide(); ui.lFillingFirstColor->show(); ui.kcbFillingFirstColor->show(); ui.lFillingSecondColor->hide(); ui.kcbFillingSecondColor->hide(); } if (m_initializing) return; for (auto* curve: m_curvesList) curve->setFillingType(type); } void HistogramDock::fillingColorStyleChanged(int index){ PlotArea::BackgroundColorStyle style = (PlotArea::BackgroundColorStyle)index; if (style == PlotArea::SingleColor){ ui.lFillingFirstColor->setText(i18n("Color:")); ui.lFillingSecondColor->hide(); ui.kcbFillingSecondColor->hide(); } else { ui.lFillingFirstColor->setText(i18n("First color:")); ui.lFillingSecondColor->show(); ui.kcbFillingSecondColor->show(); ui.lFillingBrushStyle->hide(); ui.cbFillingBrushStyle->hide(); } if (m_initializing) return; for (auto* curve: m_curvesList) curve->setFillingColorStyle(style); } void HistogramDock::fillingImageStyleChanged(int index){ if (m_initializing) return; PlotArea::BackgroundImageStyle style = (PlotArea::BackgroundImageStyle)index; for (auto* curve: m_curvesList) curve->setFillingImageStyle(style); } void HistogramDock::fillingBrushStyleChanged(int index){ if (m_initializing) return; Qt::BrushStyle style = (Qt::BrushStyle)index; for (auto* curve: m_curvesList) curve->setFillingBrushStyle(style); } void HistogramDock::fillingFirstColorChanged(const QColor& c){ if (m_initializing) return; for (auto* curve: m_curvesList) curve->setFillingFirstColor(c); } void HistogramDock::fillingSecondColorChanged(const QColor& c){ if (m_initializing) return; for (auto* curve: m_curvesList) curve->setFillingSecondColor(c); } /*! opens a file dialog and lets the user select the image file. */ void HistogramDock::selectFile() { KConfigGroup conf(KSharedConfig::openConfig(), "HistogramDock"); QString dir = conf.readEntry("LastImageDir", ""); QString formats; for (const QByteArray& format : QImageReader::supportedImageFormats()) { QString f = "*." + QString(format.constData()); formats.isEmpty() ? formats+=f : formats+=' '+f; } QString path = QFileDialog::getOpenFileName(this, i18n("Select the image file"), dir, i18n("Images (%1)", formats)); if (path.isEmpty()) return; //cancel was clicked in the file-dialog int pos = path.lastIndexOf(QDir::separator()); if (pos != -1) { QString newDir = path.left(pos); if (newDir!=dir) conf.writeEntry("LastImageDir", newDir); } ui.leFillingFileName->setText( path ); for (auto* curve: m_curvesList) curve->setFillingFileName(path); } void HistogramDock::fileNameChanged(){ if (m_initializing) return; QString fileName = ui.leFillingFileName->text(); for (auto* curve: m_curvesList) curve->setFillingFileName(fileName); } void HistogramDock::fillingOpacityChanged(int value){ if (m_initializing) return; qreal opacity = (float)value/100.; for (auto* curve: m_curvesList) curve->setFillingOpacity(opacity); } void HistogramDock::loadConfig(KConfig& config) { KConfigGroup group = config.group(QLatin1String("Histogram")); //General //we don't load/save the settings in the general-tab, since they are not style related. //It doesn't make sense to load/save them in the template. //This data is read in HistogramDock::setCurves(). //Values ui.cbValuesType->setCurrentIndex( group.readEntry("ValuesType", (int) m_curve->valuesType()) ); ui.cbValuesPosition->setCurrentIndex( group.readEntry("ValuesPosition", (int) m_curve->valuesPosition()) ); ui.sbValuesDistance->setValue( Worksheet::convertFromSceneUnits(group.readEntry("ValuesDistance", m_curve->valuesDistance()), Worksheet::Point) ); ui.sbValuesRotation->setValue( group.readEntry("ValuesRotation", m_curve->valuesRotationAngle()) ); ui.sbValuesOpacity->setValue( round(group.readEntry("ValuesOpacity",m_curve->valuesOpacity())*100.0) ); ui.leValuesPrefix->setText( group.readEntry("ValuesPrefix", m_curve->valuesPrefix()) ); ui.leValuesSuffix->setText( group.readEntry("ValuesSuffix", m_curve->valuesSuffix()) ); QFont valuesFont = m_curve->valuesFont(); valuesFont.setPointSizeF( round(Worksheet::convertFromSceneUnits(valuesFont.pixelSize(), Worksheet::Point)) ); ui.kfrValuesFont->setFont( group.readEntry("ValuesFont", valuesFont) ); ui.kcbValuesColor->setColor( group.readEntry("ValuesColor", m_curve->valuesColor()) ); //Filling ui.cbFillingPosition->setCurrentIndex( group.readEntry("FillingPosition", (int) m_curve->fillingPosition()) ); ui.cbFillingType->setCurrentIndex( group.readEntry("FillingType", (int) m_curve->fillingType()) ); ui.cbFillingColorStyle->setCurrentIndex( group.readEntry("FillingColorStyle", (int) m_curve->fillingColorStyle()) ); ui.cbFillingImageStyle->setCurrentIndex( group.readEntry("FillingImageStyle", (int) m_curve->fillingImageStyle()) ); ui.cbFillingBrushStyle->setCurrentIndex( group.readEntry("FillingBrushStyle", (int) m_curve->fillingBrushStyle()) ); ui.leFillingFileName->setText( group.readEntry("FillingFileName", m_curve->fillingFileName()) ); ui.kcbFillingFirstColor->setColor( group.readEntry("FillingFirstColor", m_curve->fillingFirstColor()) ); ui.kcbFillingSecondColor->setColor( group.readEntry("FillingSecondColor", m_curve->fillingSecondColor()) ); ui.sbFillingOpacity->setValue( round(group.readEntry("FillingOpacity", m_curve->fillingOpacity())*100.0) ); } void HistogramDock::histogramTypeChanged(int index) { if (m_initializing) return; Histogram::HistogramType histogramType = Histogram::HistogramType(index); for (auto* curve : m_curvesList) curve->setHistogramType(histogramType); } void HistogramDock::histogramOrientationChanged(int index) { if (m_initializing) return; Histogram::HistogramOrientation histogramOrientation = Histogram::HistogramOrientation(index); for (auto* curve : m_curvesList) curve->setHistogramOrientation(histogramOrientation); } -void HistogramDock::binValueChanged(int value) { +void HistogramDock::binningMethodChanged(int index) { if (m_initializing) return; + Histogram::BinningMethod binningMethod = Histogram::BinningMethod(index); + if (binningMethod == Histogram::ByNumber) { + ui.lBinCount->show(); + ui.sbBinCount->show(); + ui.lBinWidth->hide(); + ui.leBinWidth->hide(); + } else if (binningMethod == Histogram::ByWidth) { + ui.lBinCount->hide(); + ui.sbBinCount->hide(); + ui.lBinWidth->show(); + ui.leBinWidth->show(); + } else { + ui.lBinCount->hide(); + ui.sbBinCount->hide(); + ui.lBinWidth->hide(); + ui.leBinWidth->hide(); + } + for (auto* curve : m_curvesList) - curve->setBinValue(value); + curve->setBinningMethod(binningMethod); } -void HistogramDock::binsOptionChanged(int index) { +void HistogramDock::binCountChanged(int value) { if (m_initializing) return; - Histogram::BinsOption binsOption = Histogram::BinsOption(index); for (auto* curve : m_curvesList) - curve->setbinsOption(binsOption); + curve->setBinValue(value); +} + +void HistogramDock::binWidthChanged(double value) { + if (m_initializing) + return; + + //TODO +/* for (auto* curve : m_curvesList) + curve->setBinWidth(value);*/ } void HistogramDock::lineColorChanged(const QColor& color){ if (m_initializing) return; QPen pen; for (auto* curve: m_curvesList) { pen = curve->linePen(); pen.setColor(color); curve->setLinePen(pen); } } void HistogramDock::xColumnChanged(const QModelIndex& index) { if (m_initializing) return; AbstractAspect* aspect = static_cast(index.internalPointer()); AbstractColumn* column(nullptr); if (aspect) { column = dynamic_cast(aspect); Q_ASSERT(column); } for (auto* curve : m_curvesList) curve->setXColumn(column); } void HistogramDock::loadConfigFromTemplate(KConfig& config) { //extract the name of the template from the file name QString name; int index = config.name().lastIndexOf(QDir::separator()); if (index!=-1) name = config.name().right(config.name().size() - index - 1); else name = config.name(); int size = m_curvesList.size(); if (size>1) m_curve->beginMacro(i18n("%1 xy-curves: template \"%2\" loaded", size, name)); else m_curve->beginMacro(i18n("%1: template \"%2\" loaded", m_curve->name(), name)); this->loadConfig(config); m_curve->endMacro(); } void HistogramDock::saveConfigAsTemplate(KConfig& config) { KConfigGroup group = config.group( "Histogram" ); //Values group.writeEntry("ValuesType", ui.cbValuesType->currentIndex()); group.writeEntry("ValuesPosition", ui.cbValuesPosition->currentIndex()); group.writeEntry("ValuesDistance", Worksheet::convertToSceneUnits(ui.sbValuesDistance->value(),Worksheet::Point)); group.writeEntry("ValuesRotation", ui.sbValuesRotation->value()); group.writeEntry("ValuesOpacity", ui.sbValuesOpacity->value()/100); group.writeEntry("ValuesPrefix", ui.leValuesPrefix->text()); group.writeEntry("ValuesSuffix", ui.leValuesSuffix->text()); group.writeEntry("ValuesFont", ui.kfrValuesFont->font()); group.writeEntry("ValuesColor", ui.kcbValuesColor->color()); //Filling group.writeEntry("FillingPosition", ui.cbFillingPosition->currentIndex()); group.writeEntry("FillingType", ui.cbFillingType->currentIndex()); group.writeEntry("FillingColorStyle", ui.cbFillingColorStyle->currentIndex()); group.writeEntry("FillingImageStyle", ui.cbFillingImageStyle->currentIndex()); group.writeEntry("FillingBrushStyle", ui.cbFillingBrushStyle->currentIndex()); group.writeEntry("FillingFileName", ui.leFillingFileName->text()); group.writeEntry("FillingFirstColor", ui.kcbFillingFirstColor->color()); group.writeEntry("FillingSecondColor", ui.kcbFillingSecondColor->color()); group.writeEntry("FillingOpacity", ui.sbFillingOpacity->value()/100.0); config.sync(); } //************************************************************* //*********** SLOTs for changes triggered in Histogram ********** //************************************************************* //General-Tab void HistogramDock::curveDescriptionChanged(const AbstractAspect* aspect) { if (m_curve != aspect) return; m_initializing = true; if (aspect->name() != ui.leName->text()) ui.leName->setText(aspect->name()); else if (aspect->comment() != ui.leComment->text()) ui.leComment->setText(aspect->comment()); m_initializing = false; } void HistogramDock::curveHistogramDataChanged(Histogram::HistogramData data) { m_initializing = true; ui.cbHistogramType->setCurrentIndex(data.type); - ui.cbBins->setCurrentIndex(data.binsOption); - ui.sbBins->setValue(data.binValue); + ui.cbBinningMethod->setCurrentIndex(data.binningMethod); + ui.sbBinCount->setValue(data.binCount); m_initializing = false; } diff --git a/src/kdefrontend/dockwidgets/HistogramDock.h b/src/kdefrontend/dockwidgets/HistogramDock.h index d60b51f76..4bdaf1a03 100644 --- a/src/kdefrontend/dockwidgets/HistogramDock.h +++ b/src/kdefrontend/dockwidgets/HistogramDock.h @@ -1,156 +1,157 @@ /*************************************************************************** File : HistogramDock.h Project : LabPlot Description : widget for histogram plot properties -------------------------------------------------------------------- Copyright : (C) 2016 Anu Mittal (anu22mittal@gmail.com) ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #ifndef HISTOGRAMDOCK_H #define HISTOGRAMDOCK_H #include "backend/worksheet/Worksheet.h" #include "backend/worksheet/plots/cartesian/Histogram.h" #include "ui_histogramdock.h" class Histogram; class TreeViewComboBox; class AspectTreeModel; class Column; class HistogramDock : public QWidget { Q_OBJECT public: explicit HistogramDock(QWidget*); ~HistogramDock(); void setCurves(QList); private: QStringList dateStrings; QStringList timeStrings; TreeViewComboBox* cbXColumn; TreeViewComboBox* cbValuesColumn; void updateValuesFormatWidgets(const AbstractColumn::ColumnMode); void showValuesColumnFormat(const Column*); void load(); void loadConfig(KConfig&); protected: Ui::HistogramDock ui; QList m_curvesList; Histogram* m_curve; AspectTreeModel* m_aspectTreeModel; bool m_initializing; virtual void setModel(); void setModelIndexFromColumn(TreeViewComboBox*, const AbstractColumn*); private slots: void init(); void retranslateUi(); //SLOTs for changes triggered in HistogramDock void nameChanged(); void commentChanged(); void xColumnChanged(const QModelIndex&); void visibilityChanged(bool); //Histogram-types void histogramTypeChanged(int); //histogram-orientation void histogramOrientationChanged(int); //bins setting - void binsOptionChanged(int); - void binValueChanged(int); + void binningMethodChanged(int); + void binCountChanged(int); + void binWidthChanged(double); //Values-Tab void valuesTypeChanged(int); void valuesColumnChanged(const QModelIndex&); void valuesPositionChanged(int); void valuesDistanceChanged(double); void valuesRotationChanged(int); void valuesOpacityChanged(int); void valuesPrefixChanged(); void valuesSuffixChanged(); void valuesFontChanged(const QFont&); void valuesColorChanged(const QColor&); //Filling-tab void fillingPositionChanged(int); void fillingTypeChanged(int); void fillingColorStyleChanged(int); void fillingImageStyleChanged(int); void fillingBrushStyleChanged(int); void fillingFirstColorChanged(const QColor&); void fillingSecondColorChanged(const QColor&); void selectFile(); void fileNameChanged(); void fillingOpacityChanged(int); void lineColorChanged(const QColor&); //SLOTs for changes triggered in Histogram //General-Tab /*void curveDescriptionChanged(const AbstractAspect*); void curveXColumnChanged(const AbstractColumn*);*/ void curveVisibilityChanged(bool); void curveLinePenChanged(const QPen&); //Values-Tab void curveValuesTypeChanged(Histogram::ValuesType); void curveValuesColumnChanged(const AbstractColumn*); void curveValuesPositionChanged(Histogram::ValuesPosition); void curveValuesDistanceChanged(qreal); void curveValuesOpacityChanged(qreal); void curveValuesRotationAngleChanged(qreal); void curveValuesPrefixChanged(const QString&); void curveValuesSuffixChanged(const QString&); void curveValuesFontChanged(QFont); void curveValuesColorChanged(QColor); //Filling-Tab void curveFillingPositionChanged(Histogram::FillingPosition); void curveFillingTypeChanged(PlotArea::BackgroundType); void curveFillingColorStyleChanged(PlotArea::BackgroundColorStyle); void curveFillingImageStyleChanged(PlotArea::BackgroundImageStyle); void curveFillingBrushStyleChanged(Qt::BrushStyle); void curveFillingFirstColorChanged(QColor&); void curveFillingSecondColorChanged(QColor&); void curveFillingFileNameChanged(QString&); void curveFillingOpacityChanged(float); void curveDescriptionChanged(const AbstractAspect*); void curveHistogramDataChanged(Histogram::HistogramData); //load and save void loadConfigFromTemplate(KConfig&); void saveConfigAsTemplate(KConfig&); signals: void info(const QString&); }; #endif diff --git a/src/kdefrontend/ui/dockwidgets/histogramdock.ui b/src/kdefrontend/ui/dockwidgets/histogramdock.ui index 4ea22994c..ab7a3faa7 100644 --- a/src/kdefrontend/ui/dockwidgets/histogramdock.ui +++ b/src/kdefrontend/ui/dockwidgets/histogramdock.ui @@ -1,1468 +1,1498 @@ HistogramDock 0 0 532 978 0 General - + Name: Qt::Horizontal QSizePolicy::Fixed 10 23 Comment: Qt::Vertical QSizePolicy::Fixed 32 18 Data: Qt::Vertical QSizePolicy::Fixed 32 18 Type: Orientation: - + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 32 + 30 + + + + + + + + + 75 + true + + - Bins: + Binning - - + + + + Method: + + - - + + + + + + + Bin Count: + + + + + 1 30 10 - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 32 - 8 - + + + + Bin Width: - + - + + + + Qt::Vertical QSizePolicy::MinimumExpanding 24 477 - + visible Line 75 true Line Style: Qt::Horizontal QSizePolicy::Fixed 10 23 Color: 0 0 Width: pt 0.500000000000000 Opacity: 0 0 The opacity ranges from 0 to 100, where 0 is fully transparent and 100 is fully opaque. % 0 100 10 100 Qt::Vertical QSizePolicy::Fixed 32 18 75 true Drop lines Type: 0 0 Style: Color: 0 0 Width: pt 0.500000000000000 Opacity: 0 0 The opacity ranges from 0 to 100, where 0 is fully transparent and 100 is fully opaque. % 0 100 10 100 Qt::Vertical 18 403 Symbol 75 true General Style: Qt::Horizontal QSizePolicy::Fixed 10 23 0 0 Size: pt 0.500000000000000 Rotation: 0 0 ° -360 360 10 0 Opacity: 0 0 The opacity ranges from 0 to 100, where 0 is fully transparent and 100 is fully opaque. % 0 100 10 100 Qt::Vertical QSizePolicy::Fixed 72 18 75 true Filling Style: Color: 0 0 Qt::Vertical QSizePolicy::Fixed 72 18 75 true Border Style: Color: 0 0 Width: pt 0.500000000000000 Qt::Vertical QSizePolicy::Expanding 72 342 Values - + 75 true General Type: Qt::Horizontal QSizePolicy::Fixed 10 23 0 0 Dataset: Position: Distance: true pt 0.500000000000000 Rotation: 0 0 ° -360 360 10 Opacity: 0 0 The opacity ranges from 0 to 100, where 0 is fully transparent and 100 is fully opaque. % 0 100 10 100 Qt::Vertical QSizePolicy::Fixed 86 18 75 true Format Format: Precision: 0 0 0 16 0 Qt::Vertical QSizePolicy::Fixed 86 18 75 true Text Prefix: 0 0 Suffix: 0 0 Font: Color: 0 0 Qt::Vertical 28 47 Filling Direction: Qt::Horizontal QSizePolicy::Fixed 13 23 0 0 Type: 0 0 File name: Specify the name of the image file. true 0 0 Select the file to import Style: Style: Style: First color: Second color: Opacity: 0 0 The opacity ranges from 0 to 100, where 0 is fully transparent and 100 is fully opaque. % 0 100 10 100 Qt::Vertical 24 271 Error Bars 75 true Error Type: Qt::Horizontal QSizePolicy::Fixed 13 23 0 0 Data: Qt::Vertical QSizePolicy::Fixed 20 18 75 true Format Type: Style: Cap size: pt 0.500000000000000 Color: 0 0 Width: pt 0.500000000000000 Opacity: 0 0 The opacity ranges from 0 to 100, where 0 is fully transparent and 100 is fully opaque. % 0 100 10 100 Qt::Vertical QSizePolicy::Expanding 20 454 KFontRequester QWidget
kfontrequester.h
KComboBox QComboBox
kcombobox.h
KColorButton QPushButton
kcolorbutton.h