fix(app-iced): 复审 r1 四条 P2 收口(M234)
- P2-1 判据恒绿:`gallery/probe/bases.rs` 的「反向检查」把字段档计数(`:172` 遮蔽后的
`hits`)拿去比按钮档 stray ⇒ 恒绿。改成 `button_hits` / `field_hits` 两个计数,各比各的
stray,失败信息的数值与单位对齐量测对象。变异自证:卡列里留一颗忘了 `.base(..)` 的按钮
⇒ 该断言单独红(2137 px vs 3178 px,退出码 101)。
- P2-2 FAB 的底错了:禁用态背景仍是满档 `PrimaryContainer`(`Disabled.layer() == None`),
38% 内容却合在画布上。改成 `Base::of(PrimaryContainer)` + `on_container = false`
(那一层 10% 在 FAB 身上不存在),两处调用收进一个 `content_color()`;新增值判据
`disabled_fab_ink_composites_over_its_own_container`(修前 #8CA0AA / 修后 #548FBC 量级)。
- P2-3 漏改:`selection::paint::state_layer()`(hover/focus/pressed)与 `list_item` 的
状态层叠底仍写死 `Role::Surface`,改成跟 `base`;同类两处(`assemble::transparent_state_color`
的 Outlined/Text hover、drawer 项药丸)一并跟上。
- P2-4 文档失真:`feedback/{action,mod}.rs` 删掉「本地 α 合成 / 规则只认两档」的旧描述
与失效链接;`list_item` 的旧签名;三处 `probe/base.rs` → `probe/bases.rs`;
新增 `surfaces::elevated::tests::the_card_base_constant_is_the_role_the_card_paints`
真断言(原来只在文档里声称那条测试守 `BASE`),并把这句描述改准。
- nit:`disabledbase.rs` 字符串里塌成一行的续行空格、probe 汇总行把列左缘横坐标说成
「像素计数」的措辞。
门禁(CARGO_TARGET_DIR=C:/Temp/ull-target/wt-234):fmt / check --all-targets /
test -p unlucky-app-iced(896 + 6 通过,0 失败)/ clippy --workspace --all-targets -D warnings /
文件 ≤400 全绿;probe 浅色与深色都过。
This commit is contained in:
1 parent
35dbefb08d
commit
9bb3c33b8c
17 files changed
+190
-72
No files matched your search
@@ -208,7 +208,7 @@ pub(super) fn style_closure(
|
||||
.or(Some(ui.color(role))),
|
||||
None => Some(ui.color(role)),
|
||||
},
|
||||
None => transparent_state_color(ui, state, spec.content),
|
||||
None => transparent_state_color(ui, spec.base, state, spec.content),
|
||||
};
|
||||
(background, ui.color(spec.content))
|
||||
}
|
||||
@@ -246,14 +246,18 @@ pub(super) fn style_closure(
|
||||
}
|
||||
|
||||
/// 透明容器的状态层:`Outlined` / `Text` / `StandardIcon` 没有填充,可见反馈只能来自
|
||||
/// 叠在**内容角色**上的状态层——把它们当作「叠在表面色上」求值,得到不透明实色。
|
||||
/// 叠在**内容角色**上的状态层——把它们当作「叠在 `base`(脚下那一层)上」求值,得到不透明实色。
|
||||
///
|
||||
/// 之所以单独一个函数:这是 M3 里唯一「容器不存在但状态层存在」的情形,
|
||||
/// 三个变体共用一条口径,免得各自发挥。
|
||||
///
|
||||
/// M234 复审 P2-3:`base` 之前写死 `Role::Surface`,卡片里的 Text/Outlined 按钮抬起时
|
||||
/// 状态层叠在画布色上(与禁用支的口径不一致)。
|
||||
pub(super) fn transparent_state_color(
|
||||
ui: &Ui,
|
||||
base: Base,
|
||||
state: Interaction,
|
||||
content: Role,
|
||||
) -> Option<iced::Color> {
|
||||
interaction::overlay_color(ui, state, content, Role::Surface)
|
||||
interaction::overlay_color(ui, state, content, base.role())
|
||||
}
|
||||
@@ -86,6 +86,34 @@ impl<'a, M> Fab<'a, M> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 禁用态的内容色:`OnPrimaryContainer` @38% 叠在 **FAB 自己的容器**(`PrimaryContainer`)上。
|
||||
///
|
||||
/// ## 为什么底是 FAB 自己的容器,不是画布(M234 复审 P2-2)
|
||||
///
|
||||
/// 五式按钮的禁用容器是「`OnSurface`@10% 叠在脚下那一层」——透明的那种甚至没有容器;所以它们的
|
||||
/// 内容要叠 `0.10 容器 → 父底`。FAB 不一样:`Interaction::Disabled.layer()` 是 `None`,
|
||||
/// 样式闭包走 `None => Some(ui.color(Role::PrimaryContainer))`,**禁用时背景仍是满档
|
||||
/// `PrimaryContainer`**(官方 `FloatingActionButtonTokens` 也没有 DisabledContainerOpacity)。
|
||||
/// 所以内容只能叠 `PrimaryContainer` 本身,`on_container = false`——那一层 10% 在 FAB 身上
|
||||
/// 根本不存在,给了反而多算一层灰。
|
||||
///
|
||||
/// 修前传 `Base::CANVAS`:38% 的 `OnPrimaryContainer` 合在画布色上,出来是一块与 FAB 底无关的灰
|
||||
/// (Silver 浅色实测是一块灰 `rgb(0.549,0.627,0.667)`),而不是「深色字压在淡蓝容器上」
|
||||
/// 的应有结果(同板上正确值是 `rgb(0.329,0.561,0.737)`;数字见 artifacts/m234 的 README)。
|
||||
///
|
||||
/// `button()` 与样式闭包**共用这一个函数**:早先两处各写一遍,两次都传了同一个错值。
|
||||
fn content_color(ui: &Ui, forced: Option<Interaction>) -> iced::Color {
|
||||
match forced {
|
||||
Some(Interaction::Disabled) => interaction::disabled_button_content(
|
||||
ui,
|
||||
Base::of(Role::PrimaryContainer),
|
||||
Role::OnPrimaryContainer,
|
||||
false,
|
||||
),
|
||||
_ => ui.color(Role::OnPrimaryContainer),
|
||||
}
|
||||
}
|
||||
|
||||
/// 画一颗 FAB。
|
||||
pub fn fab<'a, M: Clone + 'a>(ui: &'a Ui, spec: Fab<'a, M>) -> Element<'a, M> {
|
||||
let size = spec.size;
|
||||
@@ -94,13 +122,8 @@ pub fn fab<'a, M: Clone + 'a>(ui: &'a Ui, spec: Fab<'a, M>) -> Element<'a, M> {
|
||||
} else {
|
||||
None
|
||||
});
|
||||
let ink = match forced {
|
||||
// 禁用:38% 的内容色叠在容器上(与按钮族的容器档同一口径)
|
||||
Some(Interaction::Disabled) => {
|
||||
interaction::disabled_button_content(ui, Base::CANVAS, Role::OnPrimaryContainer, true)
|
||||
}
|
||||
_ => ui.color(Role::OnPrimaryContainer),
|
||||
};
|
||||
// 内容色(含禁用档)只走 `content_color` 一处
|
||||
let ink = content_color(ui, forced);
|
||||
|
||||
let glyph = layout::fixed(
|
||||
size.icon_px(),
|
||||
@@ -159,11 +182,7 @@ pub fn fab<'a, M: Clone + 'a>(ui: &'a Ui, spec: Fab<'a, M>) -> Element<'a, M> {
|
||||
.or(Some(ui.color(Role::PrimaryContainer))),
|
||||
None => Some(ui.color(Role::PrimaryContainer)),
|
||||
};
|
||||
let text_color = if state.is_disabled() {
|
||||
interaction::disabled_button_content(ui, Base::CANVAS, Role::OnPrimaryContainer, true)
|
||||
} else {
|
||||
ui.color(Role::OnPrimaryContainer)
|
||||
};
|
||||
let text_color = content_color(ui, Some(state));
|
||||
|
||||
button::Style {
|
||||
background: background.map(Background::Color),
|
||||
|
||||
@@ -1,9 +1,29 @@
|
||||
//! FAB 的几何断言(四档尺寸/圆角/图标/内距,全部对着规格卡原值)。
|
||||
//!
|
||||
//! 抓得住:档位与规格卡错位(例如把 Default 写成 48)、圆角被写成半高、扩展态内距悄悄改成 M3 的 16。
|
||||
//! 抓不住:配色与状态层(那走 `interaction` 的既有测试)、以及图上好不好看(D30)。
|
||||
//! 抓不住:图上好不好看(D30),以及 hover/pressed 的状态层(那走 `interaction` 的既有测试)。
|
||||
//!
|
||||
//! 配色只钉**一条**(禁用内容色,M234 复审 P2-2):FAB 没有禁用容器档,所以 38% 必须合在
|
||||
//! 自己的 `PrimaryContainer` 上,而不是画布色。其余配色仍由 `interaction` 的测试覆盖。
|
||||
|
||||
use unlucky_design::color::{Role, SchemeFlavor};
|
||||
use unlucky_design::inkcat::size::FabSize;
|
||||
use unlucky_design::typography::Platform;
|
||||
|
||||
use super::super::super::interaction::Interaction;
|
||||
use crate::theme::{to_iced, Families, Ui};
|
||||
|
||||
fn ui(flavor: SchemeFlavor) -> Ui {
|
||||
Ui::with_platform(
|
||||
flavor,
|
||||
Platform::Windows,
|
||||
Families {
|
||||
text: "Segoe UI",
|
||||
display: "Segoe UI",
|
||||
mono: "Consolas",
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_four_states_are_the_spec_sizes() {
|
||||
@@ -52,3 +72,44 @@ fn the_extended_pad_end_is_a_named_constant() {
|
||||
"左右对称:规格卡只量到起始 28,右侧取同值"
|
||||
);
|
||||
}
|
||||
|
||||
/// **M234 复审 P2-2 的判据**:禁用 FAB 的内容色必须合在**自己的容器**上。
|
||||
///
|
||||
/// 走的是真实现(`fab::content_color`,`button()` 与样式闭包共用它)。抓得住:底又改回画布
|
||||
/// (那就是修前那块与 FAB 底无关的灰)、或有人把 `on_container` 打开(会多算一层
|
||||
/// 10% 的 `OnSurface` 灰)。抓不住:容器本身该不该在禁用时保持满档 `PrimaryContainer`
|
||||
/// (那是 M3 FAB token 的口径问题,不由本测试裁决)。
|
||||
#[test]
|
||||
fn disabled_fab_ink_composites_over_its_own_container() {
|
||||
for flavor in [SchemeFlavor::Light, SchemeFlavor::Dark] {
|
||||
let ui = ui(flavor);
|
||||
let scheme = unlucky_design::color::BrandBoard::for_flavor(flavor).scheme();
|
||||
// 期望值独立算:38% 的 OnPrimaryContainer 叠在满档 PrimaryContainer 上
|
||||
let expected = to_iced(
|
||||
scheme
|
||||
.get(Role::OnPrimaryContainer)
|
||||
.with_alpha(0.38)
|
||||
.over(scheme.get(Role::PrimaryContainer)),
|
||||
);
|
||||
let actual = super::content_color(&ui, Some(Interaction::Disabled));
|
||||
assert_eq!(
|
||||
actual, expected,
|
||||
"{flavor:?}:禁用 FAB 的内容色 = on-primary-container@38% 叠 PrimaryContainer"
|
||||
);
|
||||
|
||||
// 反向:不许等于「叠画布」那一档(修前的错值)
|
||||
let over_canvas = to_iced(
|
||||
scheme
|
||||
.get(Role::OnPrimaryContainer)
|
||||
.with_alpha(0.38)
|
||||
.over(scheme.get(Role::Surface)),
|
||||
);
|
||||
assert_ne!(actual, over_canvas, "{flavor:?}:又合到画布上了");
|
||||
|
||||
// 非禁用档不受影响
|
||||
assert_eq!(
|
||||
super::content_color(&ui, Some(Interaction::Enabled)),
|
||||
ui.color(Role::OnPrimaryContainer)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -13,9 +13,10 @@
|
||||
//! ## 禁用是状态不是构造器
|
||||
//!
|
||||
//! 照 `selection/chip.rs` 修好的模式:`on_press: Option<M>`,`None` = 禁用;文字色降到
|
||||
//! `OnSurface@38%`,标签本身**不删**。禁用色的**底**必须是这两个动作件自己的容器角色
|
||||
//! (`InverseSurface` / `SurfaceContainerHigh`)——`interaction::disabled_content_over_role`
|
||||
//! 只支持「叠在 Surface / 叠在 12% 容器上」两档,拿它合成会得到「38% 深字叠深底」(复审 P2-4)。
|
||||
//! `OnSurface@38%`,标签本身**不删**。禁用色的**底**是这两个动作件自己的容器角色
|
||||
//! (`InverseSurface` / `SurfaceContainerHigh`)——M234 起
|
||||
//! [`interaction::disabled_content_over_role`] 收任意底([`interaction::Base`]),所以这里
|
||||
//! **直接传容器角色**,不再自己写一遍 α 合成(M234 之前那段本地合成会得到「38% 深字叠深底」,复审 P2-4)。
|
||||
|
||||
use iced::widget::{button, text};
|
||||
use iced::{Background, Border, Element, Length, Padding, Shadow};
|
||||
@@ -32,12 +33,12 @@ use crate::theme::Ui;
|
||||
use super::super::interaction::{self, Interaction};
|
||||
use super::super::layout;
|
||||
|
||||
/// 禁用态内容色:`OnSurface@38%` 叠在**真实容器色**上(复审 P2-4)。
|
||||
/// 禁用态内容色:`OnSurface@38%` 叠在**真实容器色**上。
|
||||
///
|
||||
/// `interaction::disabled_content_over_role` 的 `on_container` 只有「叠在 Surface / 叠在
|
||||
/// 12% 容器上」两档,而这两个动作件的底是 `InverseSurface`(Snackbar)与
|
||||
/// `SurfaceContainerHigh`(Dialog)——直接调它会得到「38% 深字叠深底」。
|
||||
/// 这里按同一令牌口径([`DISABLED_CONTENT_ALPHA`])在本文件合成一次,底换成真实容器角色。
|
||||
/// 这两个动作件的底是 `InverseSurface`(Snackbar)与 `SurfaceContainerHigh`(Dialog),
|
||||
/// M234 之后 `interaction::disabled_content_over_role` 收任意 [`interaction::Base`],所以
|
||||
/// 这里只把容器角色包成 `Base` 交给它——α(0.38)与叠法仍由 `interaction::disabled` 一处给,
|
||||
/// 本文件零 α 字面量、也没有第二份合成实现。
|
||||
fn content_color(ui: &Ui, role: Role, container_role: Role, disabled: bool) -> iced::Color {
|
||||
if !disabled {
|
||||
return ui.color(role);
|
||||
|
||||
@@ -17,10 +17,9 @@
|
||||
//! 1. **数值来自哪里**:颜色/字级/圆角/内距走令牌(`Role` / `TypeRole` / `ShapeScale` / `Space`),
|
||||
//! 进度厚度、Snackbar 宽高、Dialog 宽、空态块这四组令牌层没有 → 登记 **G17**([`geometry`])。
|
||||
//! 2. **状态层只有一处**:hover/pressed 的叠色一律经 [`interaction::overlay_color`];
|
||||
//! 禁用内容默认经 [`interaction::disabled_content_over_role`],但**动作件是个例外**——
|
||||
//! `action.rs` 的 `content_color()` 把 38% 内容色叠在它**自己的容器角色**上
|
||||
//! (`InverseSurface` / `SurfaceContainerHigh`),因为 `interaction` 那两档只认
|
||||
//! 「叠在 Surface / 12% 容器上」;
|
||||
//! 禁用内容一律经 [`interaction::disabled_content_over_role`],**底由容器给**
|
||||
//! ([`interaction::Base`]):`action.rs` 传的是这两个动作件自己的容器角色
|
||||
//! (`InverseSurface` / `SurfaceContainerHigh`),其余组件传 `Base::CANVAS`;
|
||||
//! 禁用是**状态**(`on_press: Option<M>` 为 `None`),不是另一个构造器(M77 之前 Chip 踩过)。
|
||||
//! 3. **精确尺寸经 `layout`**:图标/几何图元一律 `layout::fixed` / `layout::centered_fixed`(Q9),
|
||||
//! 居中一律父级 `align_x/align_y`(Q8,不许 `center_*`)。
|
||||
|
||||
@@ -10,21 +10,21 @@
|
||||
//! 这里把三列**并排**摆出来,每列一块板、板底就是控件真踩的那层底:
|
||||
//!
|
||||
//! ```text
|
||||
//! canvas Surface ← 页面底色
|
||||
//! card SurfaceContainer ← `surfaces::elevated::card` 的底(`elevated::BASE`)
|
||||
//! panel SurfaceContainerLow ← Card 层(取景板 / 面板)
|
||||
//! canvas Surface ← 页面底色
|
||||
//! card SurfaceContainer ← `surfaces::elevated::card` 的底(`elevated::BASE`)
|
||||
//! panel SurfaceContainerLow ← Card 层(取景板 / 面板)
|
||||
//! ```
|
||||
//!
|
||||
//! 每列都是**同一族控件**:Filled/Outlined 禁用按钮、Filled 禁用字段、禁用开关与 chip、
|
||||
//! 禁用搜索条、禁用列表项、禁用滑块、禁用 tab。控件拿的都是这一列的 [`Base`],
|
||||
//! 所以列与列之间的差别只有「底」。
|
||||
//!
|
||||
//! ## 判据(数值在 `probe/base.rs`)
|
||||
//! ## 判据(数值在 `probe/bases.rs`)
|
||||
//!
|
||||
//! 像素判据判的是**精确值**:卡列里的禁用按钮容器必须等于 `on-surface@10% 叠卡片底`,
|
||||
//! 且**不等于**画布底那一档。注意量级:Ink/Silver 板上 `Surface` 与 `SurfaceContainer`
|
||||
//! 只差个位数 RGB,10% 之后差 **≈1/255**——肉眼看不出来,所以这张图的用处是**取证**,
|
||||
//! 不是「看出区别」。真判据在 `interaction::disabled::tests`(逐值)与 `probe/base.rs`(像素)。
|
||||
//! 不是「看出区别」。真判据在 `interaction::disabled::tests`(逐值)与 `probe/bases.rs`(像素)。
|
||||
//!
|
||||
//! ```text
|
||||
//! ULL_GALLERY_SECTION=disabledbase $EXE --software-renderer --screen=gallery \
|
||||
@@ -94,9 +94,7 @@ pub(super) fn section<'a>(ui: &'a Ui) -> Element<'a, DemoMessage> {
|
||||
),
|
||||
row(columns).spacing(ui.space(Space::X2)),
|
||||
text(
|
||||
"三列的控件完全相同,只有脚下的底不同。禁用容器保留 90% 的底差(10% 只叠 on-surface),
|
||||
所以列间的差别 = 底差的九成(浅色 Silver 底差 11/255、深色 Ink 底差 6/255)。
|
||||
这张图是取证;判据在 `interaction::disabled::tests`(逐值)与 `gallery::probe` 的 disabledbase 段(精确像素)",
|
||||
"三列的控件完全相同,只有脚下的底不同。禁用容器保留 90% 的底差(10% 只叠 on-surface),所以列间差别 = 底差的九成(浅色 Silver 11/255、深色 Ink 6/255)。这张图是取证;判据在 `interaction::disabled::tests`(逐值)与 `gallery::probe` 的 disabledbase 段(精确像素)",
|
||||
)
|
||||
.size(note.size_px)
|
||||
.font(ui.font_of(note))
|
||||
|
||||
@@ -155,7 +155,7 @@ fn gallery_geometry_matches_the_tokens() {
|
||||
check_divider(&shot, &ui);
|
||||
return;
|
||||
}
|
||||
// 禁用态合成底(M234):三块板各按自己的底合成,判据在 `probe/base.rs`。
|
||||
// 禁用态合成底(M234):三块板各按自己的底合成,判据在 `probe/bases.rs`。
|
||||
if section == "disabledbase" {
|
||||
bases::check(&shot, &ui, flavor);
|
||||
return;
|
||||
|
||||
@@ -105,7 +105,7 @@ fn find_plate(shot: &Shot, role: Role, ui: &Ui, name: &str) -> Rect {
|
||||
assert_eq!(
|
||||
columns.len(),
|
||||
1,
|
||||
"{name} 列({role:?} 底,{color:?})应当恰好是 1 列,实测 {}: 板子尺寸判据 MIN {MIN_PLATE_W}×{MIN_PLATE_H}",
|
||||
"{name} 列({role:?} 底,{color:?})应当恰好是 1 列,实测 {}: 板子尺寸判据 MIN {MIN_PLATE_W}×{MIN_PLATE_H}",
|
||||
columns.len()
|
||||
);
|
||||
columns.remove(0)
|
||||
@@ -162,30 +162,34 @@ pub(super) fn check(shot: &Shot, ui: &Ui, flavor: unlucky_design::color::SchemeF
|
||||
(panel_rect, panel, panel_button, panel_field, "panel"),
|
||||
] {
|
||||
let (x0, x1, y0, y1) = rect;
|
||||
let hits = count_exact(shot, wanted_button, x0, x1, y0, y1);
|
||||
// 两个计数**分开命名**:它们是不同量测对象,拿字段数去比按钮 stray 会让断言恒绿
|
||||
// (M234 复审 P2-1 的现场)。
|
||||
let button_hits = count_exact(shot, wanted_button, x0, x1, y0, y1);
|
||||
assert!(
|
||||
hits >= MIN_BUTTON_PX,
|
||||
"{name} 列里「叠 {:?}」的禁用按钮容器只有 {hits} px(应 ≥{MIN_BUTTON_PX}):\
|
||||
这一列的禁用控件没把真实父底传下去",
|
||||
button_hits >= MIN_BUTTON_PX,
|
||||
"{name} 列里「叠 {:?}」的禁用按钮容器只有 {button_hits} px(应 ≥{MIN_BUTTON_PX}): 这一列的禁用控件没把真实父底传下去",
|
||||
base.role()
|
||||
);
|
||||
let hits = count_exact(shot, wanted_field, x0, x1, y0, y1);
|
||||
let field_hits = count_exact(shot, wanted_field, x0, x1, y0, y1);
|
||||
assert!(
|
||||
hits >= MIN_FIELD_PX,
|
||||
"{name} 列里「叠 {:?}」的禁用字段容器只有 {hits} px(应 ≥{MIN_FIELD_PX})",
|
||||
field_hits >= MIN_FIELD_PX,
|
||||
"{name} 列里「叠 {:?}」的禁用字段容器只有 {field_hits} px(应 ≥{MIN_FIELD_PX})",
|
||||
base.role()
|
||||
);
|
||||
// 反向:这一列里不许出现「叠画布底」的那一档
|
||||
let stray = count_exact(shot, canvas_button, x0, x1, y0, y1);
|
||||
|
||||
// 反向 ①:**按钮**档 —— 这一列里「叠画布」的按钮容器不许和「叠该列底」的比肩。
|
||||
// 这条抓的是「只修了一半」:同列里一部分按钮仍走画布底时,正确档与错误档的像素量接近。
|
||||
let stray_button = count_exact(shot, canvas_button, x0, x1, y0, y1);
|
||||
assert!(
|
||||
hits > stray * STRAY_RATIO,
|
||||
"{name} 列里「叠 {:?}」的禁用按钮容器只有 {hits} px,而「叠画布」的有 {stray} px (要求前者 ≥ 后者 ×{STRAY_RATIO})—— 这一列的控件仍在按 Role::Surface 合成",
|
||||
button_hits > stray_button * STRAY_RATIO,
|
||||
"{name} 列里「叠 {:?}」的禁用按钮容器 {button_hits} px,而「叠画布」的**按钮容器** 有 {stray_button} px(要求前者 ≥ 后者 ×{STRAY_RATIO})—— 这一列的按钮仍在按 Role::Surface 合成",
|
||||
base.role()
|
||||
);
|
||||
let stray = count_exact(shot, canvas_field, x0, x1, y0, y1);
|
||||
// 反向 ②:**字段**档(同理,各用各的计数)
|
||||
let stray_field = count_exact(shot, canvas_field, x0, x1, y0, y1);
|
||||
assert!(
|
||||
hits > stray * STRAY_RATIO,
|
||||
"{name} 列里「叠 {:?}」的禁用字段容器只有 {hits} px,而「叠画布」的有 {stray} px (要求前者 ≥ 后者 ×{STRAY_RATIO})",
|
||||
field_hits > stray_field * STRAY_RATIO,
|
||||
"{name} 列里「叠 {:?}」的禁用字段容器 {field_hits} px,而「叠画布」的**字段容器** 有 {stray_field} px(要求前者 ≥ 后者 ×{STRAY_RATIO})—— 这一列的字段仍在按 Role::Surface 合成",
|
||||
base.role()
|
||||
);
|
||||
assert!(
|
||||
@@ -205,12 +209,14 @@ pub(super) fn check(shot: &Shot, ui: &Ui, flavor: unlucky_design::color::SchemeF
|
||||
let canvas_card_hits = count_exact(shot, card_button, cx0, cx1, cy0, cy1);
|
||||
assert!(
|
||||
canvas_hits > canvas_card_hits * STRAY_RATIO,
|
||||
"画布列里「叠画布」的禁用按钮容器 {canvas_hits} px,而「叠卡片底」的有 {canvas_card_hits} px —— 画布列的控件被传了卡片底"
|
||||
"画布列里「叠画布」的禁用按钮容器 {canvas_hits} px,而「叠卡片底」的有 {canvas_card_hits} px —— 画布列的控件被传了卡片底"
|
||||
);
|
||||
|
||||
eprintln!(
|
||||
"[probe] OK section=disabledbase flavor={flavor:?}:\
|
||||
canvas 按钮 {:?} / 卡片 {} / 面板 {} ⇒ 三列各按自己的底合成",
|
||||
canvas_button, card_rect.0, panel_rect.0
|
||||
画布列 x<{} · 卡片列左缘 x={}..{} · 面板列左缘 x={}..{};\
|
||||
按钮容器色 canvas {:?}({canvas_hits} px)⇒ 三列各按自己的底合成\
|
||||
(两个数字都是列左缘横坐标,不是像素计数)",
|
||||
card_rect.0, card_rect.0, card_rect.1, panel_rect.0, panel_rect.1, canvas_button
|
||||
);
|
||||
}
|
||||
@@ -279,8 +279,10 @@ fn disabled_colors_follow_the_brand_board_not_the_tone_baseline() {
|
||||
/// probe 分别守)。
|
||||
///
|
||||
/// 抓不住:① 容器画的是**合成色**(半透明面板 α、叠过状态层的底)——`Base` 只装一个 `Role`;
|
||||
/// ② 卡/面板组件的 `BASE` 常量与它自己画的色不一致(那条由 `surfaces::elevated::tests` 与
|
||||
/// 像素 probe 守);③ GPU(wgpu) 档(本测试是纯值,两档同源同值)。
|
||||
/// ② 卡/面板组件**画底时**用的角色与它导出的 `BASE` 不一致(`BASE` 的值本身由
|
||||
/// `surfaces::elevated::tests::the_card_base_constant_is_the_role_the_card_paints` 钉住,
|
||||
/// 「card() 真的用了它」与「页面里的调用点传了它对不对」由 `gallery::probe` 的 disabledbase
|
||||
/// 段守);③ GPU(wgpu) 档(本测试是纯值,两档同源同值)。
|
||||
#[test]
|
||||
fn disabled_paint_composites_over_the_base_it_is_given() {
|
||||
use unlucky_design::color::BrandBoard;
|
||||
|
||||
@@ -148,7 +148,7 @@ pub(super) fn palette(
|
||||
_ => ui.color(Role::OnSurface),
|
||||
};
|
||||
ItemPalette {
|
||||
pill: interaction::overlay_color(ui, state, Role::OnSurface, Role::Surface),
|
||||
pill: interaction::overlay_color(ui, state, Role::OnSurface, base.role()),
|
||||
icon: ink,
|
||||
label: ink,
|
||||
}
|
||||
|
||||
@@ -27,8 +27,9 @@
|
||||
//! ListItemDisabledTrailingIconColor = OnSurface (+ 0.38f)
|
||||
//! ```
|
||||
//!
|
||||
//! 所以这里必须走 `interaction::disabled_content_over_role(ui, OnSurface, false)`;
|
||||
//! 用默认的 `disabled_colors()`(写死 `OnSurfaceVariant`)会偏浅一档。
|
||||
//! 所以这里必须走 `interaction::disabled_content_over_role(ui, base, OnSurface, false)`
|
||||
//! (`base` = 行脚下的底,默认 [`Base::CANVAS`]);用默认的 `disabled_colors()`
|
||||
//! (写死 `OnSurfaceVariant`)会偏浅一档。
|
||||
//!
|
||||
//! ## 选中态:本项目口径(**偏离登记 D-M79-1**)
|
||||
//!
|
||||
@@ -182,8 +183,9 @@ fn palette(ui: &Ui, base: Base, state: Interaction, selected: bool) -> ItemPalet
|
||||
}
|
||||
|
||||
ItemPalette {
|
||||
// 状态层叠在**行自己的底**(Surface)上,得到不透明结果(D27)
|
||||
fill: interaction::overlay_color(ui, state, Role::OnSurface, Role::Surface),
|
||||
// 状态层叠在**行脚下的底**(`base`)上,得到不透明结果(D27)。
|
||||
// M234 复审 P2-3:原来写死 `Role::Surface`,卡片里的列表项抬起时会叠在画布色上。
|
||||
fill: interaction::overlay_color(ui, state, Role::OnSurface, base.role()),
|
||||
headline: ui.color(Role::OnSurface),
|
||||
supporting: ui.color(Role::OnSurfaceVariant),
|
||||
leading: ui.color(Role::OnSurfaceVariant),
|
||||
|
||||
@@ -161,7 +161,12 @@ pub fn checkbox<'a, M: Clone + 'a>(ui: &'a Ui, spec: Checkbox<'a, M>) -> Element
|
||||
.align_y(Alignment::Center)
|
||||
.style(source.container_style(move |state| {
|
||||
Frame {
|
||||
fill: paint::state_layer(ui, state, paint::checkbox_layer_role(filled, error)),
|
||||
fill: paint::state_layer(
|
||||
ui,
|
||||
base,
|
||||
state,
|
||||
paint::checkbox_layer_role(filled, error),
|
||||
),
|
||||
outline: None,
|
||||
stroke: 0.0,
|
||||
radius: layer_side / 2.0,
|
||||
|
||||
@@ -57,7 +57,7 @@ pub fn chip(
|
||||
let fill = if selected {
|
||||
Some(ui.color(Role::SecondaryContainer))
|
||||
} else {
|
||||
state_layer(ui, state, label_role)
|
||||
state_layer(ui, base, state, label_role)
|
||||
};
|
||||
// Assist / 选中态的前置图标是 `Primary`(`AssistChipTokens.IconColor` /
|
||||
// `InputChipTokens.SelectedLeadingIconColor`);其余跟文字同色。
|
||||
|
||||
@@ -109,10 +109,14 @@ pub struct ChipPaint {
|
||||
pub icon: Color,
|
||||
}
|
||||
|
||||
/// 状态层颜色:`content` 角色 @ 该态的 α 叠在 `surface` 上(不透明;α 的唯一实现点是
|
||||
/// [`interaction::overlay_color`],本目录零 α 字面量)。
|
||||
pub fn state_layer(ui: &Ui, state: Interaction, content: Role) -> Option<Color> {
|
||||
interaction::overlay_color(ui, state, content, Role::Surface)
|
||||
/// 状态层颜色:`content` 角色 @ 该态的 α 叠在 **`base`(控件脚下的底)** 上
|
||||
/// (不透明;α 的唯一实现点是 [`interaction::overlay_color`],本目录零 α 字面量)。
|
||||
///
|
||||
/// M234 复审 P2-3:禁用支跟了 `base`,hover/focus/pressed 这一支却仍写死 `Role::Surface`
|
||||
/// —— 卡片里的 checkbox/radio/chip 抬起来时会把状态层叠在画布色上(口径不一致比那 1/255 的
|
||||
/// 数值更麻烦)。现在两支同源。
|
||||
pub fn state_layer(ui: &Ui, base: Base, state: Interaction, content: Role) -> Option<Color> {
|
||||
interaction::overlay_color(ui, state, content, base.role())
|
||||
}
|
||||
|
||||
/// `OnSurface`@12% 叠 `base`(**容器**禁用色:Switch 轨道、Chip 未选中描边)。
|
||||
|
||||
@@ -127,7 +127,7 @@ pub fn radio<'a, M: Clone + 'a>(ui: &'a Ui, spec: Radio<'a, M>) -> Element<'a, M
|
||||
.align_y(Alignment::Center)
|
||||
.style(source.container_style(move |state| {
|
||||
Frame {
|
||||
fill: paint::state_layer(ui, state, paint::radio_layer_role(selected)),
|
||||
fill: paint::state_layer(ui, base, state, paint::radio_layer_role(selected)),
|
||||
outline: None,
|
||||
stroke: 0.0,
|
||||
radius: layer_side / 2.0,
|
||||
|
||||
@@ -77,14 +77,16 @@ fn state_layer_only_exists_on_lifted_states() {
|
||||
(Interaction::Pressed, true),
|
||||
(Interaction::Disabled, false),
|
||||
] {
|
||||
let layer = paint::state_layer(&ui, state, Role::OnSurfaceVariant);
|
||||
let layer = paint::state_layer(&ui, Base::CANVAS, state, Role::OnSurfaceVariant);
|
||||
assert_eq!(layer.is_some(), expected, "{state:?} 的状态层有无");
|
||||
if let Some(color) = layer {
|
||||
assert_eq!(color.a, 1.0, "状态层必须是实色(D27:CPU/GPU 一致)");
|
||||
}
|
||||
}
|
||||
// 同态下 hover 比 pressed 浅(8% < 10%)
|
||||
let hover = paint::state_layer(&ui, Interaction::Hovered, Role::OnSurface).unwrap();
|
||||
let pressed = paint::state_layer(&ui, Interaction::Pressed, Role::OnSurface).unwrap();
|
||||
let hover =
|
||||
paint::state_layer(&ui, Base::CANVAS, Interaction::Hovered, Role::OnSurface).unwrap();
|
||||
let pressed =
|
||||
paint::state_layer(&ui, Base::CANVAS, Interaction::Pressed, Role::OnSurface).unwrap();
|
||||
assert_ne!(hover, pressed);
|
||||
}
|
||||
@@ -75,3 +75,18 @@ fn the_card_surface_sits_one_step_above_the_canvas() {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// **M234**:卡片的底在代码里只出现两次——[`card`] 的 `background` 与导出的 [`BASE`],
|
||||
/// 这两处必须同角色,否则卡里的禁用控件会合到另一层底上。
|
||||
///
|
||||
/// 抓得住:有人只改 `BASE`(或只改 `card`)导致两边漂开;抓不住:「`card()` 真的用了
|
||||
/// `BASE` 画底」这件事(`container::Style` 闭包不可内省,只能靠代码审阅与
|
||||
/// `gallery::probe` 的 disabledbase 段——那边的像素判据要求卡列里出现「叠卡片底」的禁用容器)。
|
||||
#[test]
|
||||
fn the_card_base_constant_is_the_role_the_card_paints() {
|
||||
assert_eq!(
|
||||
super::BASE.role(),
|
||||
Role::SurfaceContainer,
|
||||
"`elevated::BASE` 必须就是卡底的角色(`card()` 的 background 用的是同一个值)"
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user