//! 宿主控件的颜色与状态调色。根据背景、强调色和交互状态生成可读颜色,不改变业务状态。 //! 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 }