diff options
Diffstat (limited to 'desktop-widgets/profile/divecartesianaxis.cpp')
-rw-r--r-- | desktop-widgets/profile/divecartesianaxis.cpp | 459 |
1 files changed, 459 insertions, 0 deletions
diff --git a/desktop-widgets/profile/divecartesianaxis.cpp b/desktop-widgets/profile/divecartesianaxis.cpp new file mode 100644 index 000000000..bf5a5380c --- /dev/null +++ b/desktop-widgets/profile/divecartesianaxis.cpp @@ -0,0 +1,459 @@ +#include "divecartesianaxis.h" +#include "divetextitem.h" +#include "helpers.h" +#include "preferences.h" +#include "diveplotdatamodel.h" +#include "animationfunctions.h" +#include "mainwindow.h" +#include "divelineitem.h" +#include "profilewidget2.h" + +QPen DiveCartesianAxis::gridPen() +{ + QPen pen; + pen.setColor(getColor(TIME_GRID)); + /* cosmetic width() == 0 for lines in printMode + * having setCosmetic(true) and width() > 0 does not work when + * printing on OSX and Linux */ + pen.setWidth(DiveCartesianAxis::printMode ? 0 : 2); + pen.setCosmetic(true); + return pen; +} + +double DiveCartesianAxis::tickInterval() const +{ + return interval; +} + +double DiveCartesianAxis::tickSize() const +{ + return tick_size; +} + +void DiveCartesianAxis::setFontLabelScale(qreal scale) +{ + labelScale = scale; + changed = true; +} + +void DiveCartesianAxis::setPrintMode(bool mode) +{ + printMode = mode; + // update the QPen of all lines depending on printMode + QPen newPen = gridPen(); + QColor oldColor = pen().brush().color(); + newPen.setBrush(oldColor); + setPen(newPen); + Q_FOREACH (DiveLineItem *item, lines) + item->setPen(pen()); +} + +void DiveCartesianAxis::setMaximum(double maximum) +{ + if (IS_FP_SAME(max, maximum)) + return; + max = maximum; + changed = true; + emit maxChanged(); +} + +void DiveCartesianAxis::setMinimum(double minimum) +{ + if (IS_FP_SAME(min, minimum)) + return; + min = minimum; + changed = true; +} + +void DiveCartesianAxis::setTextColor(const QColor &color) +{ + textColor = color; +} + +DiveCartesianAxis::DiveCartesianAxis() : QObject(), + QGraphicsLineItem(), + printMode(false), + unitSystem(0), + orientation(LeftToRight), + min(0), + max(0), + interval(1), + tick_size(0), + textVisibility(true), + lineVisibility(true), + labelScale(1.0), + line_size(1), + changed(true) +{ + setPen(gridPen()); +} + +DiveCartesianAxis::~DiveCartesianAxis() +{ +} + +void DiveCartesianAxis::setLineSize(qreal lineSize) +{ + line_size = lineSize; + changed = true; +} + +void DiveCartesianAxis::setOrientation(Orientation o) +{ + orientation = o; + changed = true; +} + +QColor DiveCartesianAxis::colorForValue(double value) +{ + return QColor(Qt::black); +} + +void DiveCartesianAxis::setTextVisible(bool arg1) +{ + if (textVisibility == arg1) { + return; + } + textVisibility = arg1; + Q_FOREACH (DiveTextItem *item, labels) { + item->setVisible(textVisibility); + } +} + +void DiveCartesianAxis::setLinesVisible(bool arg1) +{ + if (lineVisibility == arg1) { + return; + } + lineVisibility = arg1; + Q_FOREACH (DiveLineItem *item, lines) { + item->setVisible(lineVisibility); + } +} + +template <typename T> +void emptyList(QList<T *> &list, double steps) +{ + if (!list.isEmpty() && list.size() > steps) { + while (list.size() > steps) { + T *removedItem = list.takeLast(); + Animations::animDelete(removedItem); + } + } +} + +void DiveCartesianAxis::updateTicks(color_indice_t color) +{ + if (!scene() || (!changed && !MainWindow::instance()->graphics()->getPrintMode())) + return; + QLineF m = line(); + // unused so far: + // QGraphicsView *view = scene()->views().first(); + double steps = (max - min) / interval; + double currValueText = min; + double currValueLine = min; + + if (steps < 1) + return; + + emptyList(labels, steps); + emptyList(lines, steps); + + // Move the remaining Ticks / Text to it's corerct position + // Regartind the possibly new values for the Axis + qreal begin, stepSize; + if (orientation == TopToBottom) { + begin = m.y1(); + stepSize = (m.y2() - m.y1()); + } else if (orientation == BottomToTop) { + begin = m.y2(); + stepSize = (m.y2() - m.y1()); + } else if (orientation == LeftToRight) { + begin = m.x1(); + stepSize = (m.x2() - m.x1()); + } else /* if (orientation == RightToLeft) */ { + begin = m.x2(); + stepSize = (m.x2() - m.x1()); + } + stepSize = stepSize / steps; + + for (int i = 0, count = labels.size(); i < count; i++, currValueText += interval) { + qreal childPos = (orientation == TopToBottom || orientation == LeftToRight) ? + begin + i * stepSize : + begin - i * stepSize; + + labels[i]->setText(textForValue(currValueText)); + if (orientation == LeftToRight || orientation == RightToLeft) { + Animations::moveTo(labels[i],childPos, m.y1() + tick_size); + } else { + Animations::moveTo(labels[i],m.x1() - tick_size, childPos); + } + } + + for (int i = 0, count = lines.size(); i < count; i++, currValueLine += interval) { + qreal childPos = (orientation == TopToBottom || orientation == LeftToRight) ? + begin + i * stepSize : + begin - i * stepSize; + + if (orientation == LeftToRight || orientation == RightToLeft) { + Animations::moveTo(lines[i],childPos, m.y1()); + } else { + Animations::moveTo(lines[i],m.x1(), childPos); + } + } + + // Add's the rest of the needed Ticks / Text. + for (int i = labels.size(); i < steps; i++, currValueText += interval) { + qreal childPos; + if (orientation == TopToBottom || orientation == LeftToRight) { + childPos = begin + i * stepSize; + } else { + childPos = begin - i * stepSize; + } + DiveTextItem *label = new DiveTextItem(this); + label->setText(textForValue(currValueText)); + label->setBrush(colorForValue(currValueText)); + label->setScale(fontLabelScale()); + label->setZValue(1); + labels.push_back(label); + if (orientation == RightToLeft || orientation == LeftToRight) { + label->setAlignment(Qt::AlignBottom | Qt::AlignHCenter); + label->setPos(scene()->sceneRect().width() + 10, m.y1() + tick_size); // position it outside of the scene); + Animations::moveTo(label,childPos, m.y1() + tick_size); + } else { + label->setAlignment(Qt::AlignVCenter | Qt::AlignLeft); + label->setPos(m.x1() - tick_size, scene()->sceneRect().height() + 10); + Animations::moveTo(label,m.x1() - tick_size, childPos); + } + } + + // Add's the rest of the needed Ticks / Text. + for (int i = lines.size(); i < steps; i++, currValueText += interval) { + qreal childPos; + if (orientation == TopToBottom || orientation == LeftToRight) { + childPos = begin + i * stepSize; + } else { + childPos = begin - i * stepSize; + } + DiveLineItem *line = new DiveLineItem(this); + QPen pen = gridPen(); + pen.setBrush(getColor(color)); + line->setPen(pen); + line->setZValue(0); + lines.push_back(line); + if (orientation == RightToLeft || orientation == LeftToRight) { + line->setLine(0, -line_size, 0, 0); + line->setPos(scene()->sceneRect().width() + 10, m.y1()); // position it outside of the scene); + Animations::moveTo(line,childPos, m.y1()); + } else { + QPointF p1 = mapFromScene(3, 0); + QPointF p2 = mapFromScene(line_size, 0); + line->setLine(p1.x(), 0, p2.x(), 0); + line->setPos(m.x1(), scene()->sceneRect().height() + 10); + Animations::moveTo(line,m.x1(), childPos); + } + } + + Q_FOREACH (DiveTextItem *item, labels) + item->setVisible(textVisibility); + Q_FOREACH (DiveLineItem *item, lines) + item->setVisible(lineVisibility); + changed = false; +} + +void DiveCartesianAxis::setLine(const QLineF &line) +{ + QGraphicsLineItem::setLine(line); + changed = true; +} + +void DiveCartesianAxis::animateChangeLine(const QLineF &newLine) +{ + setLine(newLine); + updateTicks(); + sizeChanged(); +} + +QString DiveCartesianAxis::textForValue(double value) +{ + return QString::number(value); +} + +void DiveCartesianAxis::setTickSize(qreal size) +{ + tick_size = size; +} + +void DiveCartesianAxis::setTickInterval(double i) +{ + interval = i; +} + +qreal DiveCartesianAxis::valueAt(const QPointF &p) const +{ + QLineF m = line(); + QPointF relativePosition = p; + relativePosition -= pos(); // normalize p based on the axis' offset on screen + + double retValue = (orientation == LeftToRight || orientation == RightToLeft) ? + max * (relativePosition.x() - m.x1()) / (m.x2() - m.x1()) : + max * (relativePosition.y() - m.y1()) / (m.y2() - m.y1()); + return retValue; +} + +qreal DiveCartesianAxis::posAtValue(qreal value) +{ + QLineF m = line(); + QPointF p = pos(); + + double size = max - min; + // unused for now: + // double distanceFromOrigin = value - min; + double percent = IS_FP_SAME(min, max) ? 0.0 : (value - min) / size; + + + double realSize = orientation == LeftToRight || orientation == RightToLeft ? + m.x2() - m.x1() : + m.y2() - m.y1(); + + // Inverted axis, just invert the percentage. + if (orientation == RightToLeft || orientation == BottomToTop) + percent = 1 - percent; + + double retValue = realSize * percent; + double adjusted = + orientation == LeftToRight ? retValue + m.x1() + p.x() : + orientation == RightToLeft ? retValue + m.x1() + p.x() : + orientation == TopToBottom ? retValue + m.y1() + p.y() : + /* entation == BottomToTop */ retValue + m.y1() + p.y(); + return adjusted; +} + +qreal DiveCartesianAxis::percentAt(const QPointF &p) +{ + qreal value = valueAt(p); + double size = max - min; + double percent = value / size; + return percent; +} + +double DiveCartesianAxis::maximum() const +{ + return max; +} + +double DiveCartesianAxis::minimum() const +{ + return min; +} + +double DiveCartesianAxis::fontLabelScale() const +{ + return labelScale; +} + +void DiveCartesianAxis::setColor(const QColor &color) +{ + QPen defaultPen = gridPen(); + defaultPen.setColor(color); + defaultPen.setJoinStyle(Qt::RoundJoin); + defaultPen.setCapStyle(Qt::RoundCap); + setPen(defaultPen); +} + +QString DepthAxis::textForValue(double value) +{ + if (value == 0) + return QString(); + return get_depth_string(value, false, false); +} + +QColor DepthAxis::colorForValue(double value) +{ + Q_UNUSED(value); + return QColor(Qt::red); +} + +DepthAxis::DepthAxis() +{ + connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), this, SLOT(settingsChanged())); + changed = true; + settingsChanged(); +} + +void DepthAxis::settingsChanged() +{ + static int unitSystem = prefs.units.length; + if ( unitSystem == prefs.units.length ) + return; + changed = true; + updateTicks(); + unitSystem = prefs.units.length; +} + +QColor TimeAxis::colorForValue(double value) +{ + Q_UNUSED(value); + return QColor(Qt::blue); +} + +QString TimeAxis::textForValue(double value) +{ + int nr = value / 60; + if (maximum() < 600) + return QString("%1:%2").arg(nr).arg((int)value % 60, 2, 10, QChar('0')); + return QString::number(nr); +} + +void TimeAxis::updateTicks() +{ + DiveCartesianAxis::updateTicks(); + if (maximum() > 600) { + for (int i = 0; i < labels.count(); i++) { + labels[i]->setVisible(i % 2); + } + } +} + +QString TemperatureAxis::textForValue(double value) +{ + return QString::number(mkelvin_to_C((int)value)); +} + +PartialGasPressureAxis::PartialGasPressureAxis() : + DiveCartesianAxis(), + model(NULL) +{ + connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), this, SLOT(settingsChanged())); +} + +void PartialGasPressureAxis::setModel(DivePlotDataModel *m) +{ + model = m; + connect(model, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(settingsChanged())); + settingsChanged(); +} + +void PartialGasPressureAxis::settingsChanged() +{ + bool showPhe = prefs.pp_graphs.phe; + bool showPn2 = prefs.pp_graphs.pn2; + bool showPo2 = prefs.pp_graphs.po2; + setVisible(showPhe || showPn2 || showPo2); + if (!model->rowCount()) + return; + + double max = showPhe ? model->pheMax() : -1; + if (showPn2 && model->pn2Max() > max) + max = model->pn2Max(); + if (showPo2 && model->po2Max() > max) + max = model->po2Max(); + + qreal pp = floor(max * 10.0) / 10.0 + 0.2; + if (IS_FP_SAME(maximum(), pp)) + return; + + setMaximum(pp); + setTickInterval(pp > 4 ? 0.5 : 0.25); + updateTicks(); +} |