Index: src/CMakeLists.txt =================================================================== --- src/CMakeLists.txt +++ src/CMakeLists.txt @@ -320,6 +320,7 @@ ${COMMONFRONTEND_DIR}/widgets/TreeViewComboBox.cpp ${COMMONFRONTEND_DIR}/widgets/qxtspanslider.cpp ${COMMONFRONTEND_DIR}/widgets/MemoryWidget.cpp + ${COMMONFRONTEND_DIR}/widgets/DateTimeSpinBox.cpp ${COMMONFRONTEND_DIR}/datapicker/DatapickerView.cpp ${COMMONFRONTEND_DIR}/datapicker/DatapickerImageView.cpp ) Index: src/backend/worksheet/plots/cartesian/Axis.cpp =================================================================== --- src/backend/worksheet/plots/cartesian/Axis.cpp +++ src/backend/worksheet/plots/cartesian/Axis.cpp @@ -172,7 +172,7 @@ d->majorTicksDirection = (Axis::TicksDirection) group.readEntry("MajorTicksDirection", (int) Axis::ticksOut); d->majorTicksType = (Axis::TicksType) group.readEntry("MajorTicksType", (int) Axis::TicksTotalNumber); d->majorTicksNumber = group.readEntry("MajorTicksNumber", 11); - d->majorTicksIncrement = group.readEntry("MajorTicksIncrement", 1.0); + d->majorTicksIncrement = group.readEntry("MajorTicksIncrement", -1.0); // set to negative value, so axisdocks determines the value to not to have to much labels the first time switched to TicksIncrement d->majorTicksPen.setStyle((Qt::PenStyle) group.readEntry("MajorTicksLineStyle", (int)Qt::SolidLine) ); d->majorTicksPen.setColor( group.readEntry("MajorTicksColor", QColor(Qt::black) ) ); d->majorTicksPen.setWidthF( group.readEntry("MajorTicksWidth", Worksheet::convertToSceneUnits(1.0, Worksheet::Point) ) ); @@ -182,7 +182,7 @@ d->minorTicksDirection = (Axis::TicksDirection) group.readEntry("MinorTicksDirection", (int) Axis::ticksOut); d->minorTicksType = (Axis::TicksType) group.readEntry("MinorTicksType", (int) Axis::TicksTotalNumber); d->minorTicksNumber = group.readEntry("MinorTicksNumber", 1); - d->minorTicksIncrement = group.readEntry("MinorTicksIncrement", 0.5); + d->minorTicksIncrement = group.readEntry("MinorTicksIncrement", -1.0); d->minorTicksPen.setStyle((Qt::PenStyle) group.readEntry("MinorTicksLineStyle", (int)Qt::SolidLine) ); d->minorTicksPen.setColor( group.readEntry("MinorTicksColor", QColor(Qt::black) ) ); d->minorTicksPen.setWidthF( group.readEntry("MinorTicksWidth", Worksheet::convertToSceneUnits(1.0, Worksheet::Point) ) ); @@ -774,7 +774,7 @@ exec(new AxisSetLabelsOffsetCmd(d, offset, ki18n("%1: set label offset"))); } -STD_SETTER_CMD_IMPL_F_S(Axis, SetLabelsRotationAngle, qreal, labelsRotationAngle, recalcShapeAndBoundingRect); +STD_SETTER_CMD_IMPL_F_S(Axis, SetLabelsRotationAngle, qreal, labelsRotationAngle, retransformTickLabelPositions); void Axis::setLabelsRotationAngle(qreal angle) { Q_D(Axis); if (angle != d->labelsRotationAngle) @@ -1440,6 +1440,7 @@ for (const auto value : tickLabelValues) { str = QString::number(value, 'e', labelsPrecision); if (str == "-" + nullStr) str = nullStr; + str = labelsPrefix + str + labelsSuffix; tickLabelStrings << str; } } else if (labelsFormat == Axis::FormatPowers10) { @@ -1495,10 +1496,12 @@ for (int i = 0; i < tempValues.size(); ++i) { for (int j = 0; j < tempValues.size(); ++j) { - if (i == j) continue; - if (tempValues.at(i) == tempValues.at(j)) { - //duplicate for the current precision found, increase the precision and check again - return upperLabelsPrecision(precision + 1); + if (i == j) + continue; + + if (tempValues.at(i) == tempValues.at(j)) { + //duplicate for the current precision found, increase the precision and check again + return upperLabelsPrecision(precision + 1); } } } @@ -1563,15 +1566,24 @@ QTextDocument td; td.setDefaultFont(labelsFont); - + double cosinus = cos(labelsRotationAngle * M_PI / 180); // calculate only one time + double sinus = sin(labelsRotationAngle * M_PI / 180); // calculate only one time for ( int i = 0; i < majorTickPoints.size(); i++ ) { - if (labelsFormat == Axis::FormatDecimal || labelsFormat == Axis::FormatScientificE) { + if ((orientation == Axis::AxisHorizontal && plot->xRangeFormat() == CartesianPlot::Numeric) || + (orientation == Axis::AxisVertical && plot->yRangeFormat() == CartesianPlot::Numeric)) { + if (labelsFormat == Axis::FormatDecimal || labelsFormat == Axis::FormatScientificE) { + width = fm.width(tickLabelStrings.at(i)); + } else { + td.setHtml(tickLabelStrings.at(i)); + width = td.size().width(); + height = td.size().height(); + } + } else { // Datetime width = fm.width(tickLabelStrings.at(i)); - } else { - td.setHtml(tickLabelStrings.at(i)); - width = td.size().width(); - height = td.size().height(); } + + double diffx = cosinus * width; + double diffy = sinus * width; anchorPoint = majorTickPoints.at(i); //center align all labels with respect to the end point of the tick line @@ -1579,19 +1591,47 @@ if (offset < middleY) { startPoint = anchorPoint + QPointF(0, (majorTicksDirection & Axis::ticksIn) ? yDirection * majorTicksLength : 0); endPoint = anchorPoint + QPointF(0, (majorTicksDirection & Axis::ticksOut) ? -yDirection * majorTicksLength : 0); - } - else { + } else { startPoint = anchorPoint + QPointF(0, (majorTicksDirection & Axis::ticksOut) ? yDirection * majorTicksLength : 0); endPoint = anchorPoint + QPointF(0, (majorTicksDirection & Axis::ticksIn) ? -yDirection * majorTicksLength : 0); } - if (labelsPosition == Axis::LabelsOut) { - pos.setX( endPoint.x() - width/2); - pos.setY( endPoint.y() + height + labelsOffset ); - } else { - pos.setX( startPoint.x() - width/2); - pos.setY( startPoint.y() - labelsOffset ); + + // for rotated labels (angle is not zero), align label's corner at the position of the tick + if (abs(labelsRotationAngle) > 179.999 && abs(labelsRotationAngle) < 180.009) { // +-180° + if (labelsPosition == Axis::LabelsOut) { + pos.setX( endPoint.x() + width/2); + pos.setY( endPoint.y() + labelsOffset ); + } else { + pos.setX( startPoint.x() + width/2); + pos.setY( startPoint.y() - height + labelsOffset ); + } + } else if (labelsRotationAngle <= -0.01) { // [-0.01°, -180°) + if (labelsPosition == Axis::LabelsOut) { + pos.setX( endPoint.x() + sinus * height/2); + pos.setY( endPoint.y() + labelsOffset + cosinus * height/2); + } else { + pos.setX( startPoint.x() + sinus * height/2 - diffx); + pos.setY( startPoint.y() + labelsOffset + cosinus * height/2 + diffy); + } + } else if (labelsRotationAngle >= 0.01) { // [0.01°, 180°) + if (labelsPosition == Axis::LabelsOut) { + pos.setX( endPoint.x() - diffx + sinus * height/2); + pos.setY( endPoint.y() + labelsOffset + diffy + cosinus * height/2); + } else { + pos.setX( startPoint.x() + sinus * height/2); + pos.setY( startPoint.y() + labelsOffset + cosinus * height/2); + } + } else { // 0° + if (labelsPosition == Axis::LabelsOut) { + pos.setX( endPoint.x() - width/2); + pos.setY( endPoint.y() + height + labelsOffset ); + } else { + pos.setX( startPoint.x() - width/2); + pos.setY( startPoint.y() + labelsOffset ); + } } - } else {// vertical + // ---------------------- vertical ------------------------- + } else { if (offset < middleX) { startPoint = anchorPoint + QPointF((majorTicksDirection & Axis::ticksIn) ? xDirection * majorTicksLength : 0, 0); endPoint = anchorPoint + QPointF((majorTicksDirection & Axis::ticksOut) ? -xDirection * majorTicksLength : 0, 0); @@ -1599,12 +1639,57 @@ startPoint = anchorPoint + QPointF((majorTicksDirection & Axis::ticksOut) ? xDirection * majorTicksLength : 0, 0); endPoint = anchorPoint + QPointF((majorTicksDirection & Axis::ticksIn) ? -xDirection * majorTicksLength : 0, 0); } - if (labelsPosition == Axis::LabelsOut) { - pos.setX( endPoint.x() - width - labelsOffset ); - pos.setY( endPoint.y() + height/2 ); - } else { - pos.setX( startPoint.x() + labelsOffset ); - pos.setY( startPoint.y() + height/2 ); + + if (labelsRotationAngle >= 89.999 && labelsRotationAngle <= 90.009) { // +90° + if (labelsPosition == Axis::LabelsOut) { + pos.setX( endPoint.x() - labelsOffset); + pos.setY( endPoint.y() + width/2 ); + } else { + pos.setX( startPoint.x() - labelsOffset); + pos.setY( startPoint.y() + width/2); + } + } else if (labelsRotationAngle >= -90.999 && labelsRotationAngle <= -89.009) { // -90° + if (labelsPosition == Axis::LabelsOut) { + pos.setX( endPoint.x() - labelsOffset - height); + pos.setY( endPoint.y() - width/2 ); + } else { + pos.setX( startPoint.x() - labelsOffset); + pos.setY( startPoint.y() - width/2 ); + } + } else if (abs(labelsRotationAngle) > 179.999 && abs(labelsRotationAngle) < 180.009) { // +-180° + if (labelsPosition == Axis::LabelsOut) { + pos.setX( endPoint.x() - labelsOffset); + pos.setY( endPoint.y() - height/2); + } else { + pos.setX( startPoint.x() - labelsOffset + width); + pos.setY( startPoint.y() - height/2 ); + } + } else if (abs(labelsRotationAngle) >= 0.01 && abs(labelsRotationAngle) < 90.01) { // [0.01°, 90°) + if (labelsPosition == Axis::LabelsOut) { + // left + pos.setX( endPoint.x() - labelsOffset - diffx + sinus * height/2); + pos.setY( endPoint.y() + cosinus * height/2 + diffy); + } else { + pos.setX( startPoint.x() - labelsOffset + sinus * height/2); + pos.setY( startPoint.y() + cosinus * height/2); + } + } else if (abs(labelsRotationAngle) >= 90.01 && abs(labelsRotationAngle) < 180) { // [90.01, 180) + if (labelsPosition == Axis::LabelsOut) { + // left + pos.setX( endPoint.x() - labelsOffset + sinus * height/2); + pos.setY( endPoint.y() + cosinus * height/2); + } else { + pos.setX( startPoint.x() - labelsOffset - diffx + sinus * height/2); + pos.setY( startPoint.y() + diffy + cosinus * height/2); + } + } else { // 0° + if (labelsPosition == Axis::LabelsOut) { + pos.setX( endPoint.x() - width - labelsOffset); + pos.setY( endPoint.y() + height/2 ); + } else { + pos.setX( startPoint.x() - labelsOffset); + pos.setY( startPoint.y() + height/2 ); + } } } tickLabelPoints << pos; @@ -1762,15 +1847,16 @@ for (int i = 0; i < tickLabelPoints.size(); i++) { tempPath = QPainterPath(); if (labelsFormat == Axis::FormatDecimal || labelsFormat == Axis::FormatScientificE) { - tempPath.addRect( fm.boundingRect(tickLabelStrings.at(i)) ); + tempPath.addRect(fm.boundingRect(tickLabelStrings.at(i))); } else { td.setHtml(tickLabelStrings.at(i)); - tempPath.addRect( QRectF(0, -td.size().height(), td.size().width(), td.size().height()) ); + tempPath.addRect(QRectF(0, -td.size().height(), td.size().width(), td.size().height())); } trafo.reset(); trafo.translate( tickLabelPoints.at(i).x(), tickLabelPoints.at(i).y() ); - trafo.rotate( -labelsRotationAngle ); + + trafo.rotate(-labelsRotationAngle); tempPath = trafo.map(tempPath); tickLabelsPath.addPath(WorksheetElement::shapeFromPath(tempPath, linePen)); @@ -1787,11 +1873,15 @@ qreal offsetX = titleOffsetX - labelsOffset; //the distance to the axis line qreal offsetY = titleOffsetY - labelsOffset; //the distance to the axis line if (orientation == Axis::AxisHorizontal) { - offsetY -= title->graphicsItem()->boundingRect().height()/2 + tickLabelsPath.boundingRect().height(); - title->setPosition( QPointF( (rect.topLeft().x() + rect.topRight().x())/2 + offsetX, rect.bottomLeft().y() - offsetY ) ); + offsetY -= title->graphicsItem()->boundingRect().height()/2; + if (labelsPosition == Axis::LabelsOut) + offsetY -= tickLabelsPath.boundingRect().height(); + title->setPosition( QPointF( (rect.topLeft().x() + rect.topRight().x())/2 + titleOffsetX, rect.bottomLeft().y() - offsetY ) ); } else { - offsetX -= title->graphicsItem()->boundingRect().width()/2 + tickLabelsPath.boundingRect().width(); - title->setPosition( QPointF( rect.topLeft().x() + offsetX, (rect.topLeft().y() + rect.bottomLeft().y())/2 - offsetY) ); + offsetX -= title->graphicsItem()->boundingRect().width()/2; + if (labelsPosition == Axis::LabelsOut) + offsetX -= tickLabelsPath.boundingRect().width(); + title->setPosition( QPointF( rect.topLeft().x() + offsetX, (rect.topLeft().y() + rect.bottomLeft().y())/2 - titleOffsetY) ); } axisShape.addPath(WorksheetElement::shapeFromPath(title->graphicsItem()->mapToParent(title->graphicsItem()->shape()), linePen)); } @@ -1853,21 +1943,32 @@ painter->setFont(labelsFont); QTextDocument td; td.setDefaultFont(labelsFont); - for (int i = 0; i < tickLabelPoints.size(); i++) { - painter->translate(tickLabelPoints.at(i)); - painter->save(); - painter->rotate(-labelsRotationAngle); - - if (labelsFormat == Axis::FormatDecimal || labelsFormat == Axis::FormatScientificE) { + if ((orientation == Axis::AxisHorizontal && plot->xRangeFormat() == CartesianPlot::Numeric) || + (orientation == Axis::AxisVertical && plot->yRangeFormat() == CartesianPlot::Numeric)) { + for (int i = 0; i < tickLabelPoints.size(); i++) { + painter->translate(tickLabelPoints.at(i)); + painter->save(); + painter->rotate(-labelsRotationAngle); + + if (labelsFormat == Axis::FormatDecimal || labelsFormat == Axis::FormatScientificE) { + painter->drawText(QPoint(0,0), tickLabelStrings.at(i)); + } else { + td.setHtml(tickLabelStrings.at(i)); + painter->translate(0, -td.size().height()); + td.drawContents(painter); + } + painter->restore(); + painter->translate(-tickLabelPoints.at(i)); + } + } else { // datetime + for (int i = 0; i < tickLabelPoints.size(); i++) { + painter->translate(tickLabelPoints.at(i)); + painter->save(); + painter->rotate(-labelsRotationAngle); painter->drawText(QPoint(0,0), tickLabelStrings.at(i)); - } else { - td.setHtml(tickLabelStrings.at(i)); - painter->translate(0, -td.size().height()); - td.drawContents(painter); + painter->restore(); + painter->translate(-tickLabelPoints.at(i)); } - - painter->restore(); - painter->translate(-tickLabelPoints.at(i)); } } Index: src/commonfrontend/widgets/DateTimeSpinBox.h =================================================================== --- /dev/null +++ src/commonfrontend/widgets/DateTimeSpinBox.h @@ -0,0 +1,74 @@ +/*************************************************************************** + File : DateTimeSpinBox.h + Project : LabPlot + Description : widget for setting datetimes with a spinbox + -------------------------------------------------------------------- + Copyright : (C) 2019 Martin Marmsoler (martin.marmsoler@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 DATETIMESPINBOX_H +#define DATETIMESPINBOX_H + +#include + +class QRegularExpressionValidator; + + +// Assumption: Month has always 30 days +class DateTimeSpinBox: public QAbstractSpinBox +{ + + Q_OBJECT; +private: + enum Type { + year, + month, + day, + hour, + minute, + second, + millisecond + }; + +public: + DateTimeSpinBox(QWidget* parent); + void keyPressEvent(QKeyEvent *event) override; + void stepBy(int steps) override; + QAbstractSpinBox::StepEnabled stepEnabled() const override; + bool increaseValue(Type type, int step); + bool changeValue(qint64& thisType, Type nextTypeType, int step); + Type determineType(int cursorPos) const; + void writeValue(); + void setValue(qint64 increment); + qint64 value(); + void getValue(); + void setCursorPosition(Type type); + bool valid(); +private: + QRegularExpressionValidator *m_regularExpressionValidator; + qint64 m_year{0}, m_month{0}, m_day{0}, m_hour{0}, m_minute{0}, m_second{0}, m_millisecond{0}; +signals: + void valueChanged(); +}; + +#endif // DATETIMESPINBOX_H Index: src/commonfrontend/widgets/DateTimeSpinBox.cpp =================================================================== --- /dev/null +++ src/commonfrontend/widgets/DateTimeSpinBox.cpp @@ -0,0 +1,304 @@ +/*************************************************************************** + File : DateTimeSpinBox.cpp + Project : LabPlot + Description : widget for setting datetimes with a spinbox + -------------------------------------------------------------------- + Copyright : (C) 2019 Martin Marmsoler (martin.marmsoler@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 * + * * + ***************************************************************************/ + +#include "DateTimeSpinBox.h" + +#include +#include +#include + +DateTimeSpinBox::DateTimeSpinBox(QWidget* parent) : QAbstractSpinBox (parent) +{ + lineEdit()->setText("0000.00.00 00:00:00.001"); + stepEnabled(); + + m_regularExpressionValidator = new QRegularExpressionValidator(); + + QRegularExpression regExp("([0-9]+)\.(0[0-9]|1[0-2]|[0-9])\.(0[0-9]|[0-2][0-9]|30|[0-9]) ([0-1][0-9]|2[0-3]|[0-9])\:([0-5][0-9]|[0-9])\:([0-5][0-9]|[0-9])\.[0-9]{0,3}"); + m_regularExpressionValidator->setRegularExpression(regExp); + + lineEdit()->setValidator(m_regularExpressionValidator); +} + +void DateTimeSpinBox::keyPressEvent(QKeyEvent *event) { + + if (event->key() >= Qt::Key_0 && event->key() <= Qt::Key_9) { + int cursorPos = lineEdit()->cursorPosition(); + int textLenght = lineEdit()->text().length(); + QAbstractSpinBox::keyPressEvent(event); + getValue(); + if (lineEdit()->text().length() != textLenght) + lineEdit()->setCursorPosition(cursorPos + 1); + else + lineEdit()->setCursorPosition(cursorPos); + } else if (event->key() == Qt::Key_Up) { + Type type = determineType(lineEdit()->cursorPosition()); + increaseValue(type, 1); + writeValue(); + setCursorPosition(type); + } else if (event->key() == Qt::Key_Down) { + Type type = determineType(lineEdit()->cursorPosition()); + increaseValue(type, -1); + writeValue(); + setCursorPosition(type); + } else { + QAbstractSpinBox::keyPressEvent(event); + getValue(); + } +} + +QAbstractSpinBox::StepEnabled DateTimeSpinBox::stepEnabled() const { + return QAbstractSpinBox::StepEnabledFlag::StepUpEnabled | QAbstractSpinBox::StepEnabledFlag::StepDownEnabled; // for testing +} + +void DateTimeSpinBox::stepBy(int steps) { + Type type = determineType(lineEdit()->cursorPosition()); + increaseValue(type, steps); + writeValue(); + setCursorPosition(type); +} + +/*! + * Write value to lineEdit of the spinbox + */ +void DateTimeSpinBox::writeValue() { + lineEdit()->setText(QString::number(m_year) + "." + + QString("%1").arg(m_month, 2, 10, QLatin1Char('0')) + "." + + QString("%1").arg(m_day, 2, 10, QLatin1Char('0')) + " " + + QString("%1").arg(m_hour, 2, 10, QLatin1Char('0')) + ":" + + QString("%1").arg(m_minute, 2, 10, QLatin1Char('0')) + ":" + + QString("%1").arg(m_second, 2, 10, QLatin1Char('0')) + "." + + QString("%1").arg(m_millisecond, 3, 10, QLatin1Char('0'))); + emit valueChanged(); +} + +void DateTimeSpinBox::setValue(qint64 increment) { + qint64 divisor = qint64(12) * 30 * 24 * 60 * 60 * 1000; + qint64 rest; + m_year = increment / divisor; + rest = increment - m_year * divisor; + divisor = qint64(30) * 24 * 60 * 60 * 1000; + m_month = rest / divisor; + rest = rest - m_month * divisor; + divisor = qint64(24) * 60 * 60 * 1000; + m_day = rest / divisor; + rest = rest - m_day * divisor; + divisor = qint64(60) * 60 * 1000; + m_hour = rest / divisor; + rest -= m_hour * divisor; + divisor = qint64(60)* 1000; + m_minute = rest / divisor; + rest -= m_minute * divisor; + divisor = qint64(1000); + m_second = rest /divisor; + rest -= m_second * divisor; + m_millisecond = rest; + + writeValue(); +} + +qint64 DateTimeSpinBox::value() { + return m_millisecond + + 1000 * (m_second + + 60 * (m_minute + + 60 * (m_hour + + 24 * (m_day + + 30 * (m_month + + 12 * m_year))))); +} + +/*! + * Read value from lineEdit of the spinbox + */ +void DateTimeSpinBox::getValue() { + QString text = lineEdit()->text(); + + int counter = 0; + int startIndex = 0; + for (int i=0; i< text.length(); i++) { + if (text[i] == "." || text[i] == ":" || text[i] == " " || i == text.length()-1) { + switch(counter) { + case Type::year: + m_year = text.mid(startIndex, i - startIndex).toInt(); + break; + case Type::month: + m_month = text.mid(startIndex, i - startIndex).toInt(); + break; + case Type::day: + m_day = text.mid(startIndex, i - startIndex).toInt(); + break; + case Type::hour: + m_hour = text.mid(startIndex, i - startIndex).toInt(); + break; + case Type::minute: + m_minute = text.mid(startIndex, i - startIndex).toInt(); + break; + case Type::second: + m_second = text.mid(startIndex, i - startIndex).toInt(); + break; + case Type::millisecond: + m_millisecond = text.mid(startIndex, i - startIndex + 1).toInt(); // because of the condition (i == text.length()-1) + break; + } + startIndex = i+1; + counter ++; + } + } + + emit valueChanged(); +} + +void DateTimeSpinBox::setCursorPosition(Type type) { + QString text = lineEdit()->text(); + int counter = 0; + for (int i = 0; i < text.length(); i++) { + if (text[i] == "." || text[i] == ":" || text[i] == " ") + counter ++; + + if (counter-1 == type) { + lineEdit()->setCursorPosition(i); + break; + } + } +} + +bool DateTimeSpinBox::valid() { + return true; +} + +// step can also be negative +bool DateTimeSpinBox::increaseValue(DateTimeSpinBox::Type type, int step) { + switch (type) { + + case Type::year: { + if (m_year + step < 0 && step < 0) { + if (m_year + step < 0) { + m_year = 0; + return false; + } + } + m_year += step; + return true; + } + break; + case Type::month: + return changeValue(m_month, Type::year, step); + break; + case Type::day: + return changeValue(m_day, Type::month, step); + break; + case Type::hour: + return changeValue(m_hour, Type::day, step); + break; + case Type::minute: + return changeValue(m_minute, Type::hour, step); + break; + case Type::second: + return changeValue(m_second, Type::minute, step); + break; + case Type::millisecond: + return changeValue(m_millisecond, Type::second, step); + break; + default: + return false; + break; + } + +} + +bool DateTimeSpinBox::changeValue(qint64& thisType, DateTimeSpinBox::Type nextTypeType, int step) { + + int maxValue = 1; + switch (nextTypeType) { + case (Type::year): + maxValue = 12; + break; + case (Type::month): + maxValue = 30; + break; + case (Type::day): + maxValue = 24; + break; + case (Type::hour): + maxValue = 60; + break; + case (Type::minute): + maxValue = 60; + break; + case (Type::second): + maxValue = 1000; + break; + case (Type::millisecond): + return false; + } + + int nextTypeCounter = step / maxValue; + step -= nextTypeCounter * maxValue; + if (thisType + step < 0 && step < 0) { + nextTypeCounter --; + if (increaseValue(nextTypeType, nextTypeCounter)) { + step += maxValue; + thisType += step; + return true; + } else { + thisType = 0; + return false; + } + } else if ( thisType + step > maxValue-1 && step > 0) { + step -= nextTypeCounter * maxValue; + if (thisType + step > maxValue-1) { + nextTypeCounter ++; + step -= maxValue; + thisType += step; + } else + thisType += step; + + + return increaseValue(nextTypeType, nextTypeCounter); + } + thisType += step; + return true; +} + +DateTimeSpinBox::Type DateTimeSpinBox::determineType(int cursorPos) const{ + QString text = lineEdit()->text(); + + if (cursorPos > text.length()) + cursorPos = text.length(); + + int counter = 0; + for (int i = 0; i < cursorPos; i++) { + if (text[i] == "." || text[i] == ":" || text[i] == " ") + counter ++; + } + + if (counter <= Type::millisecond) + return static_cast(counter); + + return Type::millisecond; +} Index: src/kdefrontend/dockwidgets/AxisDock.h =================================================================== --- src/kdefrontend/dockwidgets/AxisDock.h +++ src/kdefrontend/dockwidgets/AxisDock.h @@ -38,6 +38,7 @@ class TreeViewComboBox; class AspectTreeModel; class AbstractColumn; +class DateTimeSpinBox; class AxisDock : public QWidget{ Q_OBJECT @@ -66,6 +67,13 @@ void load(); void loadConfig(KConfig&); + // own created widgets + DateTimeSpinBox* dtsbMajorTicksIncrement {nullptr}; + DateTimeSpinBox* dtsbMinorTicksIncrement {nullptr}; + + int determineDecimals(double diff); + double determineStep(double diff, int decimal); + private slots: void init(); Index: src/kdefrontend/dockwidgets/AxisDock.cpp =================================================================== --- src/kdefrontend/dockwidgets/AxisDock.cpp +++ src/kdefrontend/dockwidgets/AxisDock.cpp @@ -37,6 +37,7 @@ #include "kdefrontend/GuiTools.h" #include "kdefrontend/TemplateHandler.h" #include "kdefrontend/widgets/LabelWidget.h" +#include "commonfrontend/widgets/DateTimeSpinBox.h" #include #include @@ -65,10 +66,13 @@ //"Ticks"-tab auto* layout = static_cast(ui.tabTicks->layout()); cbMajorTicksColumn = new TreeViewComboBox(ui.tabTicks); - layout->addWidget(cbMajorTicksColumn, 5, 2); - + layout->addWidget(cbMajorTicksColumn, 7, 2); cbMinorTicksColumn = new TreeViewComboBox(ui.tabTicks); - layout->addWidget(cbMinorTicksColumn, 18, 2); + layout->addWidget(cbMinorTicksColumn, 21, 2); + dtsbMajorTicksIncrement = new DateTimeSpinBox(ui.tabTicks); + layout->addWidget(dtsbMajorTicksIncrement, 6, 2); + dtsbMinorTicksIncrement = new DateTimeSpinBox(ui.tabTicks); + layout->addWidget(dtsbMinorTicksIncrement, 20, 2); //adjust layouts in the tabs for (int i = 0; i < ui.tabWidget->count(); ++i) { @@ -114,7 +118,9 @@ connect( ui.cbMajorTicksDirection, SIGNAL(currentIndexChanged(int)), this, SLOT(majorTicksDirectionChanged(int)) ); connect( ui.cbMajorTicksType, SIGNAL(currentIndexChanged(int)), this, SLOT(majorTicksTypeChanged(int)) ); connect( ui.sbMajorTicksNumber, SIGNAL(valueChanged(int)), this, SLOT(majorTicksNumberChanged(int)) ); - connect( ui.leMajorTicksIncrement, SIGNAL(textChanged(QString)), this, SLOT(majorTicksIncrementChanged()) ); + connect( ui.sbMajorTicksIncrementNumeric, SIGNAL(valueChanged(double)), this, SLOT(majorTicksIncrementChanged()) ); + connect( dtsbMajorTicksIncrement, SIGNAL(valueChanged()), this, SLOT(majorTicksIncrementChanged()) ); + //connect( ui.sbMajorTicksIncrementNumeric, &QDoubleSpinBox::valueChanged, this, &AxisDock::majorTicksIncrementChanged); connect( cbMajorTicksColumn, SIGNAL(currentModelIndexChanged(QModelIndex)), this, SLOT(majorTicksColumnChanged(QModelIndex)) ); connect( ui.cbMajorTicksLineStyle, SIGNAL(currentIndexChanged(int)), this, SLOT(majorTicksLineStyleChanged(int)) ); connect( ui.kcbMajorTicksColor, SIGNAL(changed(QColor)), this, SLOT(majorTicksColorChanged(QColor)) ); @@ -126,7 +132,8 @@ connect( ui.cbMinorTicksDirection, SIGNAL(currentIndexChanged(int)), this, SLOT(minorTicksDirectionChanged(int)) ); connect( ui.cbMinorTicksType, SIGNAL(currentIndexChanged(int)), this, SLOT(minorTicksTypeChanged(int)) ); connect( ui.sbMinorTicksNumber, SIGNAL(valueChanged(int)), this, SLOT(minorTicksNumberChanged(int)) ); - connect( ui.leMinorTicksIncrement, SIGNAL(textChanged(QString)), this, SLOT(minorTicksIncrementChanged()) ); + connect( ui.sbMajorTicksIncrementNumeric, SIGNAL(valueChanged(double)), this, SLOT(minorTicksIncrementChanged()) ); + connect( dtsbMinorTicksIncrement, SIGNAL(valueChanged()), this, SLOT(minorTicksIncrementChanged()) ); connect( cbMinorTicksColumn, SIGNAL(currentModelIndexChanged(QModelIndex)), this, SLOT(minorTicksColumnChanged(QModelIndex)) ); connect( ui.cbMinorTicksLineStyle, SIGNAL(currentIndexChanged(int)), this, SLOT(minorTicksLineStyleChanged(int)) ); connect( ui.kcbMinorTicksColor, SIGNAL(changed(QColor)), this, SLOT(minorTicksColorChanged(QColor)) ); @@ -186,9 +193,6 @@ ui.leZeroOffset->setValidator( new QDoubleValidator(ui.leZeroOffset) ); ui.leScalingFactor->setValidator( new QDoubleValidator(ui.leScalingFactor) ); - ui.leMajorTicksIncrement->setValidator( new QDoubleValidator(ui.leMajorTicksIncrement) ); - ui.leMinorTicksIncrement->setValidator( new QDoubleValidator(ui.leMinorTicksIncrement) ); - //TODO move this stuff to retranslateUI() ui.cbPosition->addItem(i18n("Top")); ui.cbPosition->addItem(i18n("Bottom")); @@ -789,10 +793,13 @@ ui.cbMajorTicksType->setEnabled(b); ui.lMajorTicksNumber->setEnabled(b); ui.sbMajorTicksNumber->setEnabled(b); - ui.lMajorTicksIncrement->setEnabled(b); - ui.leMajorTicksIncrement->setEnabled(b); + ui.lMajorTicksIncrementNumeric->setEnabled(b); + ui.sbMajorTicksIncrementNumeric->setEnabled(b); + ui.lMajorTicksIncrementDateTime->setEnabled(b); + dtsbMajorTicksIncrement->setEnabled(b); ui.lMajorTicksLineStyle->setEnabled(b); ui.cbMajorTicksLineStyle->setEnabled(b); + dtsbMinorTicksIncrement->setEnabled(b); if (b) { auto penStyle = Qt::PenStyle(ui.cbMajorTicksLineStyle->currentIndex()); b = (penStyle != Qt::NoPen); @@ -818,26 +825,52 @@ Shows/hides the corresponding widgets. */ void AxisDock::majorTicksTypeChanged(int index) { + + if (!m_axis) // If elements are added to the combobox 'cbMajorTicksType' (at init of this class), then this function is called, which is a problem if no axis are available + return; + auto type = Axis::TicksType(index); + const auto* plot = dynamic_cast(m_axis->parentAspect()); + + bool numeric = ( (m_axis->orientation() == Axis::AxisHorizontal && plot->xRangeFormat() == CartesianPlot::Numeric) + || (m_axis->orientation() == Axis::AxisVertical && plot->yRangeFormat() == CartesianPlot::Numeric) ); + if ( type == Axis::TicksTotalNumber) { ui.lMajorTicksNumber->show(); ui.sbMajorTicksNumber->show(); - ui.lMajorTicksIncrement->hide(); - ui.leMajorTicksIncrement->hide(); + ui.lMajorTicksIncrementNumeric->hide(); + ui.sbMajorTicksIncrementNumeric->hide(); + ui.lMajorTicksIncrementDateTime->hide(); + dtsbMajorTicksIncrement->hide(); ui.lMajorTicksColumn->hide(); cbMajorTicksColumn->hide(); } else if ( type == Axis::TicksIncrement) { ui.lMajorTicksNumber->hide(); ui.sbMajorTicksNumber->hide(); - ui.lMajorTicksIncrement->show(); - ui.leMajorTicksIncrement->show(); + ui.lMajorTicksIncrementNumeric->show(); + if (numeric) { + ui.lMajorTicksIncrementDateTime->hide(); + dtsbMajorTicksIncrement->hide(); + ui.lMajorTicksIncrementNumeric->show(); + ui.sbMajorTicksIncrementNumeric->show(); + } else { + ui.lMajorTicksIncrementDateTime->show(); + dtsbMajorTicksIncrement->show(); + ui.lMajorTicksIncrementNumeric->hide(); + ui.sbMajorTicksIncrementNumeric->hide(); + } ui.lMajorTicksColumn->hide(); cbMajorTicksColumn->hide(); + + // Check if Increment is not to small + majorTicksIncrementChanged(); } else { ui.lMajorTicksNumber->hide(); ui.sbMajorTicksNumber->hide(); - ui.lMajorTicksIncrement->hide(); - ui.leMajorTicksIncrement->hide(); + ui.lMajorTicksIncrementNumeric->hide(); + ui.sbMajorTicksIncrementNumeric->hide(); + dtsbMajorTicksIncrement->hide(); + dtsbMajorTicksIncrement->hide(); ui.lMajorTicksColumn->show(); cbMajorTicksColumn->show(); } @@ -847,6 +880,7 @@ for (auto* axis : m_axesList) axis->setMajorTicksType(type); + } void AxisDock::majorTicksNumberChanged(int value) { @@ -861,8 +895,40 @@ if (m_initializing) return; - double value = ui.leMajorTicksIncrement->text().toDouble(); - if (value < 0) value = -1.*value; //don't allow negative values + const auto* plot = dynamic_cast(m_axis->parentAspect()); + + bool numeric = ( (m_axis->orientation() == Axis::AxisHorizontal && plot->xRangeFormat() == CartesianPlot::Numeric) + || (m_axis->orientation() == Axis::AxisVertical && plot->yRangeFormat() == CartesianPlot::Numeric) ); + + double value; + + if (numeric) + value = ui.sbMajorTicksIncrementNumeric->value(); + else + value = dtsbMajorTicksIncrement->value(); + + double diff = m_axis->end() - m_axis->start(); + + if (value == 0 || diff / value > 100 || value < 0) { // maximum of 100 ticks + + if (value == 0) + value = diff / ui.sbMajorTicksNumber->value(); + + if (diff / value > 100) + value = diff / 100; + + // determine stepsize and number of decimals + m_initializing = true; + if (numeric) { + int decimal = determineDecimals(value * 10); + ui.sbMajorTicksIncrementNumeric->setDecimals(decimal); + ui.sbMajorTicksIncrementNumeric->setSingleStep(determineStep(diff, decimal)); + ui.sbMajorTicksIncrementNumeric->setValue(value); + } else + dtsbMajorTicksIncrement->setValue(value); + m_initializing = false; + } + for (auto* axis : m_axesList) axis->setMajorTicksIncrement(value); } @@ -961,8 +1027,10 @@ ui.cbMinorTicksType->setEnabled(b); ui.lMinorTicksNumber->setEnabled(b); ui.sbMinorTicksNumber->setEnabled(b); - ui.lMinorTicksIncrement->setEnabled(b); - ui.leMinorTicksIncrement->setEnabled(b); + ui.lMinorTicksIncrementNumeric->setEnabled(b); + ui.sbMinorTicksIncrementNumeric->setEnabled(b); + ui.lMinorTicksIncrementDateTime->setEnabled(b); + dtsbMinorTicksIncrement->setEnabled(b); ui.lMinorTicksLineStyle->setEnabled(b); ui.cbMinorTicksLineStyle->setEnabled(b); if (b) { @@ -986,26 +1054,52 @@ } void AxisDock::minorTicksTypeChanged(int index) { + + if (!m_axis) // If elements are added to the combobox 'cbMajorTicksType' (at init of this class), then this function is called, which is a problem if no axis are available + return; + auto type = Axis::TicksType(index); + const auto* plot = dynamic_cast(m_axis->parentAspect()); + + bool numeric = ( (m_axis->orientation() == Axis::AxisHorizontal && plot->xRangeFormat() == CartesianPlot::Numeric) + || (m_axis->orientation() == Axis::AxisVertical && plot->yRangeFormat() == CartesianPlot::Numeric) ); + + if ( type == Axis::TicksTotalNumber) { ui.lMinorTicksNumber->show(); ui.sbMinorTicksNumber->show(); - ui.lMinorTicksIncrement->hide(); - ui.leMinorTicksIncrement->hide(); + ui.lMinorTicksIncrementNumeric->hide(); + ui.sbMinorTicksIncrementNumeric->hide(); ui.lMinorTicksColumn->hide(); cbMinorTicksColumn->hide(); + ui.lMinorTicksIncrementDateTime->hide(); + dtsbMinorTicksIncrement->hide(); } else if ( type == Axis::TicksIncrement) { ui.lMinorTicksNumber->hide(); ui.sbMinorTicksNumber->hide(); - ui.lMinorTicksIncrement->show(); - ui.leMinorTicksIncrement->show(); + if (numeric) { + ui.lMinorTicksIncrementNumeric->show(); + ui.sbMinorTicksIncrementNumeric->show(); + ui.lMinorTicksIncrementDateTime->hide(); + dtsbMinorTicksIncrement->hide(); + } else { + ui.lMinorTicksIncrementNumeric->hide(); + ui.sbMinorTicksIncrementNumeric->hide(); + ui.lMinorTicksIncrementDateTime->show(); + dtsbMinorTicksIncrement->show(); + } ui.lMinorTicksColumn->hide(); cbMinorTicksColumn->hide(); + + // Check if Increment is not to small + minorTicksIncrementChanged(); } else { ui.lMinorTicksNumber->hide(); ui.sbMinorTicksNumber->hide(); - ui.lMinorTicksIncrement->hide(); - ui.leMinorTicksIncrement->hide(); + ui.lMinorTicksIncrementNumeric->hide(); + ui.sbMinorTicksIncrementNumeric->hide(); + ui.lMinorTicksIncrementDateTime->hide(); + dtsbMinorTicksIncrement->hide(); ui.lMinorTicksColumn->show(); cbMinorTicksColumn->show(); } @@ -1029,8 +1123,44 @@ if (m_initializing) return; - double value = ui.leMinorTicksIncrement->text().toDouble(); - if (value < 0) value = -1. * value; //don't allow negative values + const auto* plot = dynamic_cast(m_axis->parentAspect()); + + bool numeric = ( (m_axis->orientation() == Axis::AxisHorizontal && plot->xRangeFormat() == CartesianPlot::Numeric) + || (m_axis->orientation() == Axis::AxisVertical && plot->yRangeFormat() == CartesianPlot::Numeric) ); + + double value; + + if (numeric) + value = ui.sbMinorTicksIncrementNumeric->value(); + else + value = dtsbMinorTicksIncrement->value(); + + double numberTicks; + + if (value > 0) + numberTicks = (m_axis->end() - m_axis->start()) / (m_axis->majorTicksNumber() - 1) / value -1; // recal + + if (value == 0 || numberTicks > 100 || value < 0) { + if (value == 0) + value = (m_axis->end() - m_axis->start()) / (m_axis->majorTicksNumber() - 1) / (ui.sbMinorTicksNumber->value() + 1); + + numberTicks = (m_axis->end() - m_axis->start()) / (m_axis->majorTicksNumber() - 1) / value -1; // recalculate number of ticks + + if (numberTicks > 100) // maximum 100 minor ticks + value = (m_axis->end() - m_axis->start()) / (m_axis->majorTicksNumber() - 1) / (100 + 1); + + // determine stepsize and number of decimals + m_initializing = true; + if (numeric) { + int decimal = determineDecimals(value * 10); + ui.sbMinorTicksIncrementNumeric->setDecimals(decimal); + ui.sbMinorTicksIncrementNumeric->setSingleStep(determineStep((m_axis->end() - m_axis->start()) / (m_axis->majorTicksNumber() - 1), decimal)); + ui.sbMinorTicksIncrementNumeric->setValue(value); + } else + dtsbMinorTicksIncrement->setValue(value); + m_initializing = false; + } + for (auto* axis : m_axesList) axis->setMinorTicksIncrement(value); } @@ -1418,6 +1548,12 @@ m_initializing = true; ui.leStart->setText( QString::number(value) ); ui.dateTimeEditStart->setDateTime( QDateTime::fromMSecsSinceEpoch(value) ); + + // determine stepsize and number of decimals + double diff = m_axis->end() - m_axis->start(); + int decimal = determineDecimals(diff); + ui.sbMajorTicksIncrementNumeric->setDecimals(decimal); + ui.sbMajorTicksIncrementNumeric->setSingleStep(determineStep(diff, decimal)); m_initializing = false; } @@ -1425,6 +1561,13 @@ m_initializing = true; ui.leEnd->setText( QString::number(value) ); ui.dateTimeEditEnd->setDateTime( QDateTime::fromMSecsSinceEpoch(value) ); + ui.sbMajorTicksIncrementNumeric->setSingleStep(floor(m_axis->end() - m_axis->start())/10); + + // determine stepsize and number of decimals + double diff = m_axis->end() - m_axis->start(); + int decimal = determineDecimals(diff); + ui.sbMajorTicksIncrementNumeric->setDecimals(decimal); + ui.sbMajorTicksIncrementNumeric->setSingleStep(determineStep(diff, decimal)); m_initializing = false; } @@ -1492,7 +1635,17 @@ } void AxisDock::axisMajorTicksIncrementChanged(qreal increment) { m_initializing = true; - ui.leMajorTicksIncrement->setText( QString::number(increment)); + const auto* plot = dynamic_cast(m_axis->parentAspect()); + if (plot) { + bool numeric = ( (m_axis->orientation() == Axis::AxisHorizontal && plot->xRangeFormat() == CartesianPlot::Numeric) + || (m_axis->orientation() == Axis::AxisVertical && plot->yRangeFormat() == CartesianPlot::Numeric) ); + + if (numeric) + ui.sbMajorTicksIncrementNumeric->setValue(increment); + else { + dtsbMajorTicksIncrement->setValue(increment); + } + } m_initializing = false; } void AxisDock::axisMajorTicksPenChanged(const QPen& pen) { @@ -1531,7 +1684,17 @@ } void AxisDock::axisMinorTicksIncrementChanged(qreal increment) { m_initializing = true; - ui.leMinorTicksIncrement->setText( QString::number(increment)); + const auto* plot = dynamic_cast(m_axis->parentAspect()); + if (plot) { + bool numeric = ( (m_axis->orientation() == Axis::AxisHorizontal && plot->xRangeFormat() == CartesianPlot::Numeric) + || (m_axis->orientation() == Axis::AxisVertical && plot->yRangeFormat() == CartesianPlot::Numeric) ); + + if (numeric) + ui.sbMinorTicksIncrementNumeric->setValue(increment); + else { + dtsbMinorTicksIncrement->setValue(increment); + } + } m_initializing = false; } void AxisDock::axisMinorTicksPenChanged(const QPen& pen) { @@ -1671,6 +1834,10 @@ ui.leStart->setText( QString::number(m_axis->start()) ); ui.leEnd->setText( QString::number(m_axis->end()) ); + + ui.sbMajorTicksIncrementNumeric->setDecimals(0); + ui.sbMajorTicksIncrementNumeric->setSingleStep(m_axis->majorTicksIncrement()); + //depending on range format of the axis (numeric vs. datetime), show/hide the corresponding widgets const auto* plot = dynamic_cast(m_axis->parentAspect()); if (plot) { @@ -1706,6 +1873,7 @@ } ui.dateTimeEditStart->setDateTime(QDateTime::fromMSecsSinceEpoch(m_axis->start())); ui.dateTimeEditEnd->setDateTime(QDateTime::fromMSecsSinceEpoch(m_axis->end())); + } } @@ -1725,7 +1893,6 @@ ui.cbMajorTicksDirection->setCurrentIndex( (int) m_axis->majorTicksDirection() ); ui.cbMajorTicksType->setCurrentIndex( (int) m_axis->majorTicksType() ); ui.sbMajorTicksNumber->setValue( m_axis->majorTicksNumber() ); - ui.leMajorTicksIncrement->setText( QString::number(m_axis->majorTicksIncrement()) ); ui.cbMajorTicksLineStyle->setCurrentIndex( (int) m_axis->majorTicksPen().style() ); ui.kcbMajorTicksColor->setColor( m_axis->majorTicksPen().color() ); ui.sbMajorTicksWidth->setValue( Worksheet::convertFromSceneUnits( m_axis->majorTicksPen().widthF(),Worksheet::Point) ); @@ -1736,7 +1903,6 @@ ui.cbMinorTicksDirection->setCurrentIndex( (int) m_axis->minorTicksDirection() ); ui.cbMinorTicksType->setCurrentIndex( (int) m_axis->minorTicksType() ); ui.sbMinorTicksNumber->setValue( m_axis->minorTicksNumber() ); - ui.leMinorTicksIncrement->setText( QString::number( m_axis->minorTicksIncrement()) ); ui.cbMinorTicksLineStyle->setCurrentIndex( (int) m_axis->minorTicksPen().style() ); ui.kcbMinorTicksColor->setColor( m_axis->minorTicksPen().color() ); ui.sbMinorTicksWidth->setValue( Worksheet::convertFromSceneUnits(m_axis->minorTicksPen().widthF(),Worksheet::Point) ); @@ -1774,7 +1940,6 @@ ui.sbMinorGridWidth->setValue( Worksheet::convertFromSceneUnits(m_axis->minorGridPen().widthF(),Worksheet::Point) ); ui.sbMinorGridOpacity->setValue( round(m_axis->minorGridOpacity()*100.0) ); - m_initializing = true; GuiTools::updatePenStyles(ui.cbLineStyle, ui.kcbLineColor->color()); this->majorTicksTypeChanged(ui.cbMajorTicksType->currentIndex()); GuiTools::updatePenStyles(ui.cbMajorTicksLineStyle, ui.kcbMajorTicksColor->color()); @@ -1782,7 +1947,46 @@ GuiTools::updatePenStyles(ui.cbMinorTicksLineStyle, ui.kcbMinorTicksColor->color()); GuiTools::updatePenStyles(ui.cbMajorGridStyle, ui.kcbMajorGridColor->color()); GuiTools::updatePenStyles(ui.cbMinorGridStyle, ui.kcbMinorGridColor->color()); - m_initializing = false; +} + +/*! + * Determine the number of decimals for using in a QDoubleSpinBox + * \param diff + * \return + */ +int AxisDock::determineDecimals(double diff) { + diff /= 10; // step one decimal before + double power10 = 1; + for (int i = 0; i < 10; i++) { + double nearest = round(diff * power10) / power10; + if (nearest > 0) { + return i; + } + power10 *= 10; + } + + return 10; +} + +/*! + * Determine the step in a QDoubleSpinBox with specific decimals and diff + * \param diff Difference between the largest value and smallest value + * \param decimal + * \return + */ +double AxisDock::determineStep(double diff, int decimal) { + double ten = 1; + if (decimal == 0) { + for (unsigned int i = 1; i < 1000000000; i++) { + if (diff/ten <= 10) { + return ten/10; // use one decimal before + } + ten *= 10; + } + return 1; + } + + return static_cast(1)/(pow(10,decimal)); } void AxisDock::loadConfigFromTemplate(KConfig& config) { @@ -1808,6 +2012,13 @@ void AxisDock::loadConfig(KConfig& config) { KConfigGroup group = config.group( "Axis" ); + bool numeric = false; + const auto* plot = dynamic_cast(m_axis->parentAspect()); + if (plot) { + numeric = ( (m_axis->orientation() == Axis::AxisHorizontal && plot->xRangeFormat() == CartesianPlot::Numeric) + || (m_axis->orientation() == Axis::AxisVertical && plot->yRangeFormat() == CartesianPlot::Numeric) ); + } + //General ui.cbOrientation->setCurrentIndex( group.readEntry("Orientation", (int) m_axis->orientation()) ); @@ -1842,7 +2053,10 @@ ui.cbMajorTicksDirection->setCurrentIndex( group.readEntry("MajorTicksDirection", (int) m_axis->majorTicksDirection()) ); ui.cbMajorTicksType->setCurrentIndex( group.readEntry("MajorTicksType", (int) m_axis->majorTicksType()) ); ui.sbMajorTicksNumber->setValue( group.readEntry("MajorTicksNumber", m_axis->majorTicksNumber()) ); - ui.leMajorTicksIncrement->setText( QString::number( group.readEntry("MajorTicksIncrement", m_axis->majorTicksIncrement())) ); + if (numeric) + ui.sbMajorTicksIncrementNumeric->setValue(group.readEntry("MajorTicksIncrement", m_axis->majorTicksIncrement())); + else + dtsbMajorTicksIncrement->setValue(group.readEntry("MajorTicksIncrement", m_axis->majorTicksIncrement())); ui.cbMajorTicksLineStyle->setCurrentIndex( group.readEntry("MajorTicksLineStyle", (int) m_axis->majorTicksPen().style()) ); ui.kcbMajorTicksColor->setColor( group.readEntry("MajorTicksColor", m_axis->majorTicksPen().color()) ); ui.sbMajorTicksWidth->setValue( Worksheet::convertFromSceneUnits(group.readEntry("MajorTicksWidth", m_axis->majorTicksPen().widthF()),Worksheet::Point) ); @@ -1853,7 +2067,10 @@ ui.cbMinorTicksDirection->setCurrentIndex( group.readEntry("MinorTicksDirection", (int) m_axis->minorTicksDirection()) ); ui.cbMinorTicksType->setCurrentIndex( group.readEntry("MinorTicksType", (int) m_axis->minorTicksType()) ); ui.sbMinorTicksNumber->setValue( group.readEntry("MinorTicksNumber", m_axis->minorTicksNumber()) ); - ui.leMinorTicksIncrement->setText( QString::number( group.readEntry("MinorTicksIncrement", m_axis->minorTicksIncrement())) ); + if (numeric) + ui.sbMinorTicksIncrementNumeric->setValue(group.readEntry("MajorTicksIncrement", m_axis->majorTicksIncrement())); + else + dtsbMinorTicksIncrement->setValue(group.readEntry("MajorTicksIncrement", m_axis->majorTicksIncrement())); ui.cbMinorTicksLineStyle->setCurrentIndex( group.readEntry("MinorTicksLineStyle", (int) m_axis->minorTicksPen().style()) ); ui.kcbMinorTicksColor->setColor( group.readEntry("MinorTicksColor", m_axis->minorTicksPen().color()) ); ui.sbMinorTicksWidth->setValue( Worksheet::convertFromSceneUnits(group.readEntry("MinorTicksWidth", m_axis->minorTicksPen().widthF()),Worksheet::Point) ); @@ -1905,6 +2122,14 @@ void AxisDock::saveConfigAsTemplate(KConfig& config) { KConfigGroup group = config.group( "Axis" ); + bool numeric = false; + const auto* plot = dynamic_cast(m_axis->parentAspect()); + if (plot) { + numeric = ( (m_axis->orientation() == Axis::AxisHorizontal && plot->xRangeFormat() == CartesianPlot::Numeric) + || (m_axis->orientation() == Axis::AxisVertical && plot->yRangeFormat() == CartesianPlot::Numeric) ); + } + + //General group.writeEntry("Orientation", ui.cbOrientation->currentIndex()); @@ -1940,7 +2165,10 @@ group.writeEntry("MajorTicksDirection", ui.cbMajorTicksDirection->currentIndex()); group.writeEntry("MajorTicksType", ui.cbMajorTicksType->currentIndex()); group.writeEntry("MajorTicksNumber", ui.sbMajorTicksNumber->value()); - group.writeEntry("MajorTicksIncrement", ui.leMajorTicksIncrement->text()); + if (numeric) + group.writeEntry("MajorTicksIncrement", QString::number(ui.sbMajorTicksIncrementNumeric->value())); + else + group.writeEntry("MajorTicksIncrement", QString::number(dtsbMajorTicksIncrement->value())); group.writeEntry("MajorTicksLineStyle", ui.cbMajorTicksLineStyle->currentIndex()); group.writeEntry("MajorTicksColor", ui.kcbMajorTicksColor->color()); group.writeEntry("MajorTicksWidth", Worksheet::convertToSceneUnits(ui.sbMajorTicksWidth->value(),Worksheet::Point)); @@ -1951,7 +2179,10 @@ group.writeEntry("MinorTicksDirection", ui.cbMinorTicksDirection->currentIndex()); group.writeEntry("MinorTicksType", ui.cbMinorTicksType->currentIndex()); group.writeEntry("MinorTicksNumber", ui.sbMinorTicksNumber->value()); - group.writeEntry("MinorTicksIncrement", ui.leMinorTicksIncrement->text()); + if (numeric) + group.writeEntry("MinorTicksIncrement", QString::number(ui.sbMinorTicksIncrementNumeric->value())); + else + group.writeEntry("MinorTicksIncrement", QString::number(dtsbMinorTicksIncrement->value())); group.writeEntry("MinorTicksLineStyle", ui.cbMinorTicksLineStyle->currentIndex()); group.writeEntry("MinorTicksColor", ui.kcbMinorTicksColor->color()); group.writeEntry("MinorTicksWidth", Worksheet::convertFromSceneUnits(ui.sbMinorTicksWidth->value(),Worksheet::Point)); Index: src/kdefrontend/ui/dockwidgets/axisdock.ui =================================================================== --- src/kdefrontend/ui/dockwidgets/axisdock.ui +++ src/kdefrontend/ui/dockwidgets/axisdock.ui @@ -29,7 +29,7 @@ - 0 + 3 @@ -517,185 +517,255 @@ Ticks - - - - Qt::Horizontal - - - QSizePolicy::Fixed + + + + + 75 + true + - - - 17 - 24 - + + Minor ticks - + - - + + + + Increment: + + - - + + - Type: + Direction: - - + + - - + + - Number: + Increment: - - + + - Increment: + Column: + + + + + + + + 0 + 0 + + + + The opacity ranges from 0 to 100, where 0 is fully transparent and 100 is fully opaque. + + + % + + + 0 + + + 100 + + + 10 + + + 100 - + + + 0.000000000000000 + + + 999999999999999.000000000000000 + + - - + + + + pt + + + 0.500000000000000 + + + + + - Column: + Length: - - + + Qt::Vertical - - QSizePolicy::Fixed - - 20 - 18 + 48 + 301 - - + + - Style: + Width: - - - - - 0 - 0 - + + + + Column: - - + + - Color: + Number: - - - - - 0 - 0 - + + + + + + + Type: - - + + - Width: + Opacity: - - - - pt - - - 0.500000000000000 + + + + Increment: - + - Length: + Color: - - - - pt + + + + Style: - - 0.500000000000000 + + + + + + + + + + 0 + 0 + - - + + Opacity: - - + + + + Number: + + + + + 0 0 - - The opacity ranges from 0 to 100, where 0 is fully transparent and 100 is fully opaque. - - - % + + + + + + + 75 + true + - - + + Major ticks - - 0 + + + + + + Direction: - - 100 + + + + + + pt - 10 + 0.500000000000000 - - 100 + + + + + + Color: - + Qt::Vertical @@ -711,54 +781,31 @@ - - - - Direction: - - - - - - - - + + Type: - - - - - + + - Number: + Style: - - - - - - - Increment: + + + + pt - - - - - - - - - Column: + + 0.500000000000000 - + Qt::Vertical @@ -774,31 +821,42 @@ - - - - Style: + + + + Qt::Horizontal - - - - - - - 0 - 0 - + + QSizePolicy::Fixed - + + + 17 + 24 + + + - - - - Color: + + + + + + + Qt::Vertical - + + QSizePolicy::Fixed + + + + 20 + 18 + + + - + @@ -808,32 +866,8 @@ - - - - Width: - - - - - - - pt - - - 0.500000000000000 - - - - - - - Length: - - - - - + + pt @@ -842,15 +876,8 @@ - - - - Opacity: - - - - - + + 0 @@ -863,6 +890,9 @@ % + + + 0 @@ -877,49 +907,44 @@ - - - - Qt::Vertical - - - - 48 - 301 - + + + + + 0 + 0 + - + - - - - - 75 - true - - + + + + + - Major ticks + Length: - - - - - 75 - true - - + + - Minor ticks + Width: - - + + - Direction: + Increment: + + + + + + + 999999999999999.000000000000000 @@ -1138,10 +1163,10 @@ ° - -360 + -180 - 360 + 180 10 @@ -1473,16 +1498,16 @@ - - KComboBox - QComboBox -
kcombobox.h
-
KFontRequester QWidget
kfontrequester.h
+ + KComboBox + QComboBox +
kcombobox.h
+
KColorButton QPushButton