Files
hcie-rust-v3.05/hcie-iced-app/crates/iced-panel-adapter/src/theme.rs
T

217 lines
12 KiB
Rust
Raw Normal View History

//! Theme colors and presets for the Iced GUI panels.
//!
//! **Purpose:** Provides a Photopea-matched dark UI palette as the default theme.
//! Color values extracted from 93 Photopea screenshots for pixel-accurate matching.
//!
//! **Design tokens:**
//! - 3-tier surface elevation: recessed → panel → elevated
//! - Photopea exact RGB values for dark theme
//! - Sharp 2px corners, tight spacing
//! - Green accent for active tools (#4caf50)
//! - Blue accent for selections/links (#4a9eff)
use iced::Color;
/// Available theme presets.
///
/// `Photopea` is the default — matches the Photopea image editor's dark UI.
/// Other presets are kept as alternatives.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ThemePreset {
#[default]
Photopea,
Photoshop,
ProDark,
Amoled,
PhotoshopLight,
ProLight,
}
/// Named color tokens for the application theme.
///
/// Implements Photopea's 3-tier surface elevation system:
/// - `bg_recessed`: deepest surface (input fields, slider tracks)
/// - `bg_panel`: mid surface (docked panels, side columns)
/// - `bg_elevated`: top surface (popups, tooltips, dropdowns)
#[derive(Debug, Clone, Copy)]
pub struct ThemeColors {
/// Workspace / application background (deepest surface).
pub bg_app: Color,
/// Docked panel backgrounds (mid surface).
pub bg_panel: Color,
/// Hover feedback highlight.
pub bg_hover: Color,
/// Active/selected state background.
pub bg_active: Color,
/// Active element accent (selections, links, submenu arrows).
pub accent: Color,
/// Accent hover state.
pub accent_hover: Color,
/// Active tool highlight (green, like Photopea toolbox).
pub accent_green: Color,
/// Warning/danger accent (red, like Photopea "Account" button).
pub danger: Color,
/// Subdued low-contrast dividers.
pub border_low: Color,
/// High-contrast outer borders.
pub border_high: Color,
/// Primary high-readability text.
pub text_primary: Color,
/// Secondary muted text.
pub text_secondary: Color,
/// Disabled/very muted text.
pub text_disabled: Color,
/// Menu dropdown background (light, like Photopea menus).
pub menu_bg: Color,
/// Menu item hover highlight.
pub menu_hover: Color,
/// Menu text color (dark on light background).
pub menu_text: Color,
/// Menu keyboard shortcut text.
pub menu_shortcut: Color,
/// Light mode vs dark mode flag.
pub is_light: bool,
}
impl ThemeColors {
/// Resolve colors for a given preset.
///
/// `Photopea` preset uses exact RGB values extracted from screenshots.
pub fn get(preset: ThemePreset) -> Self {
match preset {
// ── Photopea (Default) ─────────────────────────────────────
// Exact colors from 93 Photopea screenshots.
ThemePreset::Photopea => Self {
bg_app: Color::from_rgb(0.118, 0.118, 0.118), // #1e1e1e - canvas
bg_panel: Color::from_rgb(0.165, 0.165, 0.165), // #2a2a2a - panels
bg_hover: Color::from_rgb(0.227, 0.227, 0.227), // #3a3a3a - hover
bg_active: Color::from_rgb(0.200, 0.200, 0.200), // #333333 - active tab
accent: Color::from_rgb(0.290, 0.620, 1.000), // #4a9eff - selections
accent_hover: Color::from_rgb(0.350, 0.680, 1.000),
accent_green: Color::from_rgb(0.298, 0.686, 0.314), // #4caf50 - tool active
danger: Color::from_rgb(0.906, 0.298, 0.235), // #e74c3c - account btn
border_low: Color::from_rgb(0.200, 0.200, 0.200), // #333333 - dividers
border_high: Color::from_rgb(0.267, 0.267, 0.267), // #444444 - borders
text_primary: Color::from_rgb(0.878, 0.878, 0.878), // #e0e0e0 - primary
text_secondary:Color::from_rgb(0.600, 0.600, 0.600), // #999999 - muted
text_disabled: Color::from_rgb(0.400, 0.400, 0.400), // #666666 - disabled
menu_bg: Color::from_rgb(0.910, 0.910, 0.910), // #e8e8e8 - menu bg
menu_hover: Color::from_rgb(0.702, 0.851, 1.000), // #b3d9ff - menu hover
menu_text: Color::from_rgb(0.000, 0.000, 0.000), // #000000 - menu text
menu_shortcut: Color::from_rgb(0.400, 0.400, 0.400), // #666666 - shortcuts
is_light: false,
},
// ── Photoshop (Legacy) ─────────────────────────────────────
ThemePreset::Photoshop => Self {
bg_app: Color::from_rgb(0.110, 0.110, 0.118),
bg_panel: Color::from_rgb(0.196, 0.196, 0.212),
bg_hover: Color::from_rgb(0.243, 0.243, 0.259),
bg_active: Color::from_rgb(0.227, 0.227, 0.243),
accent: Color::from_rgb(0.220, 0.471, 0.863),
accent_hover: Color::from_rgb(0.260, 0.520, 0.900),
accent_green: Color::from_rgb(0.298, 0.686, 0.314),
danger: Color::from_rgb(0.800, 0.200, 0.200),
border_low: Color::from_rgb(0.157, 0.157, 0.165),
border_high: Color::from_rgb(0.251, 0.251, 0.267),
text_primary: Color::from_rgb(0.878, 0.878, 0.878),
text_secondary:Color::from_rgb(0.580, 0.580, 0.596),
text_disabled: Color::from_rgb(0.350, 0.350, 0.360),
menu_bg: Color::from_rgb(0.910, 0.910, 0.910),
menu_hover: Color::from_rgb(0.702, 0.851, 1.000),
menu_text: Color::from_rgb(0.000, 0.000, 0.000),
menu_shortcut: Color::from_rgb(0.400, 0.400, 0.400),
is_light: false,
},
// ── Monokai ────────────────────────────────────────────────
ThemePreset::ProDark => Self {
bg_app: Color::from_rgb(0.086, 0.082, 0.071),
bg_panel: Color::from_rgb(0.153, 0.157, 0.133),
bg_hover: Color::from_rgb(0.212, 0.220, 0.188),
bg_active: Color::from_rgb(0.180, 0.184, 0.160),
accent: Color::from_rgb(0.902, 0.588, 0.196),
accent_hover: Color::from_rgb(0.940, 0.640, 0.260),
accent_green: Color::from_rgb(0.298, 0.686, 0.314),
danger: Color::from_rgb(0.780, 0.220, 0.267),
border_low: Color::from_rgb(0.110, 0.106, 0.086),
border_high: Color::from_rgb(0.243, 0.251, 0.212),
text_primary: Color::from_rgb(0.973, 0.973, 0.941),
text_secondary:Color::from_rgb(0.580, 0.588, 0.533),
text_disabled: Color::from_rgb(0.350, 0.350, 0.330),
menu_bg: Color::from_rgb(0.910, 0.910, 0.910),
menu_hover: Color::from_rgb(0.702, 0.851, 1.000),
menu_text: Color::from_rgb(0.000, 0.000, 0.000),
menu_shortcut: Color::from_rgb(0.400, 0.400, 0.400),
is_light: false,
},
// ── Dracula ────────────────────────────────────────────────
ThemePreset::Amoled => Self {
bg_app: Color::from_rgb(0.094, 0.086, 0.133),
bg_panel: Color::from_rgb(0.157, 0.165, 0.212),
bg_hover: Color::from_rgb(0.220, 0.227, 0.290),
bg_active: Color::from_rgb(0.184, 0.192, 0.243),
accent: Color::from_rgb(1.000, 0.475, 0.776),
accent_hover: Color::from_rgb(1.000, 0.530, 0.820),
accent_green: Color::from_rgb(0.298, 0.686, 0.314),
danger: Color::from_rgb(0.753, 0.220, 0.294),
border_low: Color::from_rgb(0.118, 0.110, 0.165),
border_high: Color::from_rgb(0.267, 0.275, 0.345),
text_primary: Color::from_rgb(0.973, 0.973, 0.949),
text_secondary:Color::from_rgb(0.588, 0.596, 0.667),
text_disabled: Color::from_rgb(0.350, 0.350, 0.380),
menu_bg: Color::from_rgb(0.910, 0.910, 0.910),
menu_hover: Color::from_rgb(0.702, 0.851, 1.000),
menu_text: Color::from_rgb(0.000, 0.000, 0.000),
menu_shortcut: Color::from_rgb(0.400, 0.400, 0.400),
is_light: false,
},
// ── Solarized Light ────────────────────────────────────────
ThemePreset::PhotoshopLight => Self {
bg_app: Color::from_rgb(0.992, 0.965, 0.890),
bg_panel: Color::from_rgb(1.000, 0.980, 0.922),
bg_hover: Color::from_rgb(0.933, 0.910, 0.835),
bg_active: Color::from_rgb(0.878, 0.855, 0.780),
accent: Color::from_rgb(0.796, 0.294, 0.086),
accent_hover: Color::from_rgb(0.840, 0.340, 0.140),
accent_green: Color::from_rgb(0.298, 0.686, 0.314),
danger: Color::from_rgb(0.800, 0.200, 0.200),
border_low: Color::from_rgb(0.871, 0.847, 0.769),
border_high: Color::from_rgb(0.784, 0.753, 0.667),
text_primary: Color::from_rgb(0.196, 0.196, 0.157),
text_secondary:Color::from_rgb(0.471, 0.463, 0.392),
text_disabled: Color::from_rgb(0.650, 0.640, 0.580),
menu_bg: Color::from_rgb(0.910, 0.910, 0.910),
menu_hover: Color::from_rgb(0.702, 0.851, 1.000),
menu_text: Color::from_rgb(0.000, 0.000, 0.000),
menu_shortcut: Color::from_rgb(0.400, 0.400, 0.400),
is_light: true,
},
// ── Nord ───────────────────────────────────────────────────
ThemePreset::ProLight => Self {
bg_app: Color::from_rgb(0.894, 0.910, 0.933),
bg_panel: Color::from_rgb(0.925, 0.937, 0.957),
bg_hover: Color::from_rgb(0.847, 0.871, 0.902),
bg_active: Color::from_rgb(0.816, 0.839, 0.871),
accent: Color::from_rgb(0.369, 0.506, 0.675),
accent_hover: Color::from_rgb(0.410, 0.540, 0.710),
accent_green: Color::from_rgb(0.298, 0.686, 0.314),
danger: Color::from_rgb(0.820, 0.220, 0.220),
border_low: Color::from_rgb(0.831, 0.855, 0.886),
border_high: Color::from_rgb(0.706, 0.737, 0.784),
text_primary: Color::from_rgb(0.180, 0.204, 0.251),
text_secondary:Color::from_rgb(0.392, 0.431, 0.502),
text_disabled: Color::from_rgb(0.580, 0.610, 0.650),
menu_bg: Color::from_rgb(0.910, 0.910, 0.910),
menu_hover: Color::from_rgb(0.702, 0.851, 1.000),
menu_text: Color::from_rgb(0.000, 0.000, 0.000),
menu_shortcut: Color::from_rgb(0.400, 0.400, 0.400),
is_light: true,
},
}
}
/// Auto-detect based on iced theme.
pub fn current() -> Self {
Self::get(ThemePreset::default())
}
}