Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions qt6/src/docs/Menu.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Menu 菜单项悬浮高亮渲染说明

[公共规范与控件索引](README.md)

## 适用范围与依据

本文档说明 v25 flow style 下 `MenuItem` 的悬浮(高亮)背景渲染,即菜单项被指针悬停或其子菜单展开时的背景效果。设计依据为本分支已验证实现:在既有高亮填充之上叠加 1px 内阴影,做法参照 [ToolButton](../qml/ToolButton.qml) 的 checked 状态内阴影(同样的 `BoxInsetShadow` 参数)。菜单容器面板、分隔符、页眉页脚等其它部分不在本文档范围。

普通模式、亮色主题与暗色主题下的悬浮内阴影均已定稿。

## 外形与内容布局

| 项目 | 默认值 |
|---|---|
| 菜单项背景圆角 | 6 个逻辑像素 |
| 菜单项隐式尺寸 | 180 × 26(背景建议尺寸,非控件固定宽高)|
| 菜单项内边距 | 3 |
| 内容左留白 | 取内容留白 30 与指示器/箭头占位中的较大值 |
| 图标尺寸 | 14 × 14 |
| 指示器边距 | 10 |

文字与图标由调用方提供;存在已选中项时为指示器预留空间,子菜单项为箭头预留空间。

## 渲染元素与显示条件

悬浮背景由三层叠加:底层 `HighlightPanel` 圆角填充,之上两道 1px 内阴影——顶部高光与底部阴影,均用 `BoxInsetShadow` 实现——共同形成内斜面,模仿 Button checked 状态的凸起边缘效果。三层均在菜单项处于高亮状态(指针悬停,或其子菜单可见)时显示,其余情况不显示。

| 窗口模式与主题 | 高亮填充 | 顶部内阴影 | 底部内阴影 |
|---|---|---|---|
| 普通模式、亮色 | 显示系统高亮色填充 | 不显示(透明) | 显示 1px 底部内阴影,黑色 20% 不透明度 |
| 普通模式、暗色 | 显示系统高亮色填充 | 显示 1px 顶部内阴影,白色 10% 不透明度 | 显示 1px 底部内阴影,黑色 24% 不透明度 |
| 水晶模式、亮色 | 显示系统高亮色填充 | 不显示(透明) | 显示 1px 底部内阴影,黑色 20% 不透明度 |
| 水晶模式、暗色 | 显示系统高亮色填充 | 显示 1px 顶部内阴影,白色 10% 不透明度 | 显示 1px 底部内阴影,黑色 24% 不透明度 |

> 内阴影颜色取自 `menu.itemHighlightInnerShadow`(底部)与 `menu.itemHighlightInnerShadowTop`(顶部),调色板仅定义普通状态;悬浮时按公共回退规则取普通状态值。浅色模式顶部内阴影设为透明,故不可见。暗色底部取值(24%)略高于浅色(20%),因暗色主题高亮填充更亮,需略强对比以保持底部内阴影可读。高亮填充使用 `HighlightPanel` 默认背景(`highlightPanel.background`,即系统高亮色),由既有实现提供,本文档不改变其取色。

## 色值与几何参数

两道内阴影均用 `BoxInsetShadow` 实现,`shadowBlur` 设为 1 以保证圆角处自然过渡。取与高亮面板相同的尺寸与圆角(6)。顶部 `shadowOffsetY: 1`,底部 `shadowOffsetY: -1`。顶部为白色 10% 不透明度(仅暗色),底部为黑色 20%(亮色)或 24%(暗色)不透明度。两道阴影共同形成内斜面,模仿 Button checked 状态的凸起边缘。

| 窗口模式与主题 | 顶部内阴影颜色 | 底部内阴影颜色 |
|---|---|---|
| 普通模式、亮色 | `transparent` | `rgba(0,0,0,0.2)` |
| 普通模式、暗色 | `rgba(255,255,255,0.1)` | `rgba(0,0,0,0.24)` |
| 水晶模式、亮色 | `transparent` | `rgba(0,0,0,0.2)` |
| 水晶模式、暗色 | `rgba(255,255,255,0.1)` | `rgba(0,0,0,0.24)` |

色值定义以 [FlowStyle.qml](../qml/FlowStyle.qml) 的 `menu.itemHighlightInnerShadow`(底部)与 `menu.itemHighlightInnerShadowTop`(顶部)为准。

## 实现对应关系

| 内容 | 实现来源 |
|---|---|
| 菜单项背景装配、悬浮显示条件 | [MenuItem.qml](../qml/MenuItem.qml) |
| 高亮填充面板 | [HighlightPanel.qml](../qml/HighlightPanel.qml) |
| 顶部与底部内阴影渲染 | `BoxInsetShadow`(`shadowBlur: 1`),经 [HighlightPanel.qml](../qml/HighlightPanel.qml) 的 `bevelShadowColor1/2` 触发 |
| 内阴影颜色、菜单项几何与圆角 | [FlowStyle.qml](../qml/FlowStyle.qml) 的 `menu.itemHighlightInnerShadow` 与 `menu.item` |
| 设计参照(内斜面效果)| [ToolButton.qml](../qml/ToolButton.qml) 的 checked 状态 |

## 复现与验收

- 普通模式、亮色:菜单项悬浮时,在系统高亮色填充上出现底部 1px 黑色 20% 内阴影,跟随圆角过渡;顶部无内阴影。
- 暗色主题:顶部 1px 白色 10% 高光 + 底部 1px 黑色 24% 内阴影,共同形成内斜面效果。
- 菜单容器面板、分隔符、页眉页脚等不在本次范围。

验证范围:已核对普通模式亮色与暗色悬浮内阴影的颜色、几何参数与显示条件,通过 exhibition 示例程序做视觉验收。
1 change: 1 addition & 0 deletions qt6/src/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
|---|---|
| 本主文档 | 统一目的、文档结构、状态维度、效果术语、颜色规则、维护和验收要求 |
| [Button.md](Button.md) | 普通 Button 的外形、内容、各渲染元素的显示条件、颜色和参数;不覆盖选中、高亮变体 |
| [Menu.md](Menu.md) | MenuItem 悬浮高亮背景的填充与 1px 底部内阴影、暗色主题 1px 顶部高光;不含菜单容器面板、分隔符等 |
| [QML 维护约束](../qml/.AGENTS) | 简短约束代码与文档同步,引用本规范,不重复详细规则 |

每个控件使用同名子文档,例如 Button.qml 对应 Button.md。子文档按以下顺序组织;不适用项明确说明,无需创建空章节。
Expand Down
10 changes: 10 additions & 0 deletions qt6/src/qml/FlowStyle.qml
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,16 @@ QtObject {
normal: Qt.rgba(0, 0, 0, 0.2)
normalDark: Qt.rgba(1, 1, 1, 0.1)
}
property D.Palette itemHighlightInnerShadow: D.Palette {
// Light: 20% black; Dark: 24% black.
normal: Qt.rgba(0, 0, 0, 0.2)
normalDark: Qt.rgba(0, 0, 0, 0.24)
}
property D.Palette itemHighlightInnerShadowTop: D.Palette {
// Light: no top highlight; Dark: 1px white 10% top inset highlight.
normal: ("transparent")
normalDark: Qt.rgba(1, 1, 1, 0.1)
}

property D.Palette itemText: D.Palette {
normal: ("black")
Expand Down
55 changes: 45 additions & 10 deletions qt6/src/qml/HighlightPanel.qml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2022 - 2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

Expand All @@ -12,6 +12,11 @@ Item {
property D.Palette backgroundColor: DS.Style.highlightPanel.background
property D.Palette outerShadowColor: DS.Style.highlightPanel.dropShadow
property D.Palette innerShadowColor: DS.Style.highlightPanel.innerShadow
// Dual-direction inner shadow palettes for consumers that need a
// top + bottom bevel (e.g. MenuItem hover). Default to null so the
// bevel Loaders stay inactive and existing callers are unaffected.
property D.Palette bevelShadowColor1: null
property D.Palette bevelShadowColor2: null
property int radius: DS.Style.highlightPanel.radius

implicitWidth: DS.Style.highlightPanel.width
Expand All @@ -33,13 +38,43 @@ Item {
radius: panel.radius
}

// BoxInsetShadow {
// anchors.fill: backgroundRect
// visible: panel.innerShadowColor
// shadowColor: panel.D.ColorSelector.innerShadowColor
// shadowOffsetY: -1
// shadowBlur: 2
// spread: 1
// cornerRadius: backgroundRect.radius
// }
// Bottom inner shadow (legacy single-direction API).
Loader {
anchors.fill: backgroundRect
active: panel.innerShadowColor

sourceComponent: BoxInsetShadow {
shadowColor: panel.D.ColorSelector.innerShadowColor
shadowOffsetY: -1
shadowBlur: 2
spread: 1
cornerRadius: backgroundRect.radius
}
}

// Top inner shadow (bevel highlight).
Loader {
anchors.fill: backgroundRect
active: panel.bevelShadowColor1

sourceComponent: BoxInsetShadow {
shadowColor: panel.D.ColorSelector.bevelShadowColor1
shadowOffsetY: 1
shadowBlur: 1
cornerRadius: backgroundRect.radius
}
}

// Bottom inner shadow (bevel shadow).
Loader {
anchors.fill: backgroundRect
active: panel.bevelShadowColor2

sourceComponent: BoxInsetShadow {
shadowColor: panel.D.ColorSelector.bevelShadowColor2
shadowOffsetY: -1
shadowBlur: 1
cornerRadius: backgroundRect.radius
}
}
}
2 changes: 2 additions & 0 deletions qt6/src/qml/MenuItem.qml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ T.MenuItem {
sourceComponent: HighlightPanel {
outerShadowColor: null
innerShadowColor: null
bevelShadowColor1: DS.Style.menu.itemHighlightInnerShadowTop
bevelShadowColor2: DS.Style.menu.itemHighlightInnerShadow
radius: DS.Style.menu.item.radius
}
}
Expand Down
Loading