mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-17 19:36:15 +00:00
profile: start with "absolutizing" the profile layout
The chart items were laid out in relative terms with respect to a fixed scene size (100.0, 100.0). This simply does not cut it when resizing the chart. Why should the axes always occupy the same fraction of the chart independent of the size. Moreover, this led to basically unmaintainable code. Resize the scene according to the viewport and do absolute placement of the items. This breaks the layout, but at least now we have a chance to fix things somewhat reasonably. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
parent
99284a88f7
commit
d0beae59f9
7 changed files with 174 additions and 272 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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<typename T, class... Args>
|
||||
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<DiveCalculatedCeiling>(*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<DiveHeartrateItem>(*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<DiveCalculatedTissue>(*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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -6,8 +6,9 @@
|
|||
#include "core/event.h"
|
||||
#include "core/profile.h"
|
||||
#include <QPen>
|
||||
#include <QFontMetrics>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue