diff --git a/kwin/src/breezydesktopconfig.kcfg b/kwin/src/breezydesktopconfig.kcfg
index 856f890..2535499 100644
--- a/kwin/src/breezydesktopconfig.kcfg
+++ b/kwin/src/breezydesktopconfig.kcfg
@@ -6,15 +6,15 @@
- 85
- 20
- 230
+ 22
+ 10
+ 250
- 105
- 20
- 230
+ 25
+ 10
+ 250
diff --git a/kwin/src/kcm/breezydesktopeffectkcm.cpp b/kwin/src/kcm/breezydesktopeffectkcm.cpp
index c866e86..567fa54 100644
--- a/kwin/src/kcm/breezydesktopeffectkcm.cpp
+++ b/kwin/src/kcm/breezydesktopeffectkcm.cpp
@@ -792,6 +792,8 @@ void BreezyDesktopEffectConfig::applyDistanceLabelFormatters()
qCCritical(KWIN_XR) << "applyDistanceLabelFormatters: pose has no position -> clearing formatter";
focused->clearValueToDisplayStringFn();
all->clearValueToDisplayStringFn();
+ focused->setValueUnitsSuffix(QString());
+ all->setValueUnitsSuffix(QString());
return;
}
@@ -803,6 +805,10 @@ void BreezyDesktopEffectConfig::applyDistanceLabelFormatters()
<< "fullDistanceCm=" << fullCm
<< "units=" << units;
+ // Units should appear only in the floating value bubble, not on tick labels.
+ focused->setValueUnitsSuffix(units);
+ all->setValueUnitsSuffix(units);
+
LabeledSlider::ValueToDisplayStringFn fn = [fullCm, units, loc](int raw) -> QString {
static int s_calls = 0;
if (s_calls < 25) {
@@ -817,12 +823,12 @@ void BreezyDesktopEffectConfig::applyDistanceLabelFormatters()
if (s_calls <= 25) {
qCCritical(KWIN_XR) << "distance formatter computed" << ratio << "->" << inches << "in";
}
- return loc.toString(inches, 'f', 1) + QStringLiteral(" in");
+ return loc.toString(inches, 'f', 1);
}
if (s_calls <= 25) {
qCCritical(KWIN_XR) << "distance formatter computed" << ratio << "->" << cm << "cm";
}
- return loc.toString(cm, 'f', 0) + QStringLiteral(" cm");
+ return loc.toString(cm, 'f', 0);
};
focused->setValueToDisplayStringFn(fn);
diff --git a/kwin/src/kcm/labeledslider.h b/kwin/src/kcm/labeledslider.h
index 1a539bb..7491223 100644
--- a/kwin/src/kcm/labeledslider.h
+++ b/kwin/src/kcm/labeledslider.h
@@ -33,6 +33,9 @@ class LabeledSlider : public QSlider {
// tickStartOffset: starting offset for label positions relative to minimum().
// Example: minimum=0, tickInterval=20, tickStartOffset=10 -> labels at 10,30,50,...
Q_PROPERTY(int tickStartOffset READ tickStartOffset WRITE setTickStartOffset)
+ // Optional units suffix shown ONLY in the floating value bubble.
+ // Tick labels never include units.
+ Q_PROPERTY(QString valueUnitsSuffix READ valueUnitsSuffix WRITE setValueUnitsSuffix)
public:
using ValueToDisplayStringFn = std::function;
@@ -77,6 +80,14 @@ public:
QMap valueTexts() const { return m_valueTexts; }
+ QString valueUnitsSuffix() const { return m_valueUnitsSuffix; }
+ void setValueUnitsSuffix(const QString &suffix) {
+ if (m_valueUnitsSuffix == suffix) return;
+ m_valueUnitsSuffix = suffix;
+ updateGeometry();
+ update();
+ }
+
// Optional custom formatter for displayed values.
// If set, it is consulted for values without an explicit setValueText() override.
// Returning a null QString (QString()) falls back to the built-in formatting.
@@ -162,7 +173,7 @@ protected:
optPos.sliderValue = v;
QRect handleAtVal = style()->subControlRect(QStyle::CC_Slider, &optPos, QStyle::SC_SliderHandle, this);
int x = handleAtVal.center().x();
- QString text = valueToDisplayString(v);
+ QString text = valueToDisplayString(v, /*forValueBubble=*/false);
int halfW = fm.horizontalAdvance(text) / 2;
QRect r(x - halfW, baselineY - fm.ascent(), fm.horizontalAdvance(text), fm.height());
p.drawText(r, Qt::AlignCenter, text);
@@ -173,7 +184,7 @@ protected:
if (m_showValueBubble) {
// Handle rect
const QRect handle = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
- QString valText = valueToDisplayString(value());
+ QString valText = valueToDisplayString(value(), /*forValueBubble=*/true);
QFontMetrics fm(font());
QRect textRect = fm.boundingRect(valText);
textRect.adjust(-6, -4, 6, 4);
@@ -208,31 +219,49 @@ protected:
}
private:
- QString valueToDisplayString(int raw) const {
+ QString valueToDisplayString(int raw, bool forValueBubble) const {
// Use custom text if provided for this exact integer value
auto it = m_valueTexts.constFind(raw);
if (it != m_valueTexts.constEnd()) {
return *it;
}
- if (m_valueToDisplayStringFn) {
- QString formatted = m_valueToDisplayStringFn(raw);
- if (!formatted.isNull()) {
- return formatted;
+ auto decimalShiftString = [this](int r) -> QString {
+ if (m_decimalShift == 0) {
+ return QString::number(r);
}
+ int divisor = 1;
+ for (int i = 0; i < m_decimalShift; ++i) divisor *= 10;
+ int whole = r / divisor;
+ int frac = std::abs(r % divisor);
+ QString fracStr = QString::number(frac).rightJustified(m_decimalShift, QLatin1Char('0'));
+ QString result = QString::number(std::abs(whole)) + QLatin1Char('.') + fracStr;
+ if (r < 0) result.prepend(QLatin1Char('-'));
+ return result;
+ };
+
+ QString base;
+ if (m_valueToDisplayStringFn) {
+ base = m_valueToDisplayStringFn(raw);
+ }
+ if (base.isNull()) {
+ base = decimalShiftString(raw);
}
- if (m_decimalShift == 0) {
- return QString::number(raw);
+ if (!forValueBubble) {
+ return base;
}
- int divisor = 1;
- for (int i = 0; i < m_decimalShift; ++i) divisor *= 10;
- int whole = raw / divisor;
- int frac = std::abs(raw % divisor);
- QString fracStr = QString::number(frac).rightJustified(m_decimalShift, QLatin1Char('0'));
- QString result = QString::number(std::abs(whole)) + QLatin1Char('.') + fracStr;
- if (raw < 0) result.prepend(QLatin1Char('-'));
- return result;
+
+ const QString suffix = m_valueUnitsSuffix.trimmed();
+ if (suffix.isEmpty() || base.isEmpty()) {
+ return base;
+ }
+ // Avoid double-appending if caller included units in the formatter.
+ const QString baseTrimmed = base.trimmed();
+ if (baseTrimmed.endsWith(suffix) || baseTrimmed.endsWith(QLatin1Char(' ') + suffix)) {
+ return base;
+ }
+ return baseTrimmed + QLatin1Char(' ') + suffix;
}
bool m_showValueBubble = true;
@@ -240,6 +269,7 @@ private:
int m_tickStartOffset = 0; // label positions start offset relative to minimum
QMap m_valueTexts; // optional text overrides for specific values
ValueToDisplayStringFn m_valueToDisplayStringFn; // optional custom formatter
+ QString m_valueUnitsSuffix; // shown only in the value bubble
private:
int labelInterval() const {
int ti = tickInterval();