CI / runtime smoke (macos arm64, probe) (push) Skipped
CI / fmt (rustfmt --check) (push) Canceled after 0s
CI / clippy (ubuntu-latest) (push) Canceled after 0s
CI / clippy (windows-latest) (push) Canceled after 0s
CI / test (ubuntu-latest) (push) Canceled after 0s
CI / test (windows-latest) (push) Canceled after 0s
CI / build release (ubuntu-latest) (push) Canceled after 0s
CI / build release (windows-latest) (push) Canceled after 0s
CI / runtime smoke (ubuntu x64, xvfb) (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Release / 选槽位(默认两个 Windows) (push) Canceled after 0s
Release / build (${{ matrix.slot }}) (push) Canceled after 0s
Release / GitHub Release (push) Canceled after 0s
80 lines
2.4 KiB
Rust
80 lines
2.4 KiB
Rust
//! Chip 的角色映射(`research/12b` §13.5 / §13.6 / §13.7)。
|
||
|
||
use unlucky_design::color::Role;
|
||
|
||
use crate::theme::{Ui, STROKE_PX};
|
||
|
||
use super::super::super::interaction::Interaction;
|
||
use super::{disabled_container, disabled_ink, state_layer, ChipPaint, Frame};
|
||
|
||
/// Chip 的三种(§13.6 / §13.7):Assist / Filter / Input。
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||
pub enum ChipVariant {
|
||
/// Assist:**永远未选中**,前置图标 `Primary`(`AssistChipTokens.IconColor`)。
|
||
Assist,
|
||
/// Filter:可选中(`SecondaryContainer`),选中态无描边。
|
||
Filter,
|
||
/// Input:可选中 + 后置关闭图标。
|
||
Input,
|
||
}
|
||
|
||
/// Chip 的外观。
|
||
///
|
||
/// 与 Checkbox/Radio 的区别:Chip 的**状态层就是它自己的容器**(M3 的 chip 没有圆形状态层),
|
||
/// 所以未选中 + hover 的 fill 是「状态层叠在 surface 上」的实色。
|
||
pub fn chip(
|
||
ui: &Ui,
|
||
variant: ChipVariant,
|
||
selected: bool,
|
||
state: Interaction,
|
||
radius: f32,
|
||
) -> ChipPaint {
|
||
let selected = selected && !matches!(variant, ChipVariant::Assist);
|
||
let label_role = if selected {
|
||
Role::OnSecondaryContainer
|
||
} else if matches!(variant, ChipVariant::Assist) {
|
||
Role::OnSurface
|
||
} else {
|
||
Role::OnSurfaceVariant
|
||
};
|
||
|
||
if state.is_disabled() {
|
||
let ink = disabled_ink(ui, Role::OnSurface);
|
||
return ChipPaint {
|
||
frame: Frame {
|
||
fill: selected.then(|| disabled_container(ui)),
|
||
outline: (!selected).then(|| disabled_container(ui)),
|
||
stroke: STROKE_PX,
|
||
radius,
|
||
},
|
||
label: ink,
|
||
icon: ink,
|
||
};
|
||
}
|
||
|
||
let outline = (!selected).then(|| ui.color(Role::OutlineVariant));
|
||
let fill = if selected {
|
||
Some(ui.color(Role::SecondaryContainer))
|
||
} else {
|
||
state_layer(ui, state, label_role)
|
||
};
|
||
// Assist / 选中态的前置图标是 `Primary`(`AssistChipTokens.IconColor` /
|
||
// `InputChipTokens.SelectedLeadingIconColor`);其余跟文字同色。
|
||
let icon_role = if matches!(variant, ChipVariant::Assist) || selected {
|
||
Role::Primary
|
||
} else {
|
||
label_role
|
||
};
|
||
|
||
ChipPaint {
|
||
frame: Frame {
|
||
fill,
|
||
outline,
|
||
stroke: STROKE_PX,
|
||
radius,
|
||
},
|
||
label: ui.color(label_role),
|
||
icon: ui.color(icon_role),
|
||
}
|
||
}
|