1use super::{MacBackgroundStyle, MacTheme};
4use crate::tokens::{
5 BoxViewMetrics, ButtonMetrics, CheckboxMetrics, CollectionViewMetrics, ColorWellMetrics,
6 ComboBoxMetrics, ContextMenuMetrics, DatePickerMetrics, DisclosureGroupMetrics,
7 FocusRingMetrics, FooterMetrics, HelpButtonMetrics, InlineActionButtonMetrics, LabelMetrics,
8 LayoutMetrics, LevelIndicatorMetrics, MacControlMetrics, MacMotionTokens, MacTypographyTokens,
9 MenuBarMetrics, NavigationMetrics, OutlineViewMetrics, PaletteMetrics, PathControlMetrics,
10 PlayerViewMetrics, PopUpButtonMetrics, PopoverMetrics, ProgressIndicatorMetrics,
11 RuleEditorMetrics, ScrollViewMetrics, SearchFieldMetrics, SegmentedMetrics, SliderMetrics,
12 SplitViewMetrics, StackViewMetrics, StepperMetrics, TabViewMetrics, TableViewMetrics,
13 TextFieldMetrics, ThumbnailCellMetrics, ToastMetrics, ToggleMetrics, TokenFieldMetrics,
14 ToolbarMetrics, TrimScrubberMetrics,
15};
16use egui::{Color32, FontId, Galley, TextFormat, Ui};
17use std::sync::Arc;
18
19const fn tracking_table_key(pt: i32) -> Option<&'static str> {
20 match pt {
21 6 => Some("pt_6"),
22 7 => Some("pt_7"),
23 8 => Some("pt_8"),
24 9 => Some("pt_9"),
25 10 => Some("pt_10"),
26 11 => Some("pt_11"),
27 12 => Some("pt_12"),
28 13 => Some("pt_13"),
29 14 => Some("pt_14"),
30 15 => Some("pt_15"),
31 16 => Some("pt_16"),
32 17 => Some("pt_17"),
33 18 => Some("pt_18"),
34 19 => Some("pt_19"),
35 20 => Some("pt_20"),
36 21 => Some("pt_21"),
37 22 => Some("pt_22"),
38 23 => Some("pt_23"),
39 24 => Some("pt_24"),
40 _ => None,
41 }
42}
43
44impl MacTheme {
45 pub fn tracking_for_font_size(&self, size_pt: f32) -> f32 {
49 let rounded = size_pt.round();
50 if (size_pt - rounded).abs() == 0.0 {
51 if let Some(key) = tracking_table_key(rounded as i32) {
52 if let Some(entry) = self.typography().tracking_table.get(key) {
53 return entry.tracking_pt;
54 }
55 }
56 }
57 crate::tokens::sf_pro_tracking(size_pt)
58 }
59
60 pub fn semibold_font_id(&self, ui: &Ui, size_pt: f32) -> (FontId, bool) {
64 static INTER_SEMIBOLD_FAMILY: std::sync::OnceLock<egui::FontFamily> =
65 std::sync::OnceLock::new();
66 let family = INTER_SEMIBOLD_FAMILY.get_or_init(|| {
67 egui::FontFamily::Name(crate::symbols::INTER_SEMIBOLD_FONT_NAME.into())
68 });
69 let cache_id = egui::Id::unique("macview_has_inter_semibold");
70 let pass_nr = ui.ctx().cumulative_pass_nr();
71 let cached = ui.ctx().data(|d| d.get_temp::<(u64, bool)>(cache_id));
72 let has_semibold = match cached {
73 Some((_, true)) => true,
74 Some((cached_pass, false)) if cached_pass == pass_nr => false,
75 _ => {
76 let found = ui.fonts(|f| f.families().contains(family));
77 ui.ctx().data_mut(|d| d.insert_temp(cache_id, (pass_nr, found)));
78 found
79 }
80 };
81 if has_semibold {
82 (FontId::new(size_pt, family.clone()), true)
83 } else {
84 (FontId::proportional(size_pt), false)
85 }
86 }
87
88 pub fn tracked_text_format(&self, font_id: FontId, color: Color32) -> TextFormat {
91 TextFormat {
92 font_id: font_id.clone(),
93 color,
94 extra_letter_spacing: self.tracking_for_font_size(font_id.size),
95 ..Default::default()
96 }
97 }
98
99 pub fn layout_tracked_galley(
102 &self,
103 ui: &Ui,
104 text: &str,
105 font_id: FontId,
106 color: Color32,
107 wrap_width: f32,
108 ) -> Arc<Galley> {
109 let mut job = egui::text::LayoutJob::single_section(
110 text.to_owned(),
111 self.tracked_text_format(font_id, color),
112 );
113 job.wrap.max_width = wrap_width;
114 ui.painter().layout_job(job)
115 }
116
117 pub fn control_metrics(&self) -> &MacControlMetrics { self.tokens.control_metrics() }
119 pub fn button(&self) -> &ButtonMetrics { &self.tokens.control_metrics().button }
121 pub fn text_field(&self) -> &TextFieldMetrics { &self.tokens.control_metrics().text_field }
123 pub fn segmented(&self) -> &SegmentedMetrics { &self.tokens.control_metrics().segmented }
125 pub fn focus_ring(&self) -> &FocusRingMetrics { &self.tokens.control_metrics().focus_ring }
127 pub fn toolbar_metrics(&self) -> &ToolbarMetrics { self.tokens.toolbar_metrics() }
129 pub fn popover_metrics(&self) -> &PopoverMetrics { self.tokens.popover_metrics() }
131 pub fn split_view(&self) -> &SplitViewMetrics { self.tokens.split_view_metrics() }
133 pub fn layout_metrics(&self) -> &LayoutMetrics { self.tokens.layout_metrics() }
135 pub fn scroll_view(&self) -> &ScrollViewMetrics { self.tokens.scroll_view_metrics() }
137 pub fn stack_view(&self) -> &StackViewMetrics { self.tokens.stack_view_metrics() }
139 pub fn outline_view(&self) -> &OutlineViewMetrics { self.tokens.outline_view_metrics() }
141 pub fn slider(&self) -> &SliderMetrics { self.tokens.slider_metrics() }
143 pub fn thumbnail(&self) -> &ThumbnailCellMetrics { self.tokens.thumbnail_metrics() }
145 pub fn popup_button(&self) -> &PopUpButtonMetrics { self.tokens.popup_button_metrics() }
147 pub fn search_field(&self) -> &SearchFieldMetrics { self.tokens.search_field_metrics() }
149 pub fn stepper(&self) -> &StepperMetrics { self.tokens.stepper_metrics() }
151 pub fn color_well(&self) -> &ColorWellMetrics { self.tokens.color_well_metrics() }
153 pub fn toggle(&self) -> &ToggleMetrics { self.tokens.toggle_metrics() }
155 pub fn navigation_metrics(&self) -> &NavigationMetrics { self.tokens.navigation_metrics() }
157 pub fn menu_bar_metrics(&self) -> &MenuBarMetrics { self.tokens.menu_bar_metrics() }
159 pub fn footer_metrics(&self) -> &FooterMetrics { self.tokens.footer_metrics() }
161 pub fn palette_metrics(&self) -> &PaletteMetrics { self.tokens.palette_metrics() }
163 pub fn context_menu_metrics(&self) -> &ContextMenuMetrics { self.tokens.context_menu_metrics() }
165 pub fn toast_metrics(&self) -> &ToastMetrics { self.tokens.toast_metrics() }
167 pub fn progress_indicator(&self) -> &ProgressIndicatorMetrics { self.tokens.progress_indicator_metrics() }
169 pub fn table_view(&self) -> &TableViewMetrics { self.tokens.table_view_metrics() }
171 pub fn token_field(&self) -> &TokenFieldMetrics { self.tokens.token_field_metrics() }
173 pub fn level_indicator(&self) -> &LevelIndicatorMetrics { self.tokens.level_indicator_metrics() }
175 pub fn trim_scrubber(&self) -> &TrimScrubberMetrics { self.tokens.trim_scrubber_metrics() }
177 pub fn path_control(&self) -> &PathControlMetrics { self.tokens.path_control_metrics() }
179 pub fn disclosure_group(&self) -> &DisclosureGroupMetrics { self.tokens.disclosure_group_metrics() }
181 pub fn combo_box(&self) -> &ComboBoxMetrics { self.tokens.combo_box_metrics() }
183 pub fn tab_view(&self) -> &TabViewMetrics { self.tokens.tab_view_metrics() }
185 pub fn date_picker(&self) -> &DatePickerMetrics { self.tokens.date_picker_metrics() }
187 pub fn collection_view(&self) -> &CollectionViewMetrics { self.tokens.collection_view_metrics() }
189 pub fn player_view(&self) -> &PlayerViewMetrics { self.tokens.player_view_metrics() }
191 pub fn box_view(&self) -> &BoxViewMetrics { self.tokens.box_view_metrics() }
193 pub fn rule_editor(&self) -> &RuleEditorMetrics { self.tokens.rule_editor_metrics() }
195 pub fn checkbox(&self) -> &CheckboxMetrics { self.tokens.checkbox_metrics() }
197 pub fn label_metrics(&self) -> &LabelMetrics { self.tokens.label_metrics() }
199 pub fn help_button(&self) -> &HelpButtonMetrics { self.tokens.help_button_metrics() }
201 pub fn inline_action_button(&self) -> &InlineActionButtonMetrics { self.tokens.inline_action_button_metrics() }
203 pub fn typography(&self) -> &MacTypographyTokens { self.tokens.typography() }
205 pub fn motion(&self) -> &MacMotionTokens { self.tokens.motion() }
207
208 pub fn background_style(&self, surface_bg: Color32) -> MacBackgroundStyle {
210 MacBackgroundStyle::from_color(surface_bg)
211 }
212 pub fn accent_background_style(&self) -> MacBackgroundStyle {
214 MacBackgroundStyle::from_color(self.control_accent())
215 }
216 pub fn selected_control_background_style(&self) -> MacBackgroundStyle {
218 MacBackgroundStyle::from_color(self.selected_control())
219 }
220 pub fn disabled_opacity(&self) -> f32 {
222 self.tokens.control_metrics().disabled_opacity.points()
223 }
224 pub fn apply_enabled(&self, color: Color32, enabled: bool) -> Color32 {
226 if enabled { color } else { color.gamma_multiply(self.disabled_opacity()) }
227 }
228
229 pub fn paint_focus_ring(&self, painter: &egui::Painter, rect: egui::Rect, corner_radius: f32) {
231 let ring = self.focus_ring();
232 let focus_rect = rect.expand(ring.offset.points());
233 let focus_radius = corner_radius + ring.corner_radius_delta.points();
234 painter.rect_stroke(
235 focus_rect,
236 egui::CornerRadius::same(focus_radius as u8),
237 egui::Stroke::new(ring.stroke_width.points(), self.keyboard_focus_indicator()),
238 egui::StrokeKind::Outside,
239 );
240 }
241}