From 63a14d0edfb015b3fe577e866a4e9e847cbe3c43 Mon Sep 17 00:00:00 2001 From: Joachim Kohlhammer Date: Tue, 7 May 2024 01:40:16 +0200 Subject: [PATCH] DialWindow: Scaling font in both dimensions (#4469) Currently the font in DialWindow is only scaled to make the text fit into the label vertically. This commit scales the font in both dimensions and prevents cutting off the content. The font is rescaled * If the DialWindow itself is resized * If the text set and is longer than the previous one * Every 10 text-changes --- src/Train/DialWindow.cpp | 23 +---- src/Train/DialWindow.h | 7 +- src/Train/ScalingLabel.cpp | 194 +++++++++++++++++++++++++++++++++++++ src/Train/ScalingLabel.h | 68 +++++++++++++ src/src.pro | 6 +- 5 files changed, 273 insertions(+), 25 deletions(-) create mode 100644 src/Train/ScalingLabel.cpp create mode 100644 src/Train/ScalingLabel.h diff --git a/src/Train/DialWindow.cpp b/src/Train/DialWindow.cpp index 066978d60..cff3d5ae7 100644 --- a/src/Train/DialWindow.cpp +++ b/src/Train/DialWindow.cpp @@ -80,7 +80,10 @@ DialWindow::DialWindow(Context *context) : QVBoxLayout *layout = new QVBoxLayout; layout->setSpacing(0); layout->setContentsMargins(3,3,3,3); - valueLabel = new QLabel(this); + valueLabel = new ScalingLabel(this); + QFont vlFont = valueLabel->font(); + vlFont.setWeight(QFont::Bold); + valueLabel->setFont(vlFont); valueLabel->setAlignment(Qt::AlignCenter | Qt::AlignVCenter); layout->addWidget(valueLabel); setChartLayout(layout); @@ -99,9 +102,6 @@ DialWindow::DialWindow(Context *context) : // setup colors seriesChanged(); - // setup fontsize etc - resizeEvent(NULL); - // set to zero resetValues(); } @@ -546,21 +546,6 @@ DialWindow::telemetryUpdate(const RealtimeData &rtData) } } -void DialWindow::resizeEvent(QResizeEvent * ) -{ - QFont font; - - // set point size within reasonable limits for low dpi screens - int size = (geometry().height() - 24) * 72 / logicalDpiY(); - if (size <= 0) size = 4; - if (size >= 64) size = 64; - - font.setPointSize(size); - - font.setWeight(QFont::Bold); - valueLabel->setFont(font); -} - void DialWindow::seriesChanged() { // we got some! diff --git a/src/Train/DialWindow.h b/src/Train/DialWindow.h index a21caa5f1..e49a3d0fd 100644 --- a/src/Train/DialWindow.h +++ b/src/Train/DialWindow.h @@ -26,6 +26,8 @@ #include #include +#include "ScalingLabel.h" + #include "Context.h" #include "Zones.h" // for data series types #include "RideFile.h" // for data series types @@ -74,9 +76,6 @@ class DialWindow : public GcChartWindow int style() const { return _style; } int avgSecs() const { return average; } - // change font as window resizes - void resizeEvent(QResizeEvent *); - public slots: // trap signals @@ -148,7 +147,7 @@ class DialWindow : public GcChartWindow QLineEdit *averageEdit; // display - QLabel *valueLabel; + ScalingLabel *valueLabel; QColor foreground, background; diff --git a/src/Train/ScalingLabel.cpp b/src/Train/ScalingLabel.cpp new file mode 100644 index 000000000..654f61165 --- /dev/null +++ b/src/Train/ScalingLabel.cpp @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2022 Joachim Kohlhammer (joachim.kohlhammer@gmx.de) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "ScalingLabel.h" + +#include + + +ScalingLabel::ScalingLabel +(QWidget *parent, Qt::WindowFlags f) +: ScalingLabel(4, 64, parent, f) +{ +} + + + +ScalingLabel::ScalingLabel +(int minFontPointSize, int maxFontPointSize, QWidget *parent, Qt::WindowFlags f) +: QLabel(parent, f), minFontPointSize(minFontPointSize), maxFontPointSize(maxFontPointSize) +{ + QFont fnt = font(); + fnt.setPointSize(minFontPointSize); + QLabel::setFont(fnt); +} + + +ScalingLabel::~ScalingLabel +() +{ +} + + +void +ScalingLabel::resizeEvent +(QResizeEvent *evt) +{ + Q_UNUSED(evt); + scaleFont(text(), ScalingLabelReason::ResizeEvent); +} + + +void +ScalingLabel::setText +(const QString &text) +{ + ++counter; + if (text.length() > QLabel::text().length()) { + scaleFont(text, ScalingLabelReason::TextLengthChanged); + } else if (counter > 10) { + scaleFont(text, ScalingLabelReason::CounterExceeded); + } + QLabel::setText(text); +} + + +void +ScalingLabel::setFont +(const QFont &font) +{ + if (! scaleFont(text(), font, ScalingLabelReason::FontChanged)) { + QLabel::setFont(font); + } +} + + +int +ScalingLabel::getMinFontPointSize +() const +{ + return minFontPointSize; +} + + +void +ScalingLabel::setMinFontPointSize +(int size) +{ + minFontPointSize = size; +} + + +int +ScalingLabel::getMaxFontPointSize +() const +{ + return maxFontPointSize; +} + + +void +ScalingLabel::setMaxFontPointSize +(int size) +{ + maxFontPointSize = size; +} + + +bool +ScalingLabel::isLinear +() const +{ + return linear; +} + + +void +ScalingLabel::setLinear +(bool linear) +{ + this->linear = linear; +} + + +bool +ScalingLabel::scaleFont +(const QString &text, ScalingLabelReason reason) +{ + return scaleFont(text, font(), reason); +} + + +bool +ScalingLabel::scaleFont +(const QString &text, const QFont &font, ScalingLabelReason reason) +{ + counter = 0; + if (linear) { + return scaleFontLinear(text, font, reason); + } else { + return scaleFontExact(text, font, reason); + } +} + + +bool +ScalingLabel::scaleFontExact +(const QString &text, const QFont &font, ScalingLabelReason reason) +{ + int size = maxFontPointSize + 1; + if (reason == ScalingLabelReason::CounterExceeded) { + size = font.pointSize() + 1; + } + QFont f(font); + QRect br; + do { + f.setPointSize(--size); + QFontMetrics fm = QFontMetrics(f, this); + br = fm.boundingRect(text); + } while (size >= minFontPointSize && (br.width() > width() || br.height() > height())); + QLabel::setFont(f); + return true; +} + + +bool +ScalingLabel::scaleFontLinear +(const QString &text, const QFont &font, ScalingLabelReason reason) +{ + if (text.length() == 0 || width() <= 0 || height() <= 0) { + return false; + } + int maxSize = maxFontPointSize; + if (reason == ScalingLabelReason::CounterExceeded) { + maxSize = font.pointSize(); + } + QFont f(font); + f.setPointSize(minFontPointSize); + QFontMetrics fmS = QFontMetrics(f, this); + f.setPointSize(maxSize); + QFontMetrics fmL = QFontMetrics(f, this); + QRect brS = fmS.boundingRect(text); + QRect brL = fmL.boundingRect(text); + int sizeWidth = (maxSize - minFontPointSize) / float(brL.width() - brS.width()) * width(); + int sizeHeight = (maxSize - minFontPointSize) / float(brL.height() - brS.height()) * height(); + int calcSize = std::min(sizeWidth, sizeHeight); + f.setPointSize(std::max(std::min(calcSize, maxSize), minFontPointSize)); + QLabel::setFont(f); + return true; +} diff --git a/src/Train/ScalingLabel.h b/src/Train/ScalingLabel.h new file mode 100644 index 000000000..6b6dcaa16 --- /dev/null +++ b/src/Train/ScalingLabel.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2022 Joachim Kohlhammer (joachim.kohlhammer@gmx.de) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _GC_ScalingLabel_h +#define _GC_ScalingLabel_h 1 + +#include + +enum class ScalingLabelReason : uint8_t { + TextLengthChanged, + FontChanged, + ResizeEvent, + CounterExceeded +}; + +class ScalingLabel : public QLabel +{ + Q_OBJECT + Q_PROPERTY(int minFontPointSize READ getMinFontPointSize WRITE setMinFontPointSize USER false) + Q_PROPERTY(int maxFontPointSize READ getMaxFontPointSize WRITE setMaxFontPointSize USER false) + Q_PROPERTY(bool linear READ isLinear WRITE setLinear USER false) + + public: + ScalingLabel(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags()); + ScalingLabel(int minFontPointSize, int maxFontPointSize, QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags()); + virtual ~ScalingLabel(); + + virtual void resizeEvent(QResizeEvent *evt); + virtual void setFont(const QFont &font); + + int getMinFontPointSize() const; + int getMaxFontPointSize() const; + bool isLinear() const; + + public slots: + void setText(const QString &text); + void setMinFontPointSize(int size); + void setMaxFontPointSize(int size); + void setLinear(bool linear); + + private: + bool scaleFont(const QString &text, const QFont &font, ScalingLabelReason reason); + bool scaleFont(const QString &text, ScalingLabelReason reason); + bool scaleFontExact(const QString &text, const QFont &font, ScalingLabelReason reason); + bool scaleFontLinear(const QString &text, const QFont &font, ScalingLabelReason reason); + + int minFontPointSize; + int maxFontPointSize; + bool linear = true; + int counter = 0; +}; + +#endif diff --git a/src/src.pro b/src/src.pro index c38b52f40..0f57df479 100644 --- a/src/src.pro +++ b/src/src.pro @@ -699,7 +699,8 @@ HEADERS += Train/AddDeviceWizard.h Train/CalibrationData.h Train/ComputrainerCon HEADERS += Train/TrainBottom.h Train/TrainDB.h Train/TrainSidebar.h \ Train/VideoLayoutParser.h Train/VideoSyncFile.h Train/WorkoutPlotWindow.h Train/WebPageWindow.h \ Train/WorkoutWidget.h Train/WorkoutWidgetItems.h Train/WorkoutWindow.h Train/WorkoutWizard.h Train/ZwoParser.h \ - Train/LiveMapWebPageWindow.h + Train/LiveMapWebPageWindow.h \ + Train/ScalingLabel.h ###============= @@ -803,7 +804,8 @@ SOURCES += Train/AddDeviceWizard.cpp Train/CalibrationData.cpp Train/Computraine SOURCES += Train/TrainBottom.cpp Train/TrainDB.cpp Train/TrainSidebar.cpp \ Train/VideoLayoutParser.cpp Train/VideoSyncFile.cpp Train/WorkoutPlotWindow.cpp Train/WebPageWindow.cpp \ Train/WorkoutWidget.cpp Train/WorkoutWidgetItems.cpp Train/WorkoutWindow.cpp Train/WorkoutWizard.cpp Train/ZwoParser.cpp \ - Train/LiveMapWebPageWindow.cpp + Train/LiveMapWebPageWindow.cpp \ + Train/ScalingLabel.cpp ## Crash Handling win32-msvc* {