profile: calculate maximum label sizes on construction

Instead of calculating the label sizes of the axes when
relayouting the chart, calculate them at construction time.

To do so, pass the digits before and after the decimal comma
to the constructor.

This is not so much an optimization thing, but rather an
first stab at more general label rendering. Time, of course,
will always be an exception. But hopefully the remaining
values can be done more generally.

Note that currently this code is a total mess. For example,
the labels for the temperature axes are not converted to
F if needed. And therefore also not shown. This will need
some major rethinking.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2021-09-20 21:13:19 +02:00 committed by Dirk Hohndel
parent f19ab2e4fd
commit 322e2baa8d
5 changed files with 44 additions and 32 deletions

View file

@ -18,7 +18,7 @@ void DiveCartesianAxis::setBounds(double minimum, double maximum)
max = maximum; max = maximum;
} }
DiveCartesianAxis::DiveCartesianAxis(Position position, color_index_t gridColor, double dpr, DiveCartesianAxis::DiveCartesianAxis(Position position, int integralDigits, int fractionalDigits, color_index_t gridColor, double dpr,
double labelScale, bool printMode, bool isGrayscale, ProfileScene &scene) : double labelScale, bool printMode, bool isGrayscale, ProfileScene &scene) :
printMode(printMode), printMode(printMode),
position(position), position(position),
@ -45,6 +45,26 @@ DiveCartesianAxis::DiveCartesianAxis(Position position, color_index_t gridColor,
pen.setBrush(getColor(gridColor, isGrayscale)); pen.setBrush(getColor(gridColor, isGrayscale));
gridPen = pen; gridPen = pen;
/* Create the longest expected label, e.g. 999.99. */
QString label;
label.reserve(integralDigits + fractionalDigits + 1);
for (int i = 0; i < integralDigits; ++i)
label.append('9');
if (fractionalDigits > 0) {
label.append('.');
for (int i = 0; i < fractionalDigits; ++i)
label.append('9');
}
/* Use the label to estimate size of the labels.
* Round up, because non-integers tend to give abysmal rendering.
*/
QFont fnt = DiveTextItem::getFont(dpr, labelScale);
double outlineSpace = DiveTextItem::outlineSpace(dpr);
QFontMetrics fm(fnt);
labelWidth = ceil(fm.size(Qt::TextSingleLine, label).width() + outlineSpace);
labelHeight = ceil(fm.height() + outlineSpace);
} }
DiveCartesianAxis::~DiveCartesianAxis() DiveCartesianAxis::~DiveCartesianAxis()
@ -93,23 +113,14 @@ void emptyList(QList<T *> &list, int steps, int speed)
} }
} }
double DiveCartesianAxis::textWidth(const QString &s) const
{
QFont fnt = DiveTextItem::getFont(dpr, labelScale);
QFontMetrics fm(fnt);
return fm.size(Qt::TextSingleLine, s).width() + labelSpaceHorizontal * dpr;
}
double DiveCartesianAxis::width() const double DiveCartesianAxis::width() const
{ {
return textWidth("999"); return labelWidth + labelSpaceHorizontal * dpr;
} }
double DiveCartesianAxis::height() const double DiveCartesianAxis::height() const
{ {
QFont fnt = DiveTextItem::getFont(dpr, labelScale); return labelHeight + labelSpaceVertical * dpr;
QFontMetrics fm(fnt);
return fm.height() + labelSpaceVertical * dpr;
} }
void DiveCartesianAxis::updateTicks(int animSpeed) void DiveCartesianAxis::updateTicks(int animSpeed)
@ -383,9 +394,10 @@ QString TemperatureAxis::textForValue(double value) const
return QString::number(mkelvin_to_C((int)value)); return QString::number(mkelvin_to_C((int)value));
} }
PartialGasPressureAxis::PartialGasPressureAxis(const DivePlotDataModel &model, Position position, color_index_t gridColor, PartialGasPressureAxis::PartialGasPressureAxis(const DivePlotDataModel &model, Position position, int integralDigits, int fractionalDigits,
double dpr, double labelScale, bool printMode, bool isGrayscale, ProfileScene &scene) : color_index_t gridColor, double dpr, double labelScale, bool printMode, bool isGrayscale,
DiveCartesianAxis(position, gridColor, dpr, labelScale, printMode, isGrayscale, scene), ProfileScene &scene) :
DiveCartesianAxis(position, integralDigits, fractionalDigits, gridColor, dpr, labelScale, printMode, isGrayscale, scene),
model(model) model(model)
{ {
} }
@ -413,8 +425,3 @@ void PartialGasPressureAxis::update(int animSpeed)
setTickInterval(pp > 4 ? 0.5 : 0.25); setTickInterval(pp > 4 ? 0.5 : 0.25);
updateTicks(animSpeed); updateTicks(animSpeed);
} }
double PartialGasPressureAxis::width() const
{
return textWidth(textForValue(0.99));
}

View file

@ -32,7 +32,7 @@ public:
enum class Position { enum class Position {
Left, Right, Bottom Left, Right, Bottom
}; };
DiveCartesianAxis(Position position, color_index_t gridColor, double dpr, DiveCartesianAxis(Position position, int integralDigits, int fractionalDigits, color_index_t gridColor, double dpr,
double labelScale, bool printMode, bool isGrayscale, ProfileScene &scene); double labelScale, bool printMode, bool isGrayscale, ProfileScene &scene);
~DiveCartesianAxis(); ~DiveCartesianAxis();
void setBounds(double min, double max); void setBounds(double min, double max);
@ -62,7 +62,6 @@ protected:
ProfileScene &scene; ProfileScene &scene;
virtual QString textForValue(double value) const; virtual QString textForValue(double value) const;
virtual QColor colorForValue(double value) const; virtual QColor colorForValue(double value) const;
double textWidth(const QString &s) const;
Orientation orientation; Orientation orientation;
QList<DiveTextItem *> labels; QList<DiveTextItem *> labels;
QList<DiveLineItem *> lines; QList<DiveLineItem *> lines;
@ -74,6 +73,7 @@ protected:
double labelScale; double labelScale;
bool changed; bool changed;
double dpr; double dpr;
double labelWidth, labelHeight; // maximum expected sizes of label width and height
}; };
class DepthAxis : public DiveCartesianAxis { class DepthAxis : public DiveCartesianAxis {
@ -106,10 +106,9 @@ private:
class PartialGasPressureAxis : public DiveCartesianAxis { class PartialGasPressureAxis : public DiveCartesianAxis {
Q_OBJECT Q_OBJECT
public: public:
PartialGasPressureAxis(const DivePlotDataModel &model, Position position, color_index_t gridColor, PartialGasPressureAxis(const DivePlotDataModel &model, Position position, int integralDigits, int fractionalDigits,
double dpr, double labelScale, bool printMode, bool isGrayscale, ProfileScene &scene); color_index_t gridColor, double dpr, double labelScale, bool printMode, bool isGrayscale, ProfileScene &scene);
void update(int animSpeed); void update(int animSpeed);
double width() const;
private: private:
const DivePlotDataModel &model; const DivePlotDataModel &model;
}; };

View file

@ -82,6 +82,11 @@ QFont DiveTextItem::getFont(double dpr, double scale)
return fnt; return fnt;
} }
double DiveTextItem::outlineSpace(double dpr)
{
return 2.0 * outlineSize * dpr; // Double because outline growths to both sides.
}
double DiveTextItem::fontHeight(double dpr, double scale) double DiveTextItem::fontHeight(double dpr, double scale)
{ {
QFont fnt = getFont(dpr, scale); QFont fnt = getFont(dpr, scale);

View file

@ -22,6 +22,7 @@ public:
const QString &text(); const QString &text();
static QFont getFont(double dpr, double scale); static QFont getFont(double dpr, double scale);
static double fontHeight(double dpr, double scale); static double fontHeight(double dpr, double scale);
static double outlineSpace(double dpr); // Additional space needed by outline
double height() const; double height() const;
private: private:

View file

@ -47,13 +47,13 @@ ProfileScene::ProfileScene(double dpr, bool printMode, bool isGrayscale) :
maxtime(-1), maxtime(-1),
maxdepth(-1), maxdepth(-1),
dataModel(new DivePlotDataModel(this)), dataModel(new DivePlotDataModel(this)),
profileYAxis(new DepthAxis(DiveCartesianAxis::Position::Left, TIME_GRID, dpr, 1.0, printMode, isGrayscale, *this)), profileYAxis(new DepthAxis(DiveCartesianAxis::Position::Left, 3, 0, TIME_GRID, dpr, 1.0, printMode, isGrayscale, *this)),
gasYAxis(new PartialGasPressureAxis(*dataModel, DiveCartesianAxis::Position::Right, TIME_GRID, dpr, 0.7, printMode, isGrayscale, *this)), gasYAxis(new PartialGasPressureAxis(*dataModel, DiveCartesianAxis::Position::Right, 1, 2, TIME_GRID, dpr, 0.7, printMode, isGrayscale, *this)),
temperatureAxis(new TemperatureAxis(DiveCartesianAxis::Position::Right, TIME_GRID, dpr, 1.0, printMode, isGrayscale, *this)), temperatureAxis(new TemperatureAxis(DiveCartesianAxis::Position::Right, 3, 0, TIME_GRID, dpr, 1.0, printMode, isGrayscale, *this)),
timeAxis(new TimeAxis(DiveCartesianAxis::Position::Bottom, TIME_GRID, dpr, 1.0, printMode, isGrayscale, *this)), timeAxis(new TimeAxis(DiveCartesianAxis::Position::Bottom, 2, 2, TIME_GRID, dpr, 1.0, printMode, isGrayscale, *this)),
cylinderPressureAxis(new DiveCartesianAxis(DiveCartesianAxis::Position::Right, TIME_GRID, dpr, 1.0, printMode, isGrayscale, *this)), cylinderPressureAxis(new DiveCartesianAxis(DiveCartesianAxis::Position::Right, 2, 2, TIME_GRID, dpr, 1.0, printMode, isGrayscale, *this)),
heartBeatAxis(new DiveCartesianAxis(DiveCartesianAxis::Position::Left, HR_AXIS, dpr, 0.7, printMode, isGrayscale, *this)), heartBeatAxis(new DiveCartesianAxis(DiveCartesianAxis::Position::Left, 3, 0, HR_AXIS, dpr, 0.7, printMode, isGrayscale, *this)),
percentageAxis(new DiveCartesianAxis(DiveCartesianAxis::Position::Right, TIME_GRID, dpr, 0.7, printMode, isGrayscale, *this)), percentageAxis(new DiveCartesianAxis(DiveCartesianAxis::Position::Right, 2, 0, TIME_GRID, dpr, 0.7, printMode, isGrayscale, *this)),
diveProfileItem(createItem<DiveProfileItem>(*profileYAxis, DivePlotDataModel::DEPTH, 0, dpr)), diveProfileItem(createItem<DiveProfileItem>(*profileYAxis, DivePlotDataModel::DEPTH, 0, dpr)),
temperatureItem(createItem<DiveTemperatureItem>(*temperatureAxis, DivePlotDataModel::TEMPERATURE, 1, dpr)), temperatureItem(createItem<DiveTemperatureItem>(*temperatureAxis, DivePlotDataModel::TEMPERATURE, 1, dpr)),
meanDepthItem(createItem<DiveMeanDepthItem>(*profileYAxis, DivePlotDataModel::INSTANT_MEANDEPTH, 1, dpr)), meanDepthItem(createItem<DiveMeanDepthItem>(*profileYAxis, DivePlotDataModel::INSTANT_MEANDEPTH, 1, dpr)),