app_style.rs (6460B)
1 use crate::{ 2 colors::{desktop_dark_color_theme, light_color_theme, mobile_dark_color_theme, ColorTheme}, 3 ui::is_narrow, 4 }; 5 use egui::{ 6 epaint::Shadow, 7 style::{Interaction, Selection, WidgetVisuals, Widgets}, 8 Button, Context, FontFamily, FontId, Rounding, Stroke, Style, TextStyle, Ui, Visuals, 9 }; 10 use strum::IntoEnumIterator; 11 use strum_macros::EnumIter; 12 13 const WIDGET_ROUNDING: Rounding = Rounding::same(8.0); 14 15 pub fn light_mode() -> Visuals { 16 create_themed_visuals(light_color_theme(), Visuals::light()) 17 } 18 19 pub fn dark_mode(mobile: bool) -> Visuals { 20 create_themed_visuals( 21 if mobile { 22 mobile_dark_color_theme() 23 } else { 24 desktop_dark_color_theme() 25 }, 26 Visuals::dark(), 27 ) 28 } 29 30 pub fn user_requested_visuals_change( 31 oled: bool, 32 cur_darkmode: bool, 33 ui: &mut Ui, 34 ) -> Option<Visuals> { 35 if cur_darkmode { 36 if ui 37 .add(Button::new("☀").frame(false)) 38 .on_hover_text("Switch to light mode") 39 .clicked() 40 { 41 return Some(light_mode()); 42 } 43 } else if ui 44 .add(Button::new("🌙").frame(false)) 45 .on_hover_text("Switch to dark mode") 46 .clicked() 47 { 48 return Some(dark_mode(oled)); 49 } 50 None 51 } 52 53 /// Create custom text sizes for any FontSizes 54 pub fn create_custom_style(ctx: &Context, font_size: fn(&NotedeckTextStyle) -> f32) -> Style { 55 let mut style = (*ctx.style()).clone(); 56 57 style.text_styles = NotedeckTextStyle::iter() 58 .map(|text_style| { 59 ( 60 text_style.text_style(), 61 FontId::new(font_size(&text_style), text_style.font_family()), 62 ) 63 }) 64 .collect(); 65 66 style.interaction = Interaction { 67 tooltip_delay: 0.1, 68 show_tooltips_only_when_still: false, 69 ..Interaction::default() 70 }; 71 72 style 73 } 74 75 pub fn desktop_font_size(text_style: &NotedeckTextStyle) -> f32 { 76 match text_style { 77 NotedeckTextStyle::Heading => 48.0, 78 NotedeckTextStyle::Heading2 => 24.0, 79 NotedeckTextStyle::Heading3 => 20.0, 80 NotedeckTextStyle::Body => 16.0, 81 NotedeckTextStyle::Monospace => 13.0, 82 NotedeckTextStyle::Button => 13.0, 83 NotedeckTextStyle::Small => 12.0, 84 } 85 } 86 87 pub fn mobile_font_size(text_style: &NotedeckTextStyle) -> f32 { 88 // TODO: tweak text sizes for optimal mobile viewing 89 match text_style { 90 NotedeckTextStyle::Heading => 48.0, 91 NotedeckTextStyle::Heading2 => 24.0, 92 NotedeckTextStyle::Heading3 => 20.0, 93 NotedeckTextStyle::Body => 13.0, 94 NotedeckTextStyle::Monospace => 13.0, 95 NotedeckTextStyle::Button => 13.0, 96 NotedeckTextStyle::Small => 12.0, 97 } 98 } 99 100 pub fn get_font_size(ctx: &egui::Context, text_style: &NotedeckTextStyle) -> f32 { 101 if is_narrow(ctx) { 102 mobile_font_size(text_style) 103 } else { 104 desktop_font_size(text_style) 105 } 106 } 107 108 #[derive(Copy, Clone, Eq, PartialEq, Debug, EnumIter)] 109 pub enum NotedeckTextStyle { 110 Heading, 111 Heading2, 112 Heading3, 113 Body, 114 Monospace, 115 Button, 116 Small, 117 } 118 119 impl NotedeckTextStyle { 120 pub fn text_style(&self) -> TextStyle { 121 match self { 122 Self::Heading => TextStyle::Heading, 123 Self::Heading2 => TextStyle::Name("Heading2".into()), 124 Self::Heading3 => TextStyle::Name("Heading3".into()), 125 Self::Body => TextStyle::Body, 126 Self::Monospace => TextStyle::Monospace, 127 Self::Button => TextStyle::Button, 128 Self::Small => TextStyle::Small, 129 } 130 } 131 132 pub fn font_family(&self) -> FontFamily { 133 match self { 134 Self::Heading => FontFamily::Proportional, 135 Self::Heading2 => FontFamily::Proportional, 136 Self::Heading3 => FontFamily::Proportional, 137 Self::Body => FontFamily::Proportional, 138 Self::Monospace => FontFamily::Monospace, 139 Self::Button => FontFamily::Proportional, 140 Self::Small => FontFamily::Proportional, 141 } 142 } 143 } 144 145 pub fn create_themed_visuals(theme: ColorTheme, default: Visuals) -> Visuals { 146 Visuals { 147 hyperlink_color: theme.hyperlink_color, 148 override_text_color: Some(theme.text_color), 149 panel_fill: theme.panel_fill, 150 selection: Selection { 151 bg_fill: theme.selection_color, 152 stroke: Stroke { 153 width: 1.0, 154 color: theme.selection_color, 155 }, 156 }, 157 widgets: Widgets { 158 noninteractive: WidgetVisuals { 159 bg_fill: theme.noninteractive_bg_fill, 160 weak_bg_fill: theme.noninteractive_weak_bg_fill, 161 bg_stroke: Stroke { 162 width: 1.0, 163 color: theme.noninteractive_bg_stroke_color, 164 }, 165 fg_stroke: Stroke { 166 width: 1.0, 167 color: theme.noninteractive_fg_stroke_color, 168 }, 169 rounding: WIDGET_ROUNDING, 170 ..default.widgets.noninteractive 171 }, 172 inactive: WidgetVisuals { 173 bg_fill: theme.inactive_bg_fill, 174 weak_bg_fill: theme.inactive_weak_bg_fill, 175 bg_stroke: Stroke { 176 width: 1.0, 177 color: theme.inactive_bg_stroke_color, 178 }, 179 rounding: WIDGET_ROUNDING, 180 ..default.widgets.inactive 181 }, 182 hovered: WidgetVisuals { 183 rounding: WIDGET_ROUNDING, 184 ..default.widgets.hovered 185 }, 186 active: WidgetVisuals { 187 rounding: WIDGET_ROUNDING, 188 ..default.widgets.active 189 }, 190 open: WidgetVisuals { 191 ..default.widgets.open 192 }, 193 }, 194 extreme_bg_color: theme.extreme_bg_color, 195 error_fg_color: theme.err_fg_color, 196 window_rounding: Rounding::same(8.0), 197 window_fill: theme.window_fill, 198 window_shadow: Shadow { 199 offset: [0.0, 8.0].into(), 200 blur: 24.0, 201 spread: 0.0, 202 color: egui::Color32::from_rgba_unmultiplied(0x6D, 0x6D, 0x6D, 0x14), 203 }, 204 window_stroke: Stroke { 205 width: 1.0, 206 color: theme.window_stroke_color, 207 }, 208 image_loading_spinners: false, 209 ..default 210 } 211 }