fix(app-iced): M75 —— 截图取证必须能强制「静息」态(光标污染修掉)
StyleSpec.forced 从 Interaction 改成 Option<Interaction>:Some(Enabled) 与 None 语义不同—— 前者强制画静息,后者才跟随 button::Status。修前光标恰好停在某个格子上时,gallery 的 enabled 列会被画成 hover(表现为 text 行出现不该有的灰底容器,看着像 Text 按钮自带容器)。
This commit is contained in:
1 parent
5861881073
commit
5f85891e7e
5 files changed
+31
-47
No files matched your search
@@ -32,8 +32,12 @@ pub(super) struct StyleSpec {
|
||||
pub shape: ShapeScale,
|
||||
/// 圆角折算用的边长(药丸 = 可见高)。
|
||||
pub radius_side: f32,
|
||||
/// 强制态(gallery 取证);`Enabled` 时跟随运行期的 `button::Status`。
|
||||
pub forced: Interaction,
|
||||
/// 强制态(gallery 取证);`None` = 跟随运行期的 `button::Status`。
|
||||
///
|
||||
/// **`Some(Enabled)` 与 `None` 不是一回事**:截图取证必须能强制「静息」,否则光标恰好停在
|
||||
/// 某个按钮上时那一格会被画成 hover(实测踩过:text 行 enabled 列出现不该有的灰底容器,
|
||||
/// 看起来像 Text 按钮自带容器)。
|
||||
pub forced: Option<Interaction>,
|
||||
}
|
||||
|
||||
/// 五式共用的装配:**只画一处**,五个变体函数都走这里。
|
||||
@@ -89,10 +93,10 @@ pub(super) fn assemble<'a, M: Clone + 'a>(
|
||||
.height(Length::Fill)
|
||||
.align_y(iced::Alignment::Center);
|
||||
|
||||
let forced = spec.state.unwrap_or(if spec.on_press.is_none() {
|
||||
Interaction::Disabled
|
||||
let forced = spec.state.or(if spec.on_press.is_none() {
|
||||
Some(Interaction::Disabled)
|
||||
} else {
|
||||
Interaction::Enabled
|
||||
None
|
||||
});
|
||||
|
||||
let style = style_closure(
|
||||
@@ -125,10 +129,9 @@ pub(super) fn style_closure(
|
||||
) -> impl Fn(&iced::Theme, button::Status) -> button::Style + '_ {
|
||||
move |_theme: &iced::Theme, status| {
|
||||
// 强制态优先(gallery 状态矩阵),否则把 iced 的四态翻成 M3 五态
|
||||
let state = match spec.forced {
|
||||
Interaction::Enabled => Interaction::from_status(status),
|
||||
forced => forced,
|
||||
};
|
||||
let state = spec
|
||||
.forced
|
||||
.unwrap_or_else(|| Interaction::from_status(status));
|
||||
|
||||
let (background, text_color) = if state.is_disabled() {
|
||||
let (container, content) = interaction::disabled_colors(ui, Role::Surface);
|
||||
|
||||
@@ -279,10 +279,10 @@ pub fn icon<'a, M: Clone + 'a>(
|
||||
) -> Element<'a, M> {
|
||||
let geometry = IconGeometry::of(ui);
|
||||
let (fill, content, border) = variant.roles();
|
||||
let forced = state.unwrap_or(if on_press.is_some() {
|
||||
Interaction::Enabled
|
||||
let forced = state.or(if on_press.is_some() {
|
||||
None
|
||||
} else {
|
||||
Interaction::Disabled
|
||||
Some(Interaction::Disabled)
|
||||
});
|
||||
|
||||
// Q9:图标**必须在固定尺寸的中层容器里**,否则 Button 的 Fill 约束会让 usvg 按 Contain
|
||||
|
||||
@@ -220,7 +220,7 @@ fn spec_of(variant: Variant, forced: Interaction) -> StyleSpec {
|
||||
border,
|
||||
shape: variant.shape(),
|
||||
radius_side: Geometry::of(&light(), variant, false).height,
|
||||
forced,
|
||||
forced: Some(forced),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ use unlucky_design::typography::Platform;
|
||||
|
||||
use crate::theme::{Families, Ui};
|
||||
|
||||
use super::scan::{matches, nearer, rgb, run_at, Shot};
|
||||
use super::scan::{matches, nearer, rgb, Shot};
|
||||
|
||||
const FAMILIES: Families = Families {
|
||||
text: "Segoe UI",
|
||||
@@ -127,22 +127,15 @@ fn gallery_geometry_matches_the_tokens() {
|
||||
}
|
||||
let true_height = true_bottom - true_top + 1;
|
||||
|
||||
// 圆角档位:**量顶部那一行的宽度**。药丸(r = 高/2)顶部只有几像素宽;
|
||||
// 若半径是 8(不是 full),顶行会是「几乎通栏」。这条比「数圆角行数」抗锯齿得多。
|
||||
let top_run = run_at(
|
||||
&shot,
|
||||
label_button.top,
|
||||
label_button.left,
|
||||
label_button.right,
|
||||
rgb(ui.color(Role::Primary)),
|
||||
);
|
||||
// 圆角档位:量**顶部那一行的左内缩**。药丸(r = 高/2 = 20)在离顶端 1px 处内缩
|
||||
// ≈ r − √(2r−1) = 13.8;r=8 只有 ≈4.1;直角为 0。比「数圆角行数」抗锯齿得多。
|
||||
let top_row_left = (label_button.left..=label_button.right)
|
||||
.find(|x| matches(shot.at(*x, label_button.top), fill))
|
||||
.expect("顶部行应至少有一个填充像素");
|
||||
let top_inset = top_row_left - label_button.left;
|
||||
assert!(
|
||||
(39..=41).contains(&true_height),
|
||||
"可见高应 40(12b 1.1),实测 {true_height}"
|
||||
);
|
||||
assert!(
|
||||
(4..=20).contains(&top_run),
|
||||
"药丸圆角应 = 20(12b 1.2,顶部一行的填充宽约 sqrt(2*20*1)*2 ≈ 9),实测 {top_run}px; 若接近整宽说明半径是 8 而不是 full"
|
||||
(11..=17).contains(&top_inset),
|
||||
"药丸圆角应 = 20(12b 1.2):顶部行左内缩应 ≈14,实测 {top_inset}(8 圆角 ≈4,直角 0)"
|
||||
);
|
||||
|
||||
// ---- Q9:IconButton 的字形不许撑满 40 盒 --- // ---- Q9:IconButton 的字形不许撑满 40 盒 -----------------------------------
|
||||
@@ -152,9 +145,11 @@ fn gallery_geometry_matches_the_tokens() {
|
||||
.iter()
|
||||
.filter(|bbox| (39..=41).contains(&bbox.width()) && (39..=41).contains(&bbox.height()))
|
||||
.count();
|
||||
// 只有 **enabled** 列是精确的 SecondaryContainer(hover/pressed/focus 列叠了状态层,颜色不同),
|
||||
// 所以这里只要求 ≥1:量几何一只就够,五态的可见性由图本身给。
|
||||
assert!(
|
||||
icon_states >= 2,
|
||||
"tonal IconButton 至少 2 个(实际 {icon_states})"
|
||||
icon_states >= 1,
|
||||
"tonal IconButton 至少 1 个(实际 {icon_states})"
|
||||
);
|
||||
|
||||
let gear = rgb(ui.color(Role::OnSecondaryContainer));
|
||||
@@ -216,7 +211,7 @@ fn gallery_geometry_matches_the_tokens() {
|
||||
eprintln!(
|
||||
"[probe] OK flavor={:?}:
|
||||
Filled 药丸 {}×{}(参考 高 40 / 宽 ≥58)
|
||||
顶行填充宽 {}(full 圆角应为个位数,直角/8 圆角会接近整宽)
|
||||
顶行左内缩 {}(r=20 应 ≈14;8 圆角 ≈4;直角 0)
|
||||
实心块 {} 个(含 40×40 IconButton)
|
||||
分隔线长行 {} 行(每条 1px)
|
||||
禁用容器 (on-surface@12%) 命中
|
||||
@@ -224,7 +219,7 @@ fn gallery_geometry_matches_the_tokens() {
|
||||
flavor,
|
||||
label_button.width(),
|
||||
true_height,
|
||||
top_run,
|
||||
top_inset,
|
||||
primary.len(),
|
||||
runs,
|
||||
glyph_width
|
||||
|
||||
@@ -163,17 +163,3 @@ pub(super) fn nearer(pixel: [u8; 3], fill: [u8; 3], surface: [u8; 3]) -> bool {
|
||||
};
|
||||
dist(pixel, fill) < dist(pixel, surface)
|
||||
}
|
||||
|
||||
/// 某一行的水平区间 `[left, right]` 里,`color` 连续像素的最大长度(量药丸顶部宽度用)。
|
||||
pub(super) fn run_at(shot: &Shot, y: usize, left: usize, right: usize, color: [u8; 3]) -> usize {
|
||||
let (mut longest, mut current) = (0, 0);
|
||||
for x in left..=right {
|
||||
if matches(shot.at(x, y), color) {
|
||||
current += 1;
|
||||
longest = longest.max(current);
|
||||
} else {
|
||||
current = 0;
|
||||
}
|
||||
}
|
||||
longest
|
||||
}
|
||||
Reference in new issue
Block a user