72 lines
3.0 KiB
Rust
72 lines
3.0 KiB
Rust
//! 宿主控件的颜色与状态调色。根据背景、强调色和交互状态生成可读颜色,不改变业务状态。
|
|
//!
|
|
use crate::display_list::Color;
|
|
// 宿主管理界面的白色基础背景;这些常量不会修改业务页面自己的颜色。
|
|
pub const BG: Color = Color::rgb(255, 255, 255);
|
|
// A visibly separate chrome layer against the warm, near-white content canvas.
|
|
pub const BAR: Color = Color::rgb(230, 233, 237);
|
|
pub const BORDER: Color = Color::rgb(226, 226, 226);
|
|
pub const TEXT: Color = Color::rgb(35, 42, 53);
|
|
pub const MUTED: Color = Color::rgb(103, 114, 130);
|
|
pub const ERROR: Color = Color::rgb(175, 42, 49);
|
|
pub const OK: Color = Color::rgb(31, 121, 80);
|
|
// 供设置页选择的六个强调色候选;Theme::new 还会按可读性规则调整传入颜色。
|
|
pub const PALETTE: [Color; 6] = [
|
|
Color::rgb(22, 113, 213),
|
|
Color::rgb(0, 132, 143),
|
|
Color::rgb(115, 76, 189),
|
|
Color::rgb(180, 68, 115),
|
|
Color::rgb(168, 94, 24),
|
|
Color::rgb(52, 123, 78),
|
|
];
|
|
#[derive(Clone, Copy, Debug)]
|
|
/// 当前管理界面的配色基础,派生状态颜色由方法统一计算。
|
|
pub struct Theme {
|
|
pub accent: Color,
|
|
}
|
|
impl Theme {
|
|
/// 保存经过亮度限制的强调色,所有控件状态色都从该色与管理界面背景混合得到。
|
|
pub fn new(accent: Color) -> Self {
|
|
// 构造时统一压低过亮强调色,之后 hover/pressed 等样式都从调整后的 accent 派生。
|
|
Self {
|
|
accent: readable_accent(accent),
|
|
}
|
|
}
|
|
/// 以 10% 强调色混合背景,得到未悬停的柔和选中底色。
|
|
pub fn soft(self) -> Color {
|
|
mix(BG, self.accent, 0.10)
|
|
}
|
|
/// 以 17% 强调色混合背景,得到比 soft 更明显的悬停底色。
|
|
pub fn hover(self) -> Color {
|
|
mix(BG, self.accent, 0.17)
|
|
}
|
|
/// 以 29% 强调色混合背景,增强按下状态;混色输出始终不透明。
|
|
pub fn pressed(self) -> Color {
|
|
mix(BG, self.accent, 0.29)
|
|
}
|
|
}
|
|
/// 按比例混合颜色通道,作为状态颜色的基础运算。
|
|
pub fn mix(a: Color, b: Color, amount: f32) -> Color {
|
|
// 逐 RGB 通道线性插值并四舍五入,amount 钳到 [0,1];结果使用 rgb,输出 alpha 固定为 255。
|
|
let channel =
|
|
|a: u8, b: u8| (a as f32 + (b as f32 - a as f32) * amount.clamp(0.0, 1.0)).round() as u8;
|
|
Color::rgb(
|
|
channel(a.red, b.red),
|
|
channel(a.green, b.green),
|
|
channel(a.blue, b.blue),
|
|
)
|
|
}
|
|
/// 根据背景选择可读的强调色,供选中与焦点状态使用。
|
|
pub fn readable_accent(mut c: Color) -> Color {
|
|
// 用 299/587/114 加权亮度做简单阈值判断,过亮时每轮各通道乘 0.94 变暗。
|
|
// 这是启发式规则,不是对任意背景执行通用对比度求解。
|
|
while (c.red as u32 * 299 + c.green as u32 * 587 + c.blue as u32 * 114) / 1000 > 155 {
|
|
c = Color::rgb(
|
|
(c.red as f32 * 0.94) as u8,
|
|
(c.green as f32 * 0.94) as u8,
|
|
(c.blue as f32 * 0.94) as u8,
|
|
);
|
|
}
|
|
c
|
|
}
|