fix(design,app-iced): 图标尺寸与禁用 α 收敛到官方字节码,两族拆开(M86)
图标:IconSize::Button 16→18(AAR ButtonDefaults.<clinit> 的 bipush 18);新增 IconSize::SwitchThumb=16(SwitchTokens.Selected/UnselectedIconSize)承接开关滑块,按钮与 滑块不再借同一档;IconSize::Nav 的值不动但文档订正(无消费,官方导航/列表图标是 24)。 ButtonSmallTokens.IconSize=20 在整包 AAR 里零消费(javap 搜 getIconSize 无外部调用), 是死令牌,不再作为取值依据。 禁用 α:官方本来就分两族——按钮容器 0.10(*ButtonTokens.DisabledContainerOpacity)与 面状控件 0.12(chip 描边 / slider 轨道 / switch 轨道)。原来的缺陷是一个全局 12% 同时 服务两族(按钮那半边一直错、另半边一直对),现拆成 disabled_button_colors/…_content 与 disabled_colors/disabled_content_over_role 两个入口;interaction 首次超 400 行, 禁用口径与测试搬到 interaction/disabled.rs。 标题栏 caption 三键:官方 SmallIconButtonTokens.IconSize=24,按用户点名缩到 20 (容器 46×48 不动),登记为项目偏离;icons.rs 加按令牌取尺寸的入口 view_at,按 (种类,尺寸) 分别烘焙 SVG,20px 的 stroke 取 1.8 保视觉线宽 1.5px。
This commit is contained in:
1 parent
c825e1aa3d
commit
b566097107
16 files changed
+664
-175
No files matched your search
@@ -0,0 +1,275 @@
|
||||
//! 禁用态的颜色口径:**两个族、两套 α**(M86 收口)。
|
||||
//!
|
||||
//! ## 为什么不是「一个 12%」
|
||||
//!
|
||||
//! 官方禁用 α 分两类(A 级:`material3-android-1.4.0.aar` 的字节码 `<clinit>`):
|
||||
//!
|
||||
//! | 族 | α | 官方 token | 消费者 |
|
||||
//! |---|---|---|---|
|
||||
//! | **按钮容器** | **0.10** | `*ButtonTokens.DisabledContainerOpacity`(`Filled` / `Outlined` / `Text` / `Elevated` / `Tonal` / `Baseline`) | `buttons::assemble` |
|
||||
//! | **面状控件**容器与描边 | **0.12** | `AssistChipTokens.FlatDisabledOutlineOpacity`、`FilterChipTokens.FlatDisabled(SelectedContainer/UnselectedOutline)Opacity`、`SliderTokens.DisabledInactiveTrackOpacity`、`SwitchTokens.DisabledTrackOpacity` | chip / switch / slider / TextField 描边 |
|
||||
//! | 内容(两族共用) | 0.38 | `Disabled{Icon,LabelText,Input}Opacity` | 全部 |
|
||||
//!
|
||||
//! 历史上这里只有一个 12% 常量供两族共用:**按钮那半边一直错、chip/slider/switch 那半边一直对**。
|
||||
//! 现在按族分开两个入口——取错入口的后果是「差 1/255」,肉眼看不见,只有像素 probe 会红,
|
||||
//! 所以入口**必须按名字就能选对**。
|
||||
//!
|
||||
//! ⚠️ TextField 的 **Filled 容器**不在这两族里:官方
|
||||
//! `FilledTextFieldTokens.FieldDisabledContainerOpacity = 0.04f`,我们仍在用面状族的值
|
||||
//! (既有 D10 偏离,未在本轮收口)。`inputs::field` 走 [`disabled_colors`] 的口径,行为未变。
|
||||
|
||||
use iced::Color;
|
||||
|
||||
use unlucky_design::color::state::{
|
||||
DISABLED_CONTAINER_ALPHA, DISABLED_CONTENT_ALPHA, DISABLED_SURFACE_ALPHA,
|
||||
};
|
||||
use unlucky_design::color::{Role, Scheme};
|
||||
|
||||
use crate::theme::{to_iced, Ui};
|
||||
|
||||
/// 禁用态内容色(**按角色、按有没有容器**求值)——A1 口径的入口(**面状控件族**的底)。
|
||||
///
|
||||
/// - `role`:由变体决定(Filled/Outlined/Text/Elevated = `OnSurfaceVariant`;
|
||||
/// FilledTonal 与三式 IconButton = `OnSurface`,见 `Variant::disabled_content`);
|
||||
/// - `on_container = true`:叠在**面状控件族的 12% 容器**([`DISABLED_SURFACE_ALPHA`])上
|
||||
/// (Filled TextField / 有容器控件在 12% 底上求内容时);
|
||||
/// `false`:直接叠在 **surface** 上(Text / Outlined / standard IconButton / 描边类控件的内容)。
|
||||
///
|
||||
/// **按钮家族不要用这个函数**(按钮容器是 10%):走 [`disabled_button_content`]。
|
||||
///
|
||||
/// 之前这里写死 `OnSurfaceVariant` 且只有一个「底」,导致 FilledTonal 与 IconButton 两族偏浅
|
||||
/// 15/255(视觉 r3 用像素量的)。
|
||||
pub fn disabled_content_over_role(ui: &Ui, role: Role, on_container: bool) -> Color {
|
||||
let scheme = Scheme::baseline(ui.flavor());
|
||||
disabled_content_with_alpha(&scheme, role, on_container, DISABLED_SURFACE_ALPHA)
|
||||
}
|
||||
|
||||
/// 禁用态内容色——**按钮家族**(`on_container`:是否叠在本族 10% 容器上)。
|
||||
///
|
||||
/// 与 [`disabled_content_over_role`] 的差别只有「底」的 α:按钮 10%、面状控件 12%。
|
||||
/// 两个入口分开是 M86 的结论:合成一个数会让一族永远差 1/255,肉眼看不见、只有 probe 会红。
|
||||
pub fn disabled_button_content(ui: &Ui, role: Role, on_container: bool) -> Color {
|
||||
let scheme = Scheme::baseline(ui.flavor());
|
||||
disabled_content_with_alpha(&scheme, role, on_container, DISABLED_CONTAINER_ALPHA)
|
||||
}
|
||||
|
||||
/// 两个族共用的内容色求值(「底」的 α 由调用方给)。
|
||||
fn disabled_content_with_alpha(
|
||||
scheme: &Scheme,
|
||||
role: Role,
|
||||
on_container: bool,
|
||||
container_alpha: f32,
|
||||
) -> Color {
|
||||
let base = if on_container {
|
||||
scheme
|
||||
.get(Role::OnSurface)
|
||||
.with_alpha(container_alpha)
|
||||
.over(scheme.get(Role::Surface))
|
||||
} else {
|
||||
scheme.get(Role::Surface)
|
||||
};
|
||||
|
||||
to_iced(
|
||||
scheme
|
||||
.get(role)
|
||||
.with_alpha(DISABLED_CONTENT_ALPHA)
|
||||
.over(base),
|
||||
)
|
||||
}
|
||||
|
||||
/// 禁用态的一对颜色 `(容器, 内容)`——**面状控件族**(12% 容器/描边)。
|
||||
///
|
||||
/// ⚠️ 这个名字是历史遗留(当年只有它一个),**语义是「面状控件族」**:
|
||||
/// - chip 容器与描边(`AssistChipTokens.FlatDisabledOutlineOpacity = 0.12f` 等)
|
||||
/// - switch 轨道(`SwitchTokens.DisabledTrackOpacity = 0.12f`)
|
||||
/// - slider 未激活轨(`SliderTokens.DisabledInactiveTrackOpacity = 0.12f`)
|
||||
/// - TextField 禁用描边(Filled 容器的 4% 是另一条 D10 偏离,不在这里收口)
|
||||
///
|
||||
/// **按钮家族用 [`disabled_button_colors`]**(0.10,`*ButtonTokens.DisabledContainerOpacity = 0.1f`)。
|
||||
///
|
||||
/// `ui` 不暴露 [`Scheme`],这里按同一个 flavor 求一次基线方案——调的是
|
||||
/// `unlucky_design` 的**同一个**函数与同一套角色,不是第二份令牌。
|
||||
///
|
||||
/// 顺序必须「先容器后内容」:Compose 也是这么画的,先叠容器再叠 label,
|
||||
/// 所以内容叠的角色是容器实色而不是底下的 surface。
|
||||
pub fn disabled_colors(ui: &Ui, surface: Role) -> (Color, Color) {
|
||||
disabled_colors_with_alpha(ui, surface, DISABLED_SURFACE_ALPHA)
|
||||
}
|
||||
|
||||
/// 禁用态的一对颜色 `(容器, 内容)`——**按钮家族**(10% 容器)。
|
||||
///
|
||||
/// - 容器 = `OnSurface` @ 10%([`DISABLED_CONTAINER_ALPHA`])叠在 `surface` 上;
|
||||
/// - 内容 = **默认** `OnSurfaceVariant` @ 38%;按变体的取值走 [`disabled_button_content`]。
|
||||
///
|
||||
/// 除了按钮家族,**没有别的消费者**:面状控件(chip / slider 轨道 / switch 轨道 / 描边)走
|
||||
/// [`disabled_colors`] 的 12%。
|
||||
pub fn disabled_button_colors(ui: &Ui, surface: Role) -> (Color, Color) {
|
||||
disabled_colors_with_alpha(ui, surface, DISABLED_CONTAINER_ALPHA)
|
||||
}
|
||||
|
||||
/// 两个族共用的求值:容器 = `OnSurface` @ `container_alpha` 叠在 `surface` 上,内容 = 38% 叠在容器上。
|
||||
fn disabled_colors_with_alpha(ui: &Ui, surface: Role, container_alpha: f32) -> (Color, Color) {
|
||||
let scheme = Scheme::baseline(ui.flavor());
|
||||
let base = scheme.get(surface);
|
||||
let container = scheme
|
||||
.get(Role::OnSurface)
|
||||
.with_alpha(container_alpha)
|
||||
.over(base);
|
||||
// 这里是**默认口径**(OnSurfaceVariant);按变体取值请走 [`disabled_content_over_role`]
|
||||
// ——FilledTonal 与三式 IconButton 的禁用内容是 `OnSurface`(A1)。
|
||||
let content = scheme
|
||||
.get(Role::OnSurfaceVariant)
|
||||
.with_alpha(DISABLED_CONTENT_ALPHA)
|
||||
.over(container);
|
||||
|
||||
(to_iced(container), to_iced(content))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use unlucky_design::color::SchemeFlavor;
|
||||
use unlucky_design::typography::Platform;
|
||||
|
||||
use crate::theme::Families;
|
||||
|
||||
const FAMILIES: Families = Families {
|
||||
text: "Segoe UI",
|
||||
display: "Segoe UI",
|
||||
mono: "Consolas",
|
||||
};
|
||||
|
||||
fn ui(flavor: SchemeFlavor) -> Ui {
|
||||
Ui::with_platform(flavor, Platform::Windows, FAMILIES)
|
||||
}
|
||||
|
||||
/// 两族的 α 必须都钉住(只钉一条,另一族被合并时会静默错 1/255)。
|
||||
#[test]
|
||||
fn both_disabled_alpha_classes_are_pinned_to_the_tokens() {
|
||||
// 绑定成局部变量再过断言:直接比两个常量会被 clippy 判成「常量断言」。
|
||||
let button_alpha = DISABLED_CONTAINER_ALPHA;
|
||||
let surface_alpha = DISABLED_SURFACE_ALPHA;
|
||||
let content_alpha = DISABLED_CONTENT_ALPHA;
|
||||
// 按钮容器:官方 *ButtonTokens.DisabledContainerOpacity = 0.1f
|
||||
assert!(
|
||||
(button_alpha - 0.10).abs() < f32::EPSILON,
|
||||
"按钮禁用容器 α 必须是 0.10(官方 DisabledContainerOpacity);\
|
||||
0.12 是面状控件那一类,别混用"
|
||||
);
|
||||
// 面状控件:chip 描边 / slider 未激活轨 / switch 轨道 = 0.12f
|
||||
assert!(
|
||||
(surface_alpha - 0.12).abs() < f32::EPSILON,
|
||||
"面状控件禁用 α 必须是 0.12(官方 FlatDisabledOutlineOpacity / \
|
||||
DisabledInactiveTrackOpacity / DisabledTrackOpacity)"
|
||||
);
|
||||
assert!((content_alpha - 0.38).abs() < f32::EPSILON);
|
||||
assert!(
|
||||
surface_alpha > button_alpha,
|
||||
"两族必须可区分:面状控件比按钮容器更实({surface_alpha} > {button_alpha})"
|
||||
);
|
||||
}
|
||||
|
||||
/// **面状控件族**的那一对颜色 = 0.12 预混合(chip / switch / slider / TextField 描边)。
|
||||
///
|
||||
/// `disabled_colors` 的名字是历史遗留,语义是这一族。谁把 12% 改成 10%,这条红。
|
||||
#[test]
|
||||
fn surface_family_disabled_colors_are_the_12_percent_class() {
|
||||
for flavor in [SchemeFlavor::Light, SchemeFlavor::Dark] {
|
||||
let ui = ui(flavor);
|
||||
let scheme = Scheme::baseline(flavor);
|
||||
let base = scheme.get(Role::Surface);
|
||||
let expected_container = scheme
|
||||
.get(Role::OnSurface)
|
||||
.with_alpha(DISABLED_SURFACE_ALPHA)
|
||||
.over(base);
|
||||
|
||||
let (surface, surface_content) = disabled_colors(&ui, Role::Surface);
|
||||
assert_eq!(
|
||||
surface,
|
||||
to_iced(expected_container),
|
||||
"{flavor:?}:面状控件容器 = on-surface@12% 叠表面"
|
||||
);
|
||||
assert_eq!(
|
||||
surface_content,
|
||||
to_iced(
|
||||
scheme
|
||||
.get(Role::OnSurfaceVariant)
|
||||
.with_alpha(DISABLED_CONTENT_ALPHA)
|
||||
.over(expected_container)
|
||||
),
|
||||
"{flavor:?}:面状控件内容仍是 38%,只是叠的底不同"
|
||||
);
|
||||
assert_ne!(surface, ui.color(Role::Surface), "12% 叠上去必须能看出来");
|
||||
assert_eq!(surface.a, 1.0, "禁用容器也是实色(CPU/GPU 一致)");
|
||||
assert_eq!(surface_content.a, 1.0, "禁用内容也是实色");
|
||||
// 内容叠在容器上 vs 叠在表面上,是两回事(probe 量的是前者)
|
||||
assert_ne!(
|
||||
surface_content,
|
||||
to_iced(
|
||||
scheme
|
||||
.get(Role::OnSurfaceVariant)
|
||||
.with_alpha(DISABLED_CONTENT_ALPHA)
|
||||
.over(base)
|
||||
),
|
||||
"{flavor:?}:内容必须叠在容器上"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// **按钮家族**的那一对颜色 = 0.10 预混合,且与面状控件族**必须落在不同像素值上**。
|
||||
///
|
||||
/// 这条是「拆族真的发生了」的判据:把 `disabled_button_colors` 改回 0.12,它在
|
||||
/// `expected` 与 `assert_ne!` 上同时红;两个入口合并回一个常量,也只有它红。
|
||||
#[test]
|
||||
fn button_family_disabled_colors_are_the_10_percent_class() {
|
||||
for flavor in [SchemeFlavor::Light, SchemeFlavor::Dark] {
|
||||
let ui = ui(flavor);
|
||||
let scheme = Scheme::baseline(flavor);
|
||||
let base = scheme.get(Role::Surface);
|
||||
let expected_container = scheme
|
||||
.get(Role::OnSurface)
|
||||
.with_alpha(DISABLED_CONTAINER_ALPHA)
|
||||
.over(base);
|
||||
|
||||
let (button, button_content) = disabled_button_colors(&ui, Role::Surface);
|
||||
assert_eq!(
|
||||
button,
|
||||
to_iced(expected_container),
|
||||
"{flavor:?}:按钮容器 = on-surface@10% 叠表面(官方 DisabledContainerOpacity = 0.1f)"
|
||||
);
|
||||
assert_eq!(
|
||||
button_content,
|
||||
to_iced(
|
||||
scheme
|
||||
.get(Role::OnSurfaceVariant)
|
||||
.with_alpha(DISABLED_CONTENT_ALPHA)
|
||||
.over(expected_container)
|
||||
),
|
||||
);
|
||||
|
||||
let (surface, _) = disabled_colors(&ui, Role::Surface);
|
||||
assert_ne!(
|
||||
button, surface,
|
||||
"{flavor:?}:10% 与 12% 必须落在不同像素值上(合成一个数就是这次要防的回归)"
|
||||
);
|
||||
|
||||
// 内容色同理:按钮 38% 叠 10% 底 ≠ 面状 38% 叠 12% 底
|
||||
assert_ne!(
|
||||
button_content,
|
||||
disabled_content_over_role(&ui, Role::OnSurfaceVariant, true),
|
||||
"{flavor:?}:两族的「有容器」内容色不能同源"
|
||||
);
|
||||
assert_eq!(
|
||||
disabled_button_content(&ui, Role::OnSurfaceVariant, true),
|
||||
button_content,
|
||||
"{flavor:?}:按钮内容入口必须与按钮颜色入口同源"
|
||||
);
|
||||
// 无容器时两族完全一致(都叠 surface)——差异只在「有容器」那一支
|
||||
assert_eq!(
|
||||
disabled_button_content(&ui, Role::OnSurfaceVariant, false),
|
||||
disabled_content_over_role(&ui, Role::OnSurfaceVariant, false),
|
||||
"{flavor:?}:没有容器时不该有族差异"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,9 +13,29 @@
|
||||
//! | focus | 0.10 | [`StateLayer::Focus`] |
|
||||
//! | pressed | 0.10 | [`StateLayer::Pressed`] |
|
||||
//! | dragged | 0.16 | [`StateLayer::Dragged`](按钮家族不用,列表拖拽用) |
|
||||
//! | disabled 容器 | 0.12 | [`DISABLED_CONTAINER_ALPHA`](**A1 是 0.10f**,本文件按令牌 0.12,差异登记 D8) |
|
||||
//! | disabled 容器(**按钮家族**) | 0.10 | [`DISABLED_CONTAINER_ALPHA`](按钮 `*ButtonTokens.DisabledContainerOpacity`) |
|
||||
//! | disabled 容器/描边(**面状控件族**) | 0.12 | [`DISABLED_SURFACE_ALPHA`](chip / slider 轨道 / switch 轨道 / TextField 禁用描边) |
|
||||
//! | disabled 内容 | 0.38 | [`DISABLED_CONTENT_ALPHA`] |
|
||||
//!
|
||||
//! ## ⚠️ 禁用 α 有**两类**(M86 收口,别再合成一个数)
|
||||
//!
|
||||
//! 官方禁用 α 从来不是「一个 12%」:
|
||||
//!
|
||||
//! - **按钮容器 0.10**:`BaselineButtonTokens` / `FilledButtonTokens` / `OutlinedButtonTokens` /
|
||||
//! `TextButtonTokens` / `ElevatedButtonTokens` / `TonalButtonTokens` 的 `DisabledContainerOpacity`
|
||||
//! = `0.1f`(AAR 字节码 `<clinit>` 里的 `ldc 0.1f`);
|
||||
//! - **面状控件 0.12**:`AssistChipTokens.FlatDisabledOutlineOpacity` / `FilterChipTokens.
|
||||
//! FlatDisabledSelectedContainerOpacity` / `SliderTokens.DisabledInactiveTrackOpacity` /
|
||||
//! `SwitchTokens.DisabledTrackOpacity` 都是 `0.12f`。
|
||||
//!
|
||||
//! 本模块过去只有一个 12% 常量供两条线共用:**按钮那半边一直错、chip/slider/switch 那半边一直对**。
|
||||
//! 现在按族分两个入口,谁也别再拿一个数服务两族:
|
||||
//!
|
||||
//! | 入口 | α | 谁用 |
|
||||
//! |---|---|---|
|
||||
//! | [`disabled_button_colors`] / [`disabled_button_content`] | 0.10 | **只有按钮家族**(`buttons::assemble`) |
|
||||
//! | [`disabled_colors`] / [`disabled_content_over_role`] | 0.12 | **面状控件族**:chip 容器与描边、switch 轨道、slider 未激活轨、TextField 禁用描边(`disabled_colors` 这个名字是历史遗留,**语义是面状控件族**) |
|
||||
//!
|
||||
//! 上表右列是**唯一**允许的取值口;左列只是给人看的,代码里一个数字都不许出现
|
||||
//! (`components::gate` 会扫)。
|
||||
//!
|
||||
@@ -33,10 +53,9 @@
|
||||
use iced::widget::button;
|
||||
use iced::Color;
|
||||
|
||||
use unlucky_design::color::state::{DISABLED_CONTAINER_ALPHA, DISABLED_CONTENT_ALPHA};
|
||||
use unlucky_design::color::{Role, Scheme, StateLayer};
|
||||
use unlucky_design::color::{Role, StateLayer};
|
||||
|
||||
use crate::theme::{to_iced, Ui};
|
||||
use crate::theme::Ui;
|
||||
|
||||
mod tracker;
|
||||
|
||||
@@ -63,7 +82,7 @@ pub enum Interaction {
|
||||
Focused,
|
||||
/// 按下:叠 10%。
|
||||
Pressed,
|
||||
/// 禁用:容器 12% / 内容 38%,**不叠状态层**。
|
||||
/// 禁用:按钮容器 10% / 面状控件 12% / 内容 38%,**不叠状态层**。
|
||||
Disabled,
|
||||
}
|
||||
|
||||
@@ -125,60 +144,11 @@ pub fn overlay_color(ui: &Ui, state: Interaction, content: Role, container: Role
|
||||
.map(|layer| ui.state_over(layer, content, container))
|
||||
}
|
||||
|
||||
/// 禁用态内容色(**按角色、按有没有容器**求值)——A1 口径的唯一入口。
|
||||
///
|
||||
/// - `role`:由变体决定(Filled/Outlined/Text/Elevated = `OnSurfaceVariant`;
|
||||
/// FilledTonal 与三式 IconButton = `OnSurface`,见 `Variant::disabled_content`);
|
||||
/// - `on_container = true`:叠在 **12% 容器**上(有容器的三式);
|
||||
/// `false`:直接叠在 **surface** 上(Text / Outlined / standard IconButton)。
|
||||
///
|
||||
/// 之前这里写死 `OnSurfaceVariant` 且只有一个「底」,导致 FilledTonal 与 IconButton 两族偏浅
|
||||
/// 15/255(视觉 r3 用像素量的)。
|
||||
pub fn disabled_content_over_role(ui: &Ui, role: Role, on_container: bool) -> Color {
|
||||
let scheme = Scheme::baseline(ui.flavor());
|
||||
let base = if on_container {
|
||||
scheme
|
||||
.get(Role::OnSurface)
|
||||
.with_alpha(DISABLED_CONTAINER_ALPHA)
|
||||
.over(scheme.get(Role::Surface))
|
||||
} else {
|
||||
scheme.get(Role::Surface)
|
||||
};
|
||||
mod disabled;
|
||||
|
||||
to_iced(
|
||||
scheme
|
||||
.get(role)
|
||||
.with_alpha(DISABLED_CONTENT_ALPHA)
|
||||
.over(base),
|
||||
)
|
||||
}
|
||||
|
||||
/// 禁用态的一对颜色 `(容器, 内容)`,内容按令牌口径叠在**算好的容器**之上。
|
||||
///
|
||||
/// - 容器 = `OnSurface` @ 12%([`DISABLED_CONTAINER_ALPHA`];A1 是 0.10f,见 D8)叠在 `surface` 上;
|
||||
/// - 内容 = **默认** `OnSurfaceVariant` @ 38%;按变体的取值走 [`disabled_content_over_role`]。
|
||||
///
|
||||
/// `ui` 不暴露 [`Scheme`],这里按同一个 flavor 求一次基线方案——调的是
|
||||
/// `unlucky_design` 的**同一个**函数与同一套角色,不是第二份令牌。
|
||||
///
|
||||
/// 顺序必须「先容器后内容」:Compose 也是这么画的,先叠容器再叠 label,
|
||||
/// 所以内容叠的角色是容器实色而不是底下的 surface。
|
||||
pub fn disabled_colors(ui: &Ui, surface: Role) -> (Color, Color) {
|
||||
let scheme = Scheme::baseline(ui.flavor());
|
||||
let base = scheme.get(surface);
|
||||
let container = scheme
|
||||
.get(Role::OnSurface)
|
||||
.with_alpha(DISABLED_CONTAINER_ALPHA)
|
||||
.over(base);
|
||||
// 这里是**默认口径**(OnSurfaceVariant);按变体取值请走 [`disabled_content_over_role`]
|
||||
// ——FilledTonal 与三式 IconButton 的禁用内容是 `OnSurface`(A1)。
|
||||
let content = scheme
|
||||
.get(Role::OnSurfaceVariant)
|
||||
.with_alpha(DISABLED_CONTENT_ALPHA)
|
||||
.over(container);
|
||||
|
||||
(to_iced(container), to_iced(content))
|
||||
}
|
||||
pub use disabled::{
|
||||
disabled_button_colors, disabled_button_content, disabled_colors, disabled_content_over_role,
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
@@ -198,15 +168,16 @@ mod tests {
|
||||
Ui::with_platform(flavor, Platform::Windows, FAMILIES)
|
||||
}
|
||||
|
||||
/// 契约 §3 的 α 全表:**钉住令牌值**(改令牌会让这条红,改组件抓不到)。
|
||||
/// 契约 §3 的状态层 α 全表:**钉住令牌值**(改令牌会让这条红,改组件抓不到)。
|
||||
///
|
||||
/// 禁用态的两族 α(按钮 0.10 / 面状控件 0.12)在 [`super::disabled`] 的测试里,
|
||||
/// 那边还负责「两族不能同源」的判据。
|
||||
#[test]
|
||||
fn state_layer_alphas_are_the_contract_values() {
|
||||
assert!((StateLayer::Hover.alpha() - 0.08).abs() < f32::EPSILON);
|
||||
assert!((StateLayer::Focus.alpha() - 0.10).abs() < f32::EPSILON);
|
||||
assert!((StateLayer::Pressed.alpha() - 0.10).abs() < f32::EPSILON);
|
||||
assert!((StateLayer::Dragged.alpha() - 0.16).abs() < f32::EPSILON);
|
||||
assert!((DISABLED_CONTAINER_ALPHA - 0.12).abs() < f32::EPSILON);
|
||||
assert!((DISABLED_CONTENT_ALPHA - 0.38).abs() < f32::EPSILON);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -265,34 +236,4 @@ mod tests {
|
||||
assert_ne!(hover, pressed, "8% 与 10% 必须能区分");
|
||||
assert_eq!(hover.a, 1.0, "结果必须不透明(GPU/CPU 逐像素一致)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn disabled_colors_come_from_the_token_functions() {
|
||||
let ui = ui(SchemeFlavor::Light);
|
||||
let scheme = Scheme::baseline(SchemeFlavor::Light);
|
||||
|
||||
let (container, content) = disabled_colors(&ui, Role::Surface);
|
||||
let base = scheme.get(Role::Surface);
|
||||
let expected_container = scheme
|
||||
.get(Role::OnSurface)
|
||||
.with_alpha(DISABLED_CONTAINER_ALPHA)
|
||||
.over(base);
|
||||
assert_eq!(
|
||||
container,
|
||||
to_iced(expected_container),
|
||||
"容器 = on-surface@12% 叠表面"
|
||||
);
|
||||
assert_eq!(
|
||||
content,
|
||||
to_iced(
|
||||
scheme
|
||||
.get(Role::OnSurfaceVariant)
|
||||
.with_alpha(DISABLED_CONTENT_ALPHA)
|
||||
.over(expected_container)
|
||||
),
|
||||
);
|
||||
assert_ne!(container, ui.color(Role::Surface), "12% 叠上去必须能看出来");
|
||||
assert_eq!(container.a, 1.0, "禁用容器也是实色(CPU/GPU 一致)");
|
||||
assert_eq!(content.a, 1.0, "禁用内容也是实色");
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user