Fix how units are used on the sliders

This commit is contained in:
wheaney 2026-01-15 14:57:50 -08:00
parent e4aae6bc94
commit 44ab969eb9
3 changed files with 61 additions and 25 deletions

View File

@ -6,15 +6,15 @@
<kcfgfile name="kwinrc"/> <kcfgfile name="kwinrc"/>
<group name="Effect-breezy_desktop"> <group name="Effect-breezy_desktop">
<entry name="FocusedDisplayDistance" type="Int"> <entry name="FocusedDisplayDistance" type="Int">
<default>85</default> <default>22</default>
<min>20</min> <min>10</min>
<max>230</max> <max>250</max>
<label>Focused Display Distance</label> <label>Focused Display Distance</label>
</entry> </entry>
<entry name="AllDisplaysDistance" type="Int"> <entry name="AllDisplaysDistance" type="Int">
<default>105</default> <default>25</default>
<min>20</min> <min>10</min>
<max>230</max> <max>250</max>
<label>All Displays Distance</label> <label>All Displays Distance</label>
</entry> </entry>
<entry name="measurement_units" type="String"> <entry name="measurement_units" type="String">

View File

@ -792,6 +792,8 @@ void BreezyDesktopEffectConfig::applyDistanceLabelFormatters()
qCCritical(KWIN_XR) << "applyDistanceLabelFormatters: pose has no position -> clearing formatter"; qCCritical(KWIN_XR) << "applyDistanceLabelFormatters: pose has no position -> clearing formatter";
focused->clearValueToDisplayStringFn(); focused->clearValueToDisplayStringFn();
all->clearValueToDisplayStringFn(); all->clearValueToDisplayStringFn();
focused->setValueUnitsSuffix(QString());
all->setValueUnitsSuffix(QString());
return; return;
} }
@ -803,6 +805,10 @@ void BreezyDesktopEffectConfig::applyDistanceLabelFormatters()
<< "fullDistanceCm=" << fullCm << "fullDistanceCm=" << fullCm
<< "units=" << units; << "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 { LabeledSlider::ValueToDisplayStringFn fn = [fullCm, units, loc](int raw) -> QString {
static int s_calls = 0; static int s_calls = 0;
if (s_calls < 25) { if (s_calls < 25) {
@ -817,12 +823,12 @@ void BreezyDesktopEffectConfig::applyDistanceLabelFormatters()
if (s_calls <= 25) { if (s_calls <= 25) {
qCCritical(KWIN_XR) << "distance formatter computed" << ratio << "->" << inches << "in"; 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) { if (s_calls <= 25) {
qCCritical(KWIN_XR) << "distance formatter computed" << ratio << "->" << cm << "cm"; 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); focused->setValueToDisplayStringFn(fn);

View File

@ -33,6 +33,9 @@ class LabeledSlider : public QSlider {
// tickStartOffset: starting offset for label positions relative to minimum(). // tickStartOffset: starting offset for label positions relative to minimum().
// Example: minimum=0, tickInterval=20, tickStartOffset=10 -> labels at 10,30,50,... // Example: minimum=0, tickInterval=20, tickStartOffset=10 -> labels at 10,30,50,...
Q_PROPERTY(int tickStartOffset READ tickStartOffset WRITE setTickStartOffset) 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: public:
using ValueToDisplayStringFn = std::function<QString(int)>; using ValueToDisplayStringFn = std::function<QString(int)>;
@ -77,6 +80,14 @@ public:
QMap<int, QString> valueTexts() const { return m_valueTexts; } QMap<int, QString> 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. // Optional custom formatter for displayed values.
// If set, it is consulted for values without an explicit setValueText() override. // If set, it is consulted for values without an explicit setValueText() override.
// Returning a null QString (QString()) falls back to the built-in formatting. // Returning a null QString (QString()) falls back to the built-in formatting.
@ -162,7 +173,7 @@ protected:
optPos.sliderValue = v; optPos.sliderValue = v;
QRect handleAtVal = style()->subControlRect(QStyle::CC_Slider, &optPos, QStyle::SC_SliderHandle, this); QRect handleAtVal = style()->subControlRect(QStyle::CC_Slider, &optPos, QStyle::SC_SliderHandle, this);
int x = handleAtVal.center().x(); int x = handleAtVal.center().x();
QString text = valueToDisplayString(v); QString text = valueToDisplayString(v, /*forValueBubble=*/false);
int halfW = fm.horizontalAdvance(text) / 2; int halfW = fm.horizontalAdvance(text) / 2;
QRect r(x - halfW, baselineY - fm.ascent(), fm.horizontalAdvance(text), fm.height()); QRect r(x - halfW, baselineY - fm.ascent(), fm.horizontalAdvance(text), fm.height());
p.drawText(r, Qt::AlignCenter, text); p.drawText(r, Qt::AlignCenter, text);
@ -173,7 +184,7 @@ protected:
if (m_showValueBubble) { if (m_showValueBubble) {
// Handle rect // Handle rect
const QRect handle = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this); 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()); QFontMetrics fm(font());
QRect textRect = fm.boundingRect(valText); QRect textRect = fm.boundingRect(valText);
textRect.adjust(-6, -4, 6, 4); textRect.adjust(-6, -4, 6, 4);
@ -208,31 +219,49 @@ protected:
} }
private: private:
QString valueToDisplayString(int raw) const { QString valueToDisplayString(int raw, bool forValueBubble) const {
// Use custom text if provided for this exact integer value // Use custom text if provided for this exact integer value
auto it = m_valueTexts.constFind(raw); auto it = m_valueTexts.constFind(raw);
if (it != m_valueTexts.constEnd()) { if (it != m_valueTexts.constEnd()) {
return *it; return *it;
} }
if (m_valueToDisplayStringFn) { auto decimalShiftString = [this](int r) -> QString {
QString formatted = m_valueToDisplayStringFn(raw); if (m_decimalShift == 0) {
if (!formatted.isNull()) { return QString::number(r);
return formatted;
} }
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) { if (!forValueBubble) {
return QString::number(raw); return base;
} }
int divisor = 1;
for (int i = 0; i < m_decimalShift; ++i) divisor *= 10; const QString suffix = m_valueUnitsSuffix.trimmed();
int whole = raw / divisor; if (suffix.isEmpty() || base.isEmpty()) {
int frac = std::abs(raw % divisor); return base;
QString fracStr = QString::number(frac).rightJustified(m_decimalShift, QLatin1Char('0')); }
QString result = QString::number(std::abs(whole)) + QLatin1Char('.') + fracStr; // Avoid double-appending if caller included units in the formatter.
if (raw < 0) result.prepend(QLatin1Char('-')); const QString baseTrimmed = base.trimmed();
return result; if (baseTrimmed.endsWith(suffix) || baseTrimmed.endsWith(QLatin1Char(' ') + suffix)) {
return base;
}
return baseTrimmed + QLatin1Char(' ') + suffix;
} }
bool m_showValueBubble = true; bool m_showValueBubble = true;
@ -240,6 +269,7 @@ private:
int m_tickStartOffset = 0; // label positions start offset relative to minimum int m_tickStartOffset = 0; // label positions start offset relative to minimum
QMap<int, QString> m_valueTexts; // optional text overrides for specific values QMap<int, QString> m_valueTexts; // optional text overrides for specific values
ValueToDisplayStringFn m_valueToDisplayStringFn; // optional custom formatter ValueToDisplayStringFn m_valueToDisplayStringFn; // optional custom formatter
QString m_valueUnitsSuffix; // shown only in the value bubble
private: private:
int labelInterval() const { int labelInterval() const {
int ti = tickInterval(); int ti = tickInterval();