From b54d8e04ae56ad99ec4f03f9c74b84cc5a39bf68 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Wed, 20 May 2026 20:37:04 +0200 Subject: [PATCH] Collapse focus/hover/normal ternaries into Style.controlFill helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TextField, NumberField, Dropdown, SearchableDropdown, and Toggle all painted their background, border color, and border width with the same three-line ternary ladder (`_focused ? focusFill : _hot ? hoverFill : normalFill`). Five components × three properties × three branches is a lot of room for one of them to drift from the others when a new state ever gets added. Add controlFill / controlBorder / controlBorderWidth on Style and rewrite each call site as a single binding. No visual change. --- shell/Commons/Style.qml | 22 ++++++++++++++++++++++ shell/Ui/Dropdown.qml | 16 +++------------- shell/Ui/NumberField.qml | 16 +++------------- shell/Ui/SearchableDropdown.qml | 16 +++------------- shell/Ui/TextField.qml | 16 +++------------- shell/Ui/Toggle.qml | 16 +++------------- 6 files changed, 37 insertions(+), 65 deletions(-) diff --git a/shell/Commons/Style.qml b/shell/Commons/Style.qml index 3e18b8c2..2c70eaa4 100644 --- a/shell/Commons/Style.qml +++ b/shell/Commons/Style.qml @@ -158,6 +158,28 @@ QtObject { function selectedBorderFor(foreground, accent, urgent) { return Util.alpha(selectedStateColor(foreground, accent, urgent), selectedBorderAlpha) } function focusBorderFor(foreground, accent, urgent) { return Util.alpha(focusStateColor(foreground, accent, urgent), focusBorderAlpha) } + // Composite helpers for the focus > hover > normal priority chain used by + // every form control surface (TextField, NumberField, Dropdown, Toggle, + // etc.). Saves callers from re-writing the three-line ternary ladder for + // fill / border / border-width on every Rectangle background. + function controlFill(focused, hot, foreground, accent) { + if (focused) return focusFillFor(foreground, accent) + if (hot) return hoverFillFor(foreground, accent) + return normalFillFor(foreground, accent) + } + + function controlBorder(focused, hot, foreground, accent) { + if (focused) return focusBorderFor(foreground, accent) + if (hot) return hoverBorderFor(foreground, accent) + return normalBorderFor(foreground, accent) + } + + function controlBorderWidth(focused, hot) { + if (focused) return focusBorderWidth + if (hot) return hoverBorderWidth + return normalBorderWidth + } + // Convenience colors resolved against the foundational palette. readonly property color normalFill: normalFillFor(Color.foreground, Color.accent, Color.urgent) readonly property color hoverFill: hoverFillFor(Color.foreground, Color.accent, Color.urgent) diff --git a/shell/Ui/Dropdown.qml b/shell/Ui/Dropdown.qml index 193543fb..48bd942b 100644 --- a/shell/Ui/Dropdown.qml +++ b/shell/Ui/Dropdown.qml @@ -87,19 +87,9 @@ Item { readonly property bool _focused: trigger.activeFocus readonly property bool _hot: triggerHover.hovered || root.hasCursor - color: trigger._focused - ? Style.focusFillFor(root.foreground, root.accent) - : (trigger._hot - ? Style.hoverFillFor(root.foreground, root.accent) - : Style.normalFillFor(root.foreground, root.accent)) - border.color: trigger._focused - ? Style.focusBorderFor(root.foreground, root.accent) - : (trigger._hot - ? Style.hoverBorderFor(root.foreground, root.accent) - : Style.normalBorderFor(root.foreground, root.accent)) - border.width: trigger._focused - ? Style.focusBorderWidth - : (trigger._hot ? Style.hoverBorderWidth : Style.normalBorderWidth) + color: Style.controlFill(trigger._focused, trigger._hot, root.foreground, root.accent) + border.color: Style.controlBorder(trigger._focused, trigger._hot, root.foreground, root.accent) + border.width: Style.controlBorderWidth(trigger._focused, trigger._hot) activeFocusOnTab: true diff --git a/shell/Ui/NumberField.qml b/shell/Ui/NumberField.qml index 27a3cc5c..8c860d70 100644 --- a/shell/Ui/NumberField.qml +++ b/shell/Ui/NumberField.qml @@ -50,19 +50,9 @@ Column { readonly property bool _focused: spin.activeFocus readonly property bool _hot: root._hovered || root.hasCursor - color: _focused - ? Style.focusFillFor(root.foreground, root.accent) - : (_hot - ? Style.hoverFillFor(root.foreground, root.accent) - : Style.normalFillFor(root.foreground, root.accent)) - border.color: _focused - ? Style.focusBorderFor(root.foreground, root.accent) - : (_hot - ? Style.hoverBorderFor(root.foreground, root.accent) - : Style.normalBorderFor(root.foreground, root.accent)) - border.width: _focused - ? Style.focusBorderWidth - : (_hot ? Style.hoverBorderWidth : Style.normalBorderWidth) + color: Style.controlFill(_focused, _hot, root.foreground, root.accent) + border.color: Style.controlBorder(_focused, _hot, root.foreground, root.accent) + border.width: Style.controlBorderWidth(_focused, _hot) radius: Style.cornerRadius HoverHandler { diff --git a/shell/Ui/SearchableDropdown.qml b/shell/Ui/SearchableDropdown.qml index 759bedab..5c876fa5 100644 --- a/shell/Ui/SearchableDropdown.qml +++ b/shell/Ui/SearchableDropdown.qml @@ -109,19 +109,9 @@ Item { readonly property bool _focused: trigger.activeFocus readonly property bool _hot: triggerHover.hovered || root.hasCursor - color: trigger._focused - ? Style.focusFillFor(root.foreground, root.accent) - : (trigger._hot - ? Style.hoverFillFor(root.foreground, root.accent) - : Style.normalFillFor(root.foreground, root.accent)) - border.color: trigger._focused - ? Style.focusBorderFor(root.foreground, root.accent) - : (trigger._hot - ? Style.hoverBorderFor(root.foreground, root.accent) - : Style.normalBorderFor(root.foreground, root.accent)) - border.width: trigger._focused - ? Style.focusBorderWidth - : (trigger._hot ? Style.hoverBorderWidth : Style.normalBorderWidth) + color: Style.controlFill(trigger._focused, trigger._hot, root.foreground, root.accent) + border.color: Style.controlBorder(trigger._focused, trigger._hot, root.foreground, root.accent) + border.width: Style.controlBorderWidth(trigger._focused, trigger._hot) activeFocusOnTab: true diff --git a/shell/Ui/TextField.qml b/shell/Ui/TextField.qml index ff3765d0..53c16d91 100644 --- a/shell/Ui/TextField.qml +++ b/shell/Ui/TextField.qml @@ -49,19 +49,9 @@ TextField { bottomPadding: verticalPadding background: Rectangle { - color: root._focused - ? Style.focusFillFor(root.foreground, root.accent) - : (root._hot - ? Style.hoverFillFor(root.foreground, root.accent) - : Style.normalFillFor(root.foreground, root.accent)) - border.color: root._focused - ? Style.focusBorderFor(root.foreground, root.accent) - : (root._hot - ? Style.hoverBorderFor(root.foreground, root.accent) - : Style.normalBorderFor(root.foreground, root.accent)) - border.width: root._focused - ? Style.focusBorderWidth - : (root._hot ? Style.hoverBorderWidth : Style.normalBorderWidth) + color: Style.controlFill(root._focused, root._hot, root.foreground, root.accent) + border.color: Style.controlBorder(root._focused, root._hot, root.foreground, root.accent) + border.width: Style.controlBorderWidth(root._focused, root._hot) radius: Style.cornerRadius } } diff --git a/shell/Ui/Toggle.qml b/shell/Ui/Toggle.qml index 482b129a..10324f87 100644 --- a/shell/Ui/Toggle.qml +++ b/shell/Ui/Toggle.qml @@ -53,19 +53,9 @@ Rectangle { readonly property bool _hot: hasCursor || mouse.containsMouse - color: activeFocus - ? Style.focusFillFor(foreground, accent) - : (_hot - ? Style.hoverFillFor(foreground, accent) - : Style.normalFillFor(foreground, accent)) - border.color: activeFocus - ? Style.focusBorderFor(foreground, accent) - : (_hot - ? Style.hoverBorderFor(foreground, accent) - : Style.normalBorderFor(foreground, accent)) - border.width: activeFocus - ? Style.focusBorderWidth - : (_hot ? Style.hoverBorderWidth : Style.normalBorderWidth) + color: Style.controlFill(activeFocus, _hot, foreground, accent) + border.color: Style.controlBorder(activeFocus, _hot, foreground, accent) + border.width: Style.controlBorderWidth(activeFocus, _hot) Behavior on color { ColorAnimation { duration: 100 } }