use eframe::egui; #[derive(Clone, Copy)] pub struct AppTheme { pub bg: egui::Color32, pub panel: egui::Color32, pub panel_strong: egui::Color32, pub panel_deep: egui::Color32, pub border: egui::Color32, pub border_soft: egui::Color32, pub text: egui::Color32, pub text_dim: egui::Color32, pub accent: egui::Color32, pub accent_hot: egui::Color32, pub radius: u8, } pub const ONE_DARK_PRO: AppTheme = AppTheme { bg: egui::Color32::from_rgb(40, 44, 52), // #282C34 editor background panel: egui::Color32::from_rgb(33, 37, 43), // #21252B sidebar/darker panel_strong: egui::Color32::from_rgb(44, 49, 58), // #2C313A slightly lighter panel_deep: egui::Color32::from_rgb(27, 31, 39), // #1B1F27 darkest border: egui::Color32::from_rgb(62, 68, 81), // #3E4451 border border_soft: egui::Color32::from_rgb(44, 49, 58), // #2C313A soft border text: egui::Color32::from_rgb(171, 178, 191), // #ABB2BF default text text_dim: egui::Color32::from_rgb(92, 99, 112), // #5C6370 dimmed text accent: egui::Color32::from_rgb(198, 120, 221), // #C678DD purple (signature) accent_hot: egui::Color32::from_rgb(229, 192, 123), // #E5C07B yellow/gold radius: 3, }; // Additional One Dark Pro accent colors (standalone constants) pub const ACCENT_GREEN: egui::Color32 = egui::Color32::from_rgb(152, 195, 121); // #98C379 pub const ACCENT_RED: egui::Color32 = egui::Color32::from_rgb(224, 108, 117); // #E06C75 pub const ACCENT_BLUE: egui::Color32 = egui::Color32::from_rgb(97, 175, 239); // #61AFEF pub const ACCENT_CYAN: egui::Color32 = egui::Color32::from_rgb(86, 182, 194); // #56B6C2 pub const ACCENT_ORANGE: egui::Color32 = egui::Color32::from_rgb(209, 154, 102); // #D19A66 pub fn apply_theme(ctx: &egui::Context, theme: &AppTheme) { let mut visuals = egui::Visuals::dark(); visuals.override_text_color = Some(theme.text); visuals.panel_fill = theme.bg; visuals.window_fill = theme.panel; visuals.window_stroke = egui::Stroke::new(1.0, theme.border); visuals.extreme_bg_color = theme.panel_deep; visuals.faint_bg_color = theme.panel_strong; visuals.code_bg_color = theme.panel_deep; visuals.warn_fg_color = theme.accent_hot; visuals.error_fg_color = ACCENT_RED; visuals.widgets.noninteractive.bg_fill = theme.panel_strong; visuals.widgets.noninteractive.bg_stroke = egui::Stroke::new(1.0, theme.border_soft); visuals.widgets.noninteractive.fg_stroke = egui::Stroke::new(1.0, theme.text); visuals.widgets.inactive.bg_fill = theme.panel_strong; visuals.widgets.inactive.bg_stroke = egui::Stroke::new(1.0, theme.border_soft); visuals.widgets.inactive.fg_stroke = egui::Stroke::new(1.0, theme.text); visuals.widgets.hovered.bg_fill = egui::Color32::from_rgb(55, 61, 72); visuals.widgets.hovered.bg_stroke = egui::Stroke::new(1.0, theme.border); visuals.widgets.hovered.fg_stroke = egui::Stroke::new(1.0, theme.text); visuals.widgets.active.bg_fill = theme.accent; visuals.widgets.active.bg_stroke = egui::Stroke::new(1.0, theme.accent_hot); visuals.widgets.active.fg_stroke = egui::Stroke::new(1.0, egui::Color32::WHITE); visuals.widgets.open.bg_fill = egui::Color32::from_rgb(50, 56, 66); visuals.widgets.open.bg_stroke = egui::Stroke::new(1.0, theme.border); visuals.widgets.open.fg_stroke = egui::Stroke::new(1.0, theme.text); visuals.selection.bg_fill = theme.accent; visuals.selection.stroke = egui::Stroke::new(1.0, egui::Color32::WHITE); visuals.hyperlink_color = theme.accent_hot; ctx.set_visuals(visuals); let mut style = (*ctx.global_style()).clone(); style.spacing.item_spacing = egui::vec2(7.0, 5.0); style.spacing.window_margin = egui::Margin::same(7); style.visuals.window_corner_radius = egui::CornerRadius::same(theme.radius); style.visuals.menu_corner_radius = egui::CornerRadius::same(2); style.visuals.window_shadow = egui::epaint::Shadow { offset: [0, 12], blur: 24, spread: 0, color: egui::Color32::from_black_alpha(110), }; ctx.set_global_style(style); } pub fn apply_fonts(ctx: &egui::Context) { let mut fonts = egui::FontDefinitions::default(); fonts.font_data.insert( "Hack-Bold".to_owned(), egui::FontData::from_static(include_bytes!("../static/Hack-Bold.ttf")).into(), ); let has_yahei = std::fs::read(r"C:\Windows\Fonts\msyh.ttc") .or_else(|_| std::fs::read(r"C:\Windows\Fonts\msyhbd.ttc")) .map(|font_data| { fonts.font_data.insert( "Microsoft-YaHei".to_owned(), egui::FontData::from_owned(font_data).into(), ); }) .is_ok(); fonts .families .entry(egui::FontFamily::Proportional) .or_default() .insert(0, "Hack-Bold".to_owned()); if has_yahei { fonts .families .entry(egui::FontFamily::Proportional) .or_default() .push("Microsoft-YaHei".to_owned()); } fonts .families .entry(egui::FontFamily::Monospace) .or_default() .insert(0, "Hack-Bold".to_owned()); if has_yahei { fonts .families .entry(egui::FontFamily::Monospace) .or_default() .push("Microsoft-YaHei".to_owned()); } ctx.set_fonts(fonts); } pub fn panel_frame(ctx: &egui::Context) -> egui::Frame { let style = ctx.global_style(); egui::Frame::window(&style) .fill(ONE_DARK_PRO.panel) .stroke(egui::Stroke::new(1.0, ONE_DARK_PRO.border)) .corner_radius(egui::CornerRadius::same(ONE_DARK_PRO.radius)) .shadow(egui::epaint::Shadow { offset: [0, 12], blur: 26, spread: 0, color: egui::Color32::from_black_alpha(120), }) } pub fn group_frame() -> egui::Frame { egui::Frame::new() .fill(ONE_DARK_PRO.panel_deep) .stroke(egui::Stroke::new(1.0, ONE_DARK_PRO.border_soft)) .corner_radius(egui::CornerRadius::same(2)) .inner_margin(egui::Margin::symmetric(6, 5)) } pub fn tag_button(label: impl Into) -> egui::Button<'static> { egui::Button::new(label) .fill(ONE_DARK_PRO.panel_strong) .stroke(egui::Stroke::new(1.0, ONE_DARK_PRO.border)) .corner_radius(egui::CornerRadius::same(2)) } pub fn dim_text() -> egui::Color32 { ONE_DARK_PRO.text_dim } pub fn accent_text() -> egui::Color32 { ONE_DARK_PRO.accent_hot }