From 6fc9108ccd237896112a5dc1bd79bda5cb89d3d5 Mon Sep 17 00:00:00 2001 From: chenyuanbo Date: Tue, 8 Sep 2026 16:26:37 +0800 Subject: [PATCH] fix(palette): break windowText binding loops with resolved icon palette MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Remove state-dependent palette.windowText bindings from Button, MenuItem and ItemDelegate to avoid feeding ColorSelector output back into the control palette 2. Build DciIcon.palette from the control palette and override its foreground with the resolved state color, keeping the control palette as a read-only input 3. Make ItemDelegate text and indicator icons share the resolved DciIcon foreground without introducing additional properties 4. Reuse the control's resolved DciIcon.palette in IconButton, WindowButton and ButtonIndicator instead of rebuilding it from the base control palette 5. Preserve background, highlight and highlightForeground roles so future role-specific overrides can be propagated to child icons Influence: 1. Button, MenuItem and ItemDelegate no longer report binding loops for palette.windowText 2. Checked and highlighted text and icons retain their state foreground colors 3. Derived and indicator icons receive the same effective palette as their parent control 4. Verify light/dark theme switching and checked, highlighted and disabled states fix(palette): 使用解析后的图标调色板断开 windowText 绑定环 1. 移除 Button、MenuItem 和 ItemDelegate 中依赖控件状态的 palette.windowText 绑定,避免将 ColorSelector 输出回写到控件调色板 2. 基于控件调色板构造 DciIcon.palette,并在其中覆盖已解析的状态前景色, 使控件调色板保持为只读输入 3. ItemDelegate 的文本和指示图标共用 DciIcon 的有效前景色,不引入额外属性 4. IconButton、WindowButton 和 ButtonIndicator 复用控件已经解析的 DciIcon.palette,不再从基础控件调色板重新构造 5. 保留 background、highlight 和 highlightForeground 等角色,便于后续将 各角色的独立覆盖统一传递给子图标 Influence: 1. Button、MenuItem 和 ItemDelegate 不再报告 palette.windowText 绑定循环 2. 选中和高亮状态下的文本、图标继续使用正确的状态前景色 3. 派生图标和指示图标与父控件使用同一份有效调色板 4. 验证亮暗主题切换以及选中、高亮和禁用状态 PMS: TASK-39241 --- qt6/src/qml/Button.qml | 7 +++++-- qt6/src/qml/ButtonIndicator.qml | 2 +- qt6/src/qml/IconButton.qml | 2 +- qt6/src/qml/ItemDelegate.qml | 19 ++++++++++++------- qt6/src/qml/MenuItem.qml | 9 ++++++--- qt6/src/qml/WindowButton.qml | 2 +- 6 files changed, 26 insertions(+), 15 deletions(-) diff --git a/qt6/src/qml/Button.qml b/qt6/src/qml/Button.qml index 076f950aa..83c59462c 100644 --- a/qt6/src/qml/Button.qml +++ b/qt6/src/qml/Button.qml @@ -23,8 +23,11 @@ T.Button { opacity: D.ColorSelector.controlState === D.DTK.DisabledState ? 0.4 : 1 D.DciIcon.mode: D.ColorSelector.controlState D.DciIcon.theme: D.ColorSelector.controlTheme - D.DciIcon.palette: D.DTK.makeIconPalette(palette) - palette.windowText: D.ColorSelector.textColor + D.DciIcon.palette: { + const iconPalette = D.DTK.makeIconPalette(control.palette) + iconPalette.foreground = control.D.ColorSelector.textColor + return iconPalette + } icon { width: DS.Style.button.iconSize height: DS.Style.button.iconSize diff --git a/qt6/src/qml/ButtonIndicator.qml b/qt6/src/qml/ButtonIndicator.qml index f021bf1c0..2b1c4d752 100644 --- a/qt6/src/qml/ButtonIndicator.qml +++ b/qt6/src/qml/ButtonIndicator.qml @@ -22,7 +22,7 @@ Rectangle { width: DS.Style.buttonIndicator.iconSize } name: "arrow_ordinary_down" - palette: control.D.DTK.makeIconPalette(control.palette) + palette: control.D.DciIcon.palette mode: control.D.ColorSelector.controlState theme: control.D.ColorSelector.controlTheme fallbackToQIcon: false diff --git a/qt6/src/qml/IconButton.qml b/qt6/src/qml/IconButton.qml index c7492d2c5..52423eddf 100644 --- a/qt6/src/qml/IconButton.qml +++ b/qt6/src/qml/IconButton.qml @@ -26,7 +26,7 @@ Button { contentItem: D.DciIcon { smooth: control.smooth name: control.icon.name - palette: D.DTK.makeIconPalette(control.palette) + palette: control.D.DciIcon.palette mode: control.D.ColorSelector.controlState theme: control.D.ColorSelector.controlTheme sourceSize: Qt.size(control.icon.width, control.icon.height) diff --git a/qt6/src/qml/ItemDelegate.qml b/qt6/src/qml/ItemDelegate.qml index ef530a6d2..c0a0328a2 100644 --- a/qt6/src/qml/ItemDelegate.qml +++ b/qt6/src/qml/ItemDelegate.qml @@ -43,14 +43,19 @@ T.ItemDelegate { spacing: DS.Style.control.spacing checkable: true autoExclusive: true - palette.windowText: { - let undraged = D.DTK.hasAnimation ? control.backgroundVisible && !dragActive : true - return checked && !control.cascadeSelected && undraged ? D.ColorSelector.checkedTextColor : undefined - } D.DciIcon.mode: D.ColorSelector.controlState D.DciIcon.theme: D.ColorSelector.controlTheme - D.DciIcon.palette: D.DTK.makeIconPalette(palette) + D.DciIcon.palette: { + const iconPalette = D.DTK.makeIconPalette(control.palette) + const dragAllowsSelection = D.DTK.hasAnimation + ? control.backgroundVisible && !control.dragActive + : true + iconPalette.foreground = control.checked && !control.cascadeSelected && dragAllowsSelection + ? control.D.ColorSelector.checkedTextColor + : control.palette.windowText + return iconPalette + } icon { width: DS.Style.itemDelegate.iconSize height: DS.Style.itemDelegate.iconSize @@ -65,7 +70,7 @@ T.ItemDelegate { sourceComponent: D.DciIcon { smooth: control.smooth - palette: D.DTK.makeIconPalette(control.palette) + palette: control.D.DciIcon.palette mode: control.D.ColorSelector.controlState theme: control.D.ColorSelector.controlTheme fallbackToQIcon: false @@ -84,7 +89,7 @@ T.ItemDelegate { ? Qt.AlignCenter : Qt.AlignLeft | Qt.AlignVCenter text: control.text font: control.font - color: control.palette.windowText + color: control.D.DciIcon.palette.foreground icon: D.DTK.makeIcon(control.icon, control.D.DciIcon) Layout.fillWidth: !control.contentFlow } diff --git a/qt6/src/qml/MenuItem.qml b/qt6/src/qml/MenuItem.qml index ed61474af..8eac81f87 100644 --- a/qt6/src/qml/MenuItem.qml +++ b/qt6/src/qml/MenuItem.qml @@ -27,10 +27,13 @@ T.MenuItem { : DS.Style.menu.itemText property D.Palette subMenuBackgroundColor: DS.Style.menu.subMenuOpenedBackground - palette.windowText: D.ColorSelector.textColor D.DciIcon.mode: D.ColorSelector.controlState D.DciIcon.theme: D.ColorSelector.controlTheme - D.DciIcon.palette: D.DTK.makeIconPalette(palette) + D.DciIcon.palette: { + const iconPalette = D.DTK.makeIconPalette(control.palette) + iconPalette.foreground = control.D.ColorSelector.textColor + return iconPalette + } contentItem: D.IconLabel { readonly property real arrowPadding: control.subMenu && control.arrow ? control.arrow.width + control.spacing : 0 readonly property real indicatorPadding: control.useIndicatorPadding && control.indicator ? control.indicator.width + control.spacing : 0 @@ -44,7 +47,7 @@ T.MenuItem { alignment: Qt.AlignLeft text: control.text font: control.font - color: control.palette.windowText + color: control.D.ColorSelector.textColor Behavior on color { enabled: D.DTK.hasAnimation ColorAnimation { duration: control.hovered ? 100 : 0; } diff --git a/qt6/src/qml/WindowButton.qml b/qt6/src/qml/WindowButton.qml index 81e0d82a1..e5b1ea252 100644 --- a/qt6/src/qml/WindowButton.qml +++ b/qt6/src/qml/WindowButton.qml @@ -33,7 +33,7 @@ D.IconButton { smooth: control.smooth name: control.icon.name asynchronous: false - palette: D.DTK.makeIconPalette(control.palette) + palette: control.D.DciIcon.palette mode: control.D.ColorSelector.controlState theme: control.D.ColorSelector.controlTheme sourceSize: Qt.size(control.icon.width, control.icon.height)