From 322e2baa8de6048b2aa602349aa3c0c68748b617 Mon Sep 17 00:00:00 2001 From: Berthold Stoeger Date: Mon, 20 Sep 2021 21:13:19 +0200 Subject: [PATCH] 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 --- profile-widget/divecartesianaxis.cpp | 47 ++++++++++++++++------------ profile-widget/divecartesianaxis.h | 9 +++--- profile-widget/divetextitem.cpp | 5 +++ profile-widget/divetextitem.h | 1 + profile-widget/profilescene.cpp | 14 ++++----- 5 files changed, 44 insertions(+), 32 deletions(-) diff --git a/profile-widget/divecartesianaxis.cpp b/profile-widget/divecartesianaxis.cpp index f90c0b039..1c154bd0d 100644 --- a/profile-widget/divecartesianaxis.cpp +++ b/profile-widget/divecartesianaxis.cpp @@ -18,7 +18,7 @@ void DiveCartesianAxis::setBounds(double minimum, double 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) : printMode(printMode), position(position), @@ -45,6 +45,26 @@ DiveCartesianAxis::DiveCartesianAxis(Position position, color_index_t gridColor, pen.setBrush(getColor(gridColor, isGrayscale)); 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() @@ -93,23 +113,14 @@ void emptyList(QList &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 { - return textWidth("999"); + return labelWidth + labelSpaceHorizontal * dpr; } double DiveCartesianAxis::height() const { - QFont fnt = DiveTextItem::getFont(dpr, labelScale); - QFontMetrics fm(fnt); - return fm.height() + labelSpaceVertical * dpr; + return labelHeight + labelSpaceVertical * dpr; } void DiveCartesianAxis::updateTicks(int animSpeed) @@ -383,9 +394,10 @@ QString TemperatureAxis::textForValue(double value) const return QString::number(mkelvin_to_C((int)value)); } -PartialGasPressureAxis::PartialGasPressureAxis(const DivePlotDataModel &model, Position position, color_index_t gridColor, - double dpr, double labelScale, bool printMode, bool isGrayscale, ProfileScene &scene) : - DiveCartesianAxis(position, gridColor, dpr, labelScale, printMode, isGrayscale, scene), +PartialGasPressureAxis::PartialGasPressureAxis(const DivePlotDataModel &model, Position position, int integralDigits, int fractionalDigits, + color_index_t gridColor, double dpr, double labelScale, bool printMode, bool isGrayscale, + ProfileScene &scene) : + DiveCartesianAxis(position, integralDigits, fractionalDigits, gridColor, dpr, labelScale, printMode, isGrayscale, scene), model(model) { } @@ -413,8 +425,3 @@ void PartialGasPressureAxis::update(int animSpeed) setTickInterval(pp > 4 ? 0.5 : 0.25); updateTicks(animSpeed); } - -double PartialGasPressureAxis::width() const -{ - return textWidth(textForValue(0.99)); -} diff --git a/profile-widget/divecartesianaxis.h b/profile-widget/divecartesianaxis.h index adfdd16a2..8b4fd3a03 100644 --- a/profile-widget/divecartesianaxis.h +++ b/profile-widget/divecartesianaxis.h @@ -32,7 +32,7 @@ public: enum class Position { 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); ~DiveCartesianAxis(); void setBounds(double min, double max); @@ -62,7 +62,6 @@ protected: ProfileScene &scene; virtual QString textForValue(double value) const; virtual QColor colorForValue(double value) const; - double textWidth(const QString &s) const; Orientation orientation; QList labels; QList lines; @@ -74,6 +73,7 @@ protected: double labelScale; bool changed; double dpr; + double labelWidth, labelHeight; // maximum expected sizes of label width and height }; class DepthAxis : public DiveCartesianAxis { @@ -106,10 +106,9 @@ private: class PartialGasPressureAxis : public DiveCartesianAxis { Q_OBJECT public: - PartialGasPressureAxis(const DivePlotDataModel &model, Position position, color_index_t gridColor, - double dpr, double labelScale, bool printMode, bool isGrayscale, ProfileScene &scene); + PartialGasPressureAxis(const DivePlotDataModel &model, Position position, int integralDigits, int fractionalDigits, + color_index_t gridColor, double dpr, double labelScale, bool printMode, bool isGrayscale, ProfileScene &scene); void update(int animSpeed); - double width() const; private: const DivePlotDataModel &model; }; diff --git a/profile-widget/divetextitem.cpp b/profile-widget/divetextitem.cpp index 6e6f97e95..1b8580d2a 100644 --- a/profile-widget/divetextitem.cpp +++ b/profile-widget/divetextitem.cpp @@ -82,6 +82,11 @@ QFont DiveTextItem::getFont(double dpr, double scale) 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) { QFont fnt = getFont(dpr, scale); diff --git a/profile-widget/divetextitem.h b/profile-widget/divetextitem.h index cb7d054b1..6ce3437af 100644 --- a/profile-widget/divetextitem.h +++ b/profile-widget/divetextitem.h @@ -22,6 +22,7 @@ public: const QString &text(); static QFont getFont(double dpr, double scale); static double fontHeight(double dpr, double scale); + static double outlineSpace(double dpr); // Additional space needed by outline double height() const; private: diff --git a/profile-widget/profilescene.cpp b/profile-widget/profilescene.cpp index 779514a14..020930f17 100644 --- a/profile-widget/profilescene.cpp +++ b/profile-widget/profilescene.cpp @@ -47,13 +47,13 @@ ProfileScene::ProfileScene(double dpr, bool printMode, bool isGrayscale) : maxtime(-1), maxdepth(-1), dataModel(new DivePlotDataModel(this)), - profileYAxis(new DepthAxis(DiveCartesianAxis::Position::Left, TIME_GRID, dpr, 1.0, printMode, isGrayscale, *this)), - gasYAxis(new PartialGasPressureAxis(*dataModel, DiveCartesianAxis::Position::Right, TIME_GRID, dpr, 0.7, printMode, isGrayscale, *this)), - temperatureAxis(new TemperatureAxis(DiveCartesianAxis::Position::Right, TIME_GRID, dpr, 1.0, printMode, isGrayscale, *this)), - timeAxis(new TimeAxis(DiveCartesianAxis::Position::Bottom, TIME_GRID, dpr, 1.0, printMode, isGrayscale, *this)), - cylinderPressureAxis(new DiveCartesianAxis(DiveCartesianAxis::Position::Right, TIME_GRID, dpr, 1.0, printMode, isGrayscale, *this)), - heartBeatAxis(new DiveCartesianAxis(DiveCartesianAxis::Position::Left, HR_AXIS, dpr, 0.7, printMode, isGrayscale, *this)), - percentageAxis(new DiveCartesianAxis(DiveCartesianAxis::Position::Right, TIME_GRID, dpr, 0.7, 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, 1, 2, TIME_GRID, dpr, 0.7, 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, 2, 2, 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, 3, 0, HR_AXIS, dpr, 0.7, printMode, isGrayscale, *this)), + percentageAxis(new DiveCartesianAxis(DiveCartesianAxis::Position::Right, 2, 0, TIME_GRID, dpr, 0.7, printMode, isGrayscale, *this)), diveProfileItem(createItem(*profileYAxis, DivePlotDataModel::DEPTH, 0, dpr)), temperatureItem(createItem(*temperatureAxis, DivePlotDataModel::TEMPERATURE, 1, dpr)), meanDepthItem(createItem(*profileYAxis, DivePlotDataModel::INSTANT_MEANDEPTH, 1, dpr)),