diff --git a/profile-widget/divecartesianaxis.cpp b/profile-widget/divecartesianaxis.cpp index 008d329a6..ef7bcf585 100644 --- a/profile-widget/divecartesianaxis.cpp +++ b/profile-widget/divecartesianaxis.cpp @@ -63,7 +63,6 @@ DiveCartesianAxis::DiveCartesianAxis(Position position, color_index_t gridColor, textVisibility(true), lineVisibility(true), labelScale(1.0), - line_size(1), changed(true), dpr(dpr) { @@ -74,12 +73,6 @@ DiveCartesianAxis::~DiveCartesianAxis() { } -void DiveCartesianAxis::setLineSize(qreal lineSize) -{ - line_size = lineSize; - changed = true; -} - void DiveCartesianAxis::setOrientation(Orientation o) { orientation = o; @@ -157,7 +150,7 @@ void DiveCartesianAxis::updateTicks(int animSpeed) emptyList(labels, steps, animSpeed); emptyList(lines, steps, animSpeed); - // Move the remaining ticks / text to their correct positions + // Move the remaining grid lines / labels to their correct positions // regarding the possible new values for the axis qreal begin, stepSize; if (orientation == TopToBottom) { @@ -176,56 +169,78 @@ void DiveCartesianAxis::updateTicks(int animSpeed) stepSize /= stepsInRange; for (int i = 0, count = labels.size(); i < count; i++, currValueText += interval) { - qreal childPos = (orientation == TopToBottom || orientation == LeftToRight) ? + double childPos = (orientation == TopToBottom || orientation == LeftToRight) ? begin + i * stepSize : begin - i * stepSize; labels[i]->set(textForValue(currValueText), colorForValue(currValueText)); - if (orientation == LeftToRight || orientation == RightToLeft) { - Animations::moveTo(labels[i], animSpeed, childPos, m.y1() + tick_size); - } else { - Animations::moveTo(labels[i], animSpeed ,m.x1() - tick_size, childPos); + switch (position) { + default: + case Position::Bottom: + Animations::moveTo(labels[i], animSpeed, childPos, rect.bottom() + labelSpaceVertical * dpr); + break; + case Position::Left: + Animations::moveTo(labels[i], animSpeed, rect.left() - labelSpaceHorizontal * dpr, childPos); + break; + case Position::Right: + Animations::moveTo(labels[i], animSpeed, rect.right() + labelSpaceHorizontal * dpr, childPos); + break; } } for (int i = 0, count = lines.size(); i < count; i++, currValueLine += interval) { - qreal childPos = (orientation == TopToBottom || orientation == LeftToRight) ? + double childPos = (orientation == TopToBottom || orientation == LeftToRight) ? begin + i * stepSize : begin - i * stepSize; - if (orientation == LeftToRight || orientation == RightToLeft) { - Animations::moveTo(lines[i], animSpeed, childPos, m.y1()); + if (position == Position::Bottom) { + // Fix size in case the scene changed + QLineF old = lines[i]->line(); + lines[i]->setLine(old.x1(), old.y1(), old.x1(), old.y1() + rect.height()); + Animations::moveTo(lines[i], animSpeed, childPos, rect.top()); } else { - Animations::moveTo(lines[i], animSpeed, m.x1(), childPos); + // Fix size in case the scene changed + QLineF old = lines[i]->line(); + lines[i]->setLine(old.x1(), old.y1(), old.x1() + rect.width(), old.y1()); + Animations::moveTo(lines[i], animSpeed, rect.left(), childPos); } } - // Add's the rest of the needed Ticks / Text. + // Add the rest of the needed labels. for (int i = labels.size(); i < steps; i++, currValueText += interval) { - qreal childPos; + double childPos; if (orientation == TopToBottom || orientation == LeftToRight) { childPos = begin + i * stepSize; } else { childPos = begin - i * stepSize; } - int alignFlags = orientation == RightToLeft || orientation == LeftToRight ? Qt::AlignBottom | Qt::AlignHCenter : - Qt::AlignVCenter | Qt::AlignLeft; + int alignFlags = position == Position::Bottom ? Qt::AlignTop | Qt::AlignHCenter : + position == Position::Left ? Qt::AlignVCenter | Qt::AlignLeft: + Qt::AlignVCenter | Qt::AlignRight; DiveTextItem *label = new DiveTextItem(dpr, labelScale, alignFlags, this); label->set(textForValue(currValueText), colorForValue(currValueText)); label->setZValue(1); labels.push_back(label); - if (orientation == RightToLeft || orientation == LeftToRight) { - label->setPos(scene.sceneRect().width() + 10, m.y1() + tick_size); // position it outside of the scene; - Animations::moveTo(label, animSpeed,childPos , m.y1() + tick_size); - } else { - label->setPos(m.x1() - tick_size, scene.sceneRect().height() + 10); - Animations::moveTo(label, animSpeed, m.x1() - tick_size, childPos); + switch (position) { + default: + case Position::Bottom: + label->setPos(scene.sceneRect().width() + 10, rect.bottom() + labelSpaceVertical * dpr); // position it outside of the scene; + Animations::moveTo(labels[i], animSpeed, childPos, rect.bottom() + labelSpaceVertical * dpr); + break; + case Position::Left: + label->setPos(rect.left() - labelSpaceHorizontal * dpr, scene.sceneRect().height() + 10); + Animations::moveTo(labels[i], animSpeed, rect.left() - labelSpaceHorizontal * dpr, childPos); + break; + case Position::Right: + label->setPos(rect.right() + labelSpaceHorizontal * dpr, scene.sceneRect().height() + 10); + Animations::moveTo(labels[i], animSpeed, rect.right() + labelSpaceHorizontal * dpr, childPos); + break; } } - // Add's the rest of the needed Ticks / Text. + // Add the rest of the needed grid lines. for (int i = lines.size(); i < steps; i++, currValueText += interval) { - qreal childPos; + double childPos; if (orientation == TopToBottom || orientation == LeftToRight) { childPos = begin + i * stepSize; } else { @@ -237,16 +252,14 @@ void DiveCartesianAxis::updateTicks(int animSpeed) 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, animSpeed, childPos, m.y1()); + if (position == Position::Bottom) { + line->setLine(0.0, 0.0, 0.0, rect.height()); + line->setPos(scene.sceneRect().width() + 10, rect.top()); // position it outside of the scene); + Animations::moveTo(line, animSpeed, childPos, rect.top()); } 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, animSpeed, m.x1(), childPos); + line->setLine(0.0, 0.0, rect.width(), 0.0); + line->setPos(rect.left(), scene.sceneRect().height() + 10); + Animations::moveTo(line, animSpeed, rect.left(), childPos); } } @@ -263,9 +276,21 @@ void DiveCartesianAxis::setLine(const QLineF &line) changed = true; } -void DiveCartesianAxis::animateChangeLine(const QLineF &newLine, int animSpeed) +void DiveCartesianAxis::animateChangeLine(const QRectF &rectIn, int animSpeed) { - setLine(newLine); + rect = rectIn; + switch (position) { + case Position::Left: + setLine(QLineF(rect.topLeft(), rect.bottomLeft())); + break; + case Position::Right: + setLine(QLineF(rect.topRight(), rect.bottomRight())); + break; + case Position::Bottom: + default: + setLine(QLineF(rect.bottomLeft(), rect.bottomRight())); + break; + } updateTicks(animSpeed); sizeChanged(); } @@ -380,6 +405,7 @@ QString TimeAxis::textForValue(double value) const return QString::number(nr); } +// TODO: replace by real dynamic axis - this is just weird. void TimeAxis::updateTicks(int animSpeed) { DiveCartesianAxis::updateTicks(animSpeed); diff --git a/profile-widget/divecartesianaxis.h b/profile-widget/divecartesianaxis.h index bf50a9dd8..e067d30e0 100644 --- a/profile-widget/divecartesianaxis.h +++ b/profile-widget/divecartesianaxis.h @@ -46,10 +46,9 @@ public: qreal posAtValue(qreal value) const; void setColor(const QColor &color); void setTextColor(const QColor &color); - void animateChangeLine(const QLineF &newLine, int animSpeed); + void animateChangeLine(const QRectF &rect, int animSpeed); void setTextVisible(bool arg1); void setLinesVisible(bool arg1); - void setLineSize(qreal lineSize); void setLine(const QLineF& line); virtual void updateTicks(int animSpeed); double width() const; // only for vertical axes @@ -60,6 +59,7 @@ signals: protected: Position position; + QRectF rect; // Rectangle to fill with grid lines color_index_t gridColor; ProfileScene &scene; virtual QString textForValue(double value) const; @@ -76,7 +76,6 @@ protected: bool textVisibility; bool lineVisibility; double labelScale; - qreal line_size; bool changed; double dpr; }; diff --git a/profile-widget/profilescene.cpp b/profile-widget/profilescene.cpp index a4a8e4db2..305b20b5b 100644 --- a/profile-widget/profilescene.cpp +++ b/profile-widget/profilescene.cpp @@ -15,32 +15,7 @@ #include "qt-models/diveplotdatamodel.h" #include "qt-models/diveplannermodel.h" -const static struct ProfileItemPos { - struct Pos { - QPointF on; - QPointF off; - }; - struct Axis : public Pos { - QLineF shrinked; - QLineF expanded; - QLineF intermediate; - }; - Pos dcLabel; - Pos tankBar; - Axis depth; - Axis partialPressure; - Axis partialPressureTissue; - Axis partialPressureWithTankBar; - Axis percentage; - Axis percentageWithTankBar; - Axis time; - Axis cylinder; - Axis temperature; - Axis temperatureAll; - Axis heartBeat; - Axis heartBeatWithTankBar; - ProfileItemPos(); -} itemPos; +static const double diveComputerTextBorder = 1.0; template T *ProfileScene::createItem(const DiveCartesianAxis &vAxis, int vColumn, int z, Args&&... args) @@ -92,7 +67,7 @@ ProfileScene::ProfileScene(double dpr, bool printMode, bool isGrayscale) : ccrsensor3GasItem(createPPGas(DivePlotDataModel::CCRSENSOR3, CCRSENSOR3, PO2_ALERT, &prefs.pp_graphs.po2_threshold_min, &prefs.pp_graphs.po2_threshold_max)), ocpo2GasItem(createPPGas(DivePlotDataModel::SCR_OC_PO2, SCR_OCPO2, PO2_ALERT, &prefs.pp_graphs.po2_threshold_min, &prefs.pp_graphs.po2_threshold_max)), diveCeiling(createItem(*profileYAxis, DivePlotDataModel::CEILING, 1, dpr)), - decoModelParameters(new DiveTextItem(dpr, 1.0, Qt::AlignHCenter | Qt::AlignBottom, nullptr)), + decoModelParameters(new DiveTextItem(dpr, 1.0, Qt::AlignHCenter | Qt::AlignTop, nullptr)), heartBeatItem(createItem(*heartBeatAxis, DivePlotDataModel::HEARTBEAT, 1, dpr)), tankItem(new TankItem(*timeAxis, dpr)) { @@ -106,9 +81,7 @@ ProfileScene::ProfileScene(double dpr, bool printMode, bool isGrayscale) : profileYAxis->setMinimum(0); profileYAxis->setTickInterval(M_OR_FT(10, 30)); profileYAxis->setTickSize(0.5); - profileYAxis->setLineSize(96); - timeAxis->setLineSize(92); timeAxis->setTickSize(-0.5); gasYAxis->setOrientation(DiveCartesianAxis::BottomToTop); @@ -116,20 +89,17 @@ ProfileScene::ProfileScene(double dpr, bool printMode, bool isGrayscale) : gasYAxis->setTickSize(1); gasYAxis->setMinimum(0); gasYAxis->setFontLabelScale(0.7); - gasYAxis->setLineSize(96); #ifndef SUBSURFACE_MOBILE heartBeatAxis->setOrientation(DiveCartesianAxis::BottomToTop); heartBeatAxis->setTickSize(0.2); heartBeatAxis->setTickInterval(10); heartBeatAxis->setFontLabelScale(0.7); - heartBeatAxis->setLineSize(96); percentageAxis->setOrientation(DiveCartesianAxis::BottomToTop); percentageAxis->setTickSize(0.2); percentageAxis->setTickInterval(10); percentageAxis->setFontLabelScale(0.7); - percentageAxis->setLineSize(96); #endif temperatureAxis->setOrientation(DiveCartesianAxis::BottomToTop); @@ -154,14 +124,6 @@ ProfileScene::ProfileScene(double dpr, bool printMode, bool isGrayscale) : gasYAxis->setZValue(timeAxis->zValue() + 1); tankItem->setZValue(100); - // show the deco model parameters at the top in the center - decoModelParameters->setY(0); - decoModelParameters->setX(50); - - diveComputerText->setPos(itemPos.dcLabel.on); - - tankItem->setPos(itemPos.tankBar.on); - for (int i = 0; i < 16; i++) { DiveCalculatedTissue *tissueItem = createItem(*profileYAxis, DivePlotDataModel::TISSUE_1 + i, i + 1, dpr); allTissues.append(tissueItem); @@ -231,7 +193,7 @@ void ProfileScene::updateVisibility() heartBeatItem->setVisible(prefs.hrgraph); #endif diveCeiling->setVisible(prefs.calcceiling); - decoModelParameters->setVisible(prefs.calcceiling); + decoModelParameters->setVisible(prefs.decoinfo); #ifndef SUBSURFACE_MOBILE for (DiveCalculatedTissue *tissue: allTissues) tissue->setVisible(prefs.calcalltissues && prefs.calcceiling); @@ -243,71 +205,99 @@ void ProfileScene::updateVisibility() tankItem->setVisible(prefs.tankbar); } +void ProfileScene::resize(QSizeF size) +{ + setSceneRect(QRectF(QPointF(), size)); + updateAxes(true); // disable animations when resizing +} + +// Helper structure for laying out secondary plots. +struct VerticalAxisLayout { + DiveCartesianAxis *axis; + double height; + bool visible; +}; + void ProfileScene::updateAxes(bool instant) { int animSpeed = instant || printMode ? 0 : qPrefDisplay::animation_speed(); - profileYAxis->setPos(itemPos.depth.on); + // Calculate left and right border needed for the axes. + // viz. the depth axis to the left and the partial pressure axis to the right. + // Thus, calculating the "border" of the graph is trivial. + double leftBorder = profileYAxis->width(); + if (prefs.hrgraph) + leftBorder = std::max(leftBorder, heartBeatAxis->width()); + double rightWidth = ppGraphsEnabled() ? gasYAxis->width() : 0.0; + double rightBorder = sceneRect().width() - rightWidth; + double width = rightBorder - leftBorder; -#ifndef SUBSURFACE_MOBILE - gasYAxis->update(animSpeed); // Initialize ticks of partial pressure graph - if ((prefs.percentagegraph||prefs.hrgraph) && ppGraphsEnabled()) { - profileYAxis->animateChangeLine(itemPos.depth.shrinked, animSpeed); - temperatureAxis->setPos(itemPos.temperatureAll.on); - temperatureAxis->animateChangeLine(itemPos.temperature.shrinked, animSpeed); - cylinderPressureAxis->animateChangeLine(itemPos.cylinder.shrinked, animSpeed); + if (width <= 10.0 * dpr) + return clear(); - if (prefs.tankbar) { - percentageAxis->setPos(itemPos.percentageWithTankBar.on); - percentageAxis->animateChangeLine(itemPos.percentageWithTankBar.expanded, animSpeed); - heartBeatAxis->setPos(itemPos.heartBeatWithTankBar.on); - heartBeatAxis->animateChangeLine(itemPos.heartBeatWithTankBar.expanded, animSpeed); - } else { - percentageAxis->setPos(itemPos.percentage.on); - percentageAxis->animateChangeLine(itemPos.percentage.expanded, animSpeed); - heartBeatAxis->setPos(itemPos.heartBeat.on); - heartBeatAxis->animateChangeLine(itemPos.heartBeat.expanded, animSpeed); - } - gasYAxis->setPos(itemPos.partialPressureTissue.on); - gasYAxis->animateChangeLine(itemPos.partialPressureTissue.expanded, animSpeed); - } else if (ppGraphsEnabled() || prefs.hrgraph || prefs.percentagegraph) { - profileYAxis->animateChangeLine(itemPos.depth.intermediate, animSpeed); - temperatureAxis->setPos(itemPos.temperature.on); - temperatureAxis->animateChangeLine(itemPos.temperature.intermediate, animSpeed); - cylinderPressureAxis->animateChangeLine(itemPos.cylinder.intermediate, animSpeed); - if (prefs.tankbar) { - percentageAxis->setPos(itemPos.percentageWithTankBar.on); - percentageAxis->animateChangeLine(itemPos.percentageWithTankBar.expanded, animSpeed); - gasYAxis->setPos(itemPos.partialPressureWithTankBar.on); - gasYAxis->animateChangeLine(itemPos.partialPressureWithTankBar.expanded, animSpeed); - heartBeatAxis->setPos(itemPos.heartBeatWithTankBar.on); - heartBeatAxis->animateChangeLine(itemPos.heartBeatWithTankBar.expanded, animSpeed); - } else { - gasYAxis->setPos(itemPos.partialPressure.on); - gasYAxis->animateChangeLine(itemPos.partialPressure.expanded, animSpeed); - percentageAxis->setPos(itemPos.percentage.on); - percentageAxis->animateChangeLine(itemPos.percentage.expanded, animSpeed); - heartBeatAxis->setPos(itemPos.heartBeat.on); - heartBeatAxis->animateChangeLine(itemPos.heartBeat.expanded, animSpeed); - } - } else { -#else - { -#endif - profileYAxis->animateChangeLine(itemPos.depth.expanded, animSpeed); - if (prefs.tankbar) { - temperatureAxis->setPos(itemPos.temperatureAll.on); - } else { - temperatureAxis->setPos(itemPos.temperature.on); - } - temperatureAxis->animateChangeLine(itemPos.temperature.expanded, animSpeed); - cylinderPressureAxis->animateChangeLine(itemPos.cylinder.expanded, animSpeed); + // Place the fixed dive computer text at the bottom + double bottomBorder = sceneRect().height() - diveComputerText->height() - 2.0 * dpr * diveComputerTextBorder; + diveComputerText->setPos(0.0, bottomBorder + dpr * diveComputerTextBorder); + + double topBorder = 0.0; + + // show the deco model parameters at the top in the center + if (prefs.decoinfo) { + decoModelParameters->setPos(leftBorder + width / 2.0, topBorder); + topBorder += decoModelParameters->height(); } - timeAxis->setPos(itemPos.time.on); - timeAxis->setLine(itemPos.time.expanded); + bottomBorder -= timeAxis->height(); + timeAxis->animateChangeLine(QRectF(leftBorder, topBorder, width, bottomBorder - topBorder), animSpeed); - cylinderPressureAxis->setPos(itemPos.cylinder.on); + if (prefs.tankbar) { + bottomBorder -= tankItem->height(); + // Note: we set x to 0.0, because the tank item uses the timeAxis to set the x-coordinate. + tankItem->setPos(0.0, bottomBorder); + } + + double height = bottomBorder - topBorder; + if (height <= 50.0 * dpr) + return clear(); + + // The rest is laid out dynamically. Give at least 50% to the actual profile. + // The max heights are given for DPR=1, i.e. a ca. 800x600 pixels profile. + const double minProfileFraction = 0.5; + VerticalAxisLayout secondaryAxes[] = { + // Note: axes are listed from bottom to top, since they are added that way. + { heartBeatAxis, 75.0, prefs.hrgraph }, + { percentageAxis, 50.0, prefs.percentagegraph }, + { gasYAxis, 75.0, ppGraphsEnabled() }, + { temperatureAxis, 50.0, true }, + }; + + // A loop is probably easier to read than std::accumulate. + double totalSecondaryHeight = 0.0; + for (const VerticalAxisLayout &l: secondaryAxes) { + if (l.visible) + totalSecondaryHeight += l.height * dpr; + } + + if (totalSecondaryHeight > height * minProfileFraction) { + // Use 50% for the profile and the rest for the remaining graphs, scaled by their maximum height. + double remainingSpace = height * minProfileFraction; + for (VerticalAxisLayout &l: secondaryAxes) + l.height *= remainingSpace / totalSecondaryHeight; + } + + for (const VerticalAxisLayout &l: secondaryAxes) { + l.axis->setVisible(l.visible); + if (!l.visible) + continue; + bottomBorder -= l.height * dpr; + l.axis->animateChangeLine(QRectF(leftBorder, bottomBorder, width, l.height * dpr), animSpeed); + } + + height = bottomBorder - topBorder; + profileYAxis->animateChangeLine(QRectF(leftBorder, topBorder, width, height), animSpeed); + + // The cylinders are displayed in the 24-80% region of the profile + cylinderPressureAxis->animateChangeLine(QRectF(leftBorder, topBorder + 0.24 * height, width, 0.56 * height), animSpeed); } bool ProfileScene::isPointOutOfBoundaries(const QPointF &point) const @@ -320,123 +310,6 @@ bool ProfileScene::isPointOutOfBoundaries(const QPointF &point) const ypos < profileYAxis->minimum(); } -ProfileItemPos::ProfileItemPos() -{ - // Scene is *always* (double) 100 / 100. - // TODO: The relative scaling doesn't work well with large or small - // profiles and needs to be fixed. - - dcLabel.on.setX(3); - dcLabel.on.setY(100); - dcLabel.off.setX(-10); - dcLabel.off.setY(100); - - tankBar.on.setX(0); -#ifndef SUBSURFACE_MOBILE - tankBar.on.setY(91.95); -#else - tankBar.on.setY(86.4); -#endif - - //Depth Axis Config - depth.on.setX(3); - depth.on.setY(3); - depth.off.setX(-2); - depth.off.setY(3); - depth.expanded.setP1(QPointF(0, 0)); -#ifndef SUBSURFACE_MOBILE - depth.expanded.setP2(QPointF(0, 85)); -#else - depth.expanded.setP2(QPointF(0, 65)); -#endif - depth.shrinked.setP1(QPointF(0, 0)); - depth.shrinked.setP2(QPointF(0, 55)); - depth.intermediate.setP1(QPointF(0, 0)); - depth.intermediate.setP2(QPointF(0, 65)); - - // Time Axis Config - time.on.setX(3); -#ifndef SUBSURFACE_MOBILE - time.on.setY(95); -#else - time.on.setY(89.5); -#endif - time.off.setX(3); - time.off.setY(110); - time.expanded.setP1(QPointF(0, 0)); - time.expanded.setP2(QPointF(94, 0)); - - // Partial Gas Axis Config - partialPressure.on.setX(97); -#ifndef SUBSURFACE_MOBILE - partialPressure.on.setY(75); -#else - partialPressure.on.setY(70); -#endif - partialPressure.off.setX(110); - partialPressure.off.setY(63); - partialPressure.expanded.setP1(QPointF(0, 0)); -#ifndef SUBSURFACE_MOBILE - partialPressure.expanded.setP2(QPointF(0, 19)); -#else - partialPressure.expanded.setP2(QPointF(0, 20)); -#endif - partialPressureWithTankBar = partialPressure; - partialPressureWithTankBar.expanded.setP2(QPointF(0, 17)); - partialPressureTissue = partialPressure; - partialPressureTissue.on.setX(97); - partialPressureTissue.on.setY(65); - partialPressureTissue.expanded.setP2(QPointF(0, 16)); - - // cylinder axis config - cylinder.on.setX(3); - cylinder.on.setY(20); - cylinder.off.setX(-10); - cylinder.off.setY(20); - cylinder.expanded.setP1(QPointF(0, 15)); - cylinder.expanded.setP2(QPointF(0, 50)); - cylinder.shrinked.setP1(QPointF(0, 0)); - cylinder.shrinked.setP2(QPointF(0, 20)); - cylinder.intermediate.setP1(QPointF(0, 0)); - cylinder.intermediate.setP2(QPointF(0, 20)); - - // Temperature axis config - temperature.on.setX(3); - temperature.off.setX(-10); - temperature.off.setY(40); - temperature.expanded.setP1(QPointF(0, 20)); - temperature.expanded.setP2(QPointF(0, 33)); - temperature.shrinked.setP1(QPointF(0, 2)); - temperature.shrinked.setP2(QPointF(0, 12)); -#ifndef SUBSURFACE_MOBILE - temperature.on.setY(60); - temperatureAll.on.setY(51); - temperature.intermediate.setP1(QPointF(0, 2)); - temperature.intermediate.setP2(QPointF(0, 12)); -#else - temperature.on.setY(51); - temperatureAll.on.setY(47); - temperature.intermediate.setP1(QPointF(0, 2)); - temperature.intermediate.setP2(QPointF(0, 12)); -#endif - - // Heart rate axis config - heartBeat.on.setX(3); - heartBeat.on.setY(82); - heartBeat.expanded.setP1(QPointF(0, 0)); - heartBeat.expanded.setP2(QPointF(0, 10)); - heartBeatWithTankBar = heartBeat; - heartBeatWithTankBar.expanded.setP2(QPointF(0, 7)); - - // Percentage axis config - percentage.on.setX(3); - percentage.on.setY(80); - percentage.expanded.setP1(QPointF(0, 0)); - percentage.expanded.setP2(QPointF(0, 15)); - percentageWithTankBar = percentage; - percentageWithTankBar.expanded.setP2(QPointF(0, 11.9)); -} - void ProfileScene::plotDive(const struct dive *dIn, int dcIn, DivePlannerPointsModel *plannerModel, bool inPlanner, bool instant, bool calcMax) { d = dIn; @@ -530,7 +403,7 @@ void ProfileScene::plotDive(const struct dive *dIn, int dcIn, DivePlannerPointsM heartBeatAxis->setMinimum(heartBeatAxisMin); heartBeatAxis->setMaximum(heartBeatAxisMax + 1); heartBeatAxis->setTickInterval(heartBeatAxisTick); - heartBeatAxis->updateTicks(animSpeed); + heartBeatAxis->updateTicks(animSpeed); // this shows the ticks } heartBeatAxis->setVisible(prefs.hrgraph && plotInfo.maxhr); @@ -564,9 +437,6 @@ void ProfileScene::plotDive(const struct dive *dIn, int dcIn, DivePlannerPointsM #ifdef SUBSURFACE_MOBILE if (currentdc->divemode == CCR) { - gasYAxis->setPos(itemPos.partialPressure.on); - gasYAxis->setLine(itemPos.partialPressure.expanded); - tankItem->setVisible(false); pn2GasItem->setVisible(false); po2GasItem->setVisible(prefs.pp_graphs.po2); @@ -588,7 +458,6 @@ void ProfileScene::plotDive(const struct dive *dIn, int dcIn, DivePlannerPointsM temperatureItem->setVisible(false); } else { tankItem->setVisible(prefs.tankbar); - gasYAxis->setPos(itemPos.partialPressure.off); pn2GasItem->setVisible(false); po2GasItem->setVisible(false); pheGasItem->setVisible(false); diff --git a/profile-widget/profilescene.h b/profile-widget/profilescene.h index 1277fb466..6749183bd 100644 --- a/profile-widget/profilescene.h +++ b/profile-widget/profilescene.h @@ -39,6 +39,7 @@ public: ProfileScene(double dpr, bool printMode, bool isGrayscale); ~ProfileScene(); + void resize(QSizeF size); void updateAxes(bool instant); // Update axes according to preferences void clear(); bool isPointOutOfBoundaries(const QPointF &point) const; diff --git a/profile-widget/profilewidget2.cpp b/profile-widget/profilewidget2.cpp index e826fc23f..fbc72b07f 100644 --- a/profile-widget/profilewidget2.cpp +++ b/profile-widget/profilewidget2.cpp @@ -270,7 +270,8 @@ void ProfileWidget2::settingsChanged() void ProfileWidget2::resizeEvent(QResizeEvent *event) { QGraphicsView::resizeEvent(event); - fitInView(sceneRect(), Qt::IgnoreAspectRatio); + profileScene->resize(viewport()->size()); + plotDive(d, dc, false, true); // disable animation on resize events } #ifndef SUBSURFACE_MOBILE diff --git a/profile-widget/tankitem.cpp b/profile-widget/tankitem.cpp index e74a3f128..f2a87aaa4 100644 --- a/profile-widget/tankitem.cpp +++ b/profile-widget/tankitem.cpp @@ -6,8 +6,9 @@ #include "core/event.h" #include "core/profile.h" #include +#include -static const qreal height = 3.0; +static const double border = 1.0; TankItem::TankItem(const DiveCartesianAxis &axis, double dpr) : hAxis(axis), @@ -18,14 +19,14 @@ TankItem::TankItem(const DiveCartesianAxis &axis, double dpr) : QColor blue(AIR_BLUE); QColor yellow(NITROX_YELLOW); QColor green(NITROX_GREEN); - QLinearGradient nitroxGradient(QPointF(0, 0), QPointF(0, height)); + QLinearGradient nitroxGradient(QPointF(0, 0), QPointF(0, height())); nitroxGradient.setColorAt(0.0, green); nitroxGradient.setColorAt(0.49, green); nitroxGradient.setColorAt(0.5, yellow); nitroxGradient.setColorAt(1.0, yellow); nitrox = nitroxGradient; oxygen = green; - QLinearGradient trimixGradient(QPointF(0, 0), QPointF(0, height)); + QLinearGradient trimixGradient(QPointF(0, 0), QPointF(0, height())); trimixGradient.setColorAt(0.0, green); trimixGradient.setColorAt(0.49, green); trimixGradient.setColorAt(0.5, red); @@ -34,13 +35,20 @@ TankItem::TankItem(const DiveCartesianAxis &axis, double dpr) : air = blue; } +double TankItem::height() const +{ + QFont fnt = DiveTextItem::getFont(dpr, 1.0); + QFontMetrics fm(fnt); + return fm.height() + 2.0 * border * dpr; +} + void TankItem::createBar(int startTime, int stopTime, struct gasmix gas) { qreal x = hAxis.posAtValue(startTime); qreal w = hAxis.posAtValue(stopTime) - hAxis.posAtValue(startTime); // pick the right gradient, size, position and text - QGraphicsRectItem *rect = new QGraphicsRectItem(x, 0, w, height, this); + QGraphicsRectItem *rect = new QGraphicsRectItem(x, 0, w, height(), this); if (gasmix_is_air(gas)) rect->setBrush(air); else if (gas.he.permille) @@ -51,12 +59,9 @@ void TankItem::createBar(int startTime, int stopTime, struct gasmix gas) rect->setBrush(nitrox); rect->setPen(QPen(QBrush(), 0.0)); // get rid of the thick line around the rectangle rects.push_back(rect); - DiveTextItem *label = new DiveTextItem(dpr, 1.0, Qt::AlignBottom | Qt::AlignRight, rect); + DiveTextItem *label = new DiveTextItem(dpr, 1.0, Qt::AlignVCenter | Qt::AlignRight, rect); label->set(gasname(gas), Qt::black); - label->setPos(x + 1, 0); -#ifdef SUBSURFACE_MOBILE - label->setPos(x + 1, -2.5); -#endif + label->setPos(x + 2.0 * dpr, height() / 2.0); label->setZValue(101); } diff --git a/profile-widget/tankitem.h b/profile-widget/tankitem.h index 2c96f20dd..526b91edd 100644 --- a/profile-widget/tankitem.h +++ b/profile-widget/tankitem.h @@ -15,6 +15,7 @@ class TankItem : public QGraphicsRectItem public: explicit TankItem(const DiveCartesianAxis &axis, double dpr); void setData(const struct plot_info *plotInfo, const struct dive *d); + double height() const; private: void createBar(int startTime, int stopTime, struct gasmix gas);