Hide unavailable display scale options

This commit is contained in:
David Heinemeier Hansson
2026-07-23 18:06:19 -07:00
parent 58ec29f20a
commit 63955e787f
3 changed files with 90 additions and 5 deletions
+51
View File
@@ -33,6 +33,55 @@ function cleanScale(scale, width, height) {
return normalizeScale(scaleUnits / 120)
}
function matchingScaleIndex(scales, currentScale, width, height) {
var current = Number(currentScale)
if (!Array.isArray(scales) || !isFinite(current)) return -1
var bestIndex = -1
var bestDistance = Infinity
var normalizedCurrent = normalizeScale(current)
for (var i = 0; i < scales.length; i++) {
if (cleanScale(scales[i], width, height) !== normalizedCurrent) continue
var distance = Math.abs(Number(scales[i]) - current)
if (distance < bestDistance) {
bestIndex = i
bestDistance = distance
}
}
return bestIndex
}
function availableScales(scales, width, height) {
if (!Array.isArray(scales) || Number(width) <= 0 || Number(height) <= 0) return scales || []
var byEffectiveScale = {}
for (var i = 0; i < scales.length; i++) {
var requested = Number(scales[i])
var effective = Number(cleanScale(requested, width, height))
// Clean scales round upward. If the mode cannot reach the requested
// scale, cleanScale caps at its largest valid value and this preset is
// not actually available.
if (!isFinite(requested) || !isFinite(effective) || effective < requested) continue
var key = normalizeScale(effective)
var existing = byEffectiveScale[key]
if (!existing || Math.abs(requested - effective) < existing.distance) {
byEffectiveScale[key] = {
value: String(scales[i]),
index: i,
distance: Math.abs(requested - effective)
}
}
}
return Object.keys(byEffectiveScale)
.map(function(key) { return byEffectiveScale[key] })
.sort(function(a, b) { return a.index - b.index })
.map(function(candidate) { return candidate.value })
}
function brightnessName(percent) {
var p = Math.round(percent)
if (p >= 95) return "Sun blast"
@@ -70,6 +119,8 @@ if (typeof module !== "undefined") {
clampBrightness: clampBrightness,
normalizeScale: normalizeScale,
cleanScale: cleanScale,
matchingScaleIndex: matchingScaleIndex,
availableScales: availableScales,
brightnessName: brightnessName,
parseDisplays: parseDisplays
}
+14 -5
View File
@@ -38,7 +38,15 @@ Panel {
// j/k walks each row.
// Mouse hover on a target updates root state via the components' `hovered`
// signal so keyboard cursor and pointer share one highlight.
readonly property var scaleValues: ["1", "1.25", "1.6", "2", "3", "4"]
readonly property var scalePresets: ["1", "1.25", "1.6", "2", "3", "4"]
readonly property var scaleValues: {
for (var i = 0; i < displays.length; i++) {
var display = displays[i]
if (display && display.focused)
return Model.availableScales(scalePresets, display.width, display.height)
}
return scalePresets
}
property string focusSection: "scale"
property int selectedIndex: 0
property bool cursorActive: false
@@ -246,13 +254,13 @@ Panel {
return Model.normalizeScale(scale)
}
function effectiveScale(scale) {
function activeScaleIndex() {
for (var i = 0; i < displays.length; i++) {
var display = displays[i]
if (display && display.focused)
return Model.cleanScale(scale, display.width, display.height)
return Model.matchingScaleIndex(scaleValues, monitorScale, display.width, display.height)
}
return normalizeScale(scale)
return -1
}
// Playful mood-name for a given brightness percent. Bands intentionally
@@ -342,6 +350,7 @@ Panel {
onBrightnessAvailableChanged: clampCursor()
onDisplaysChanged: clampCursor()
onScaleValuesChanged: clampCursor()
onVisibleSectionsChanged: clampCursor()
// Only poll while the panel is open; the bar glyph tracks monitor count via
@@ -780,7 +789,7 @@ Panel {
verticalPadding: Style.spacing.controlPaddingY
bordered: true
active: root.normalizeScale(root.monitorScale) === root.effectiveScale(scaleValue)
active: root.activeScaleIndex() === scaleIndex
hasCursor: root.cursorActive && root.focusSection === "scale" && root.selectedIndex === scaleIndex
onClicked: root.setScale(scaleValue)