khora_infra/ui/egui/app/
context.rs1use std::collections::HashMap;
12
13use khora_core::ui::editor::ViewportTextureHandle;
14use khora_core::ui::{AppContext, FontPack, UiBuilder, UiTheme};
15
16use crate::ui::egui::theme::apply_theme;
17use crate::ui::egui::ui_builder::EguiUiBuilder;
18
19pub struct EguiAppContext<'a> {
29 ui: &'a mut egui::Ui,
30 frame: &'a mut eframe::Frame,
31 viewport_textures: HashMap<ViewportTextureHandle, egui::TextureId>,
34}
35
36impl<'a> EguiAppContext<'a> {
37 pub fn new(ui: &'a mut egui::Ui, frame: &'a mut eframe::Frame) -> Self {
39 Self {
40 ui,
41 frame,
42 viewport_textures: HashMap::new(),
43 }
44 }
45}
46
47impl AppContext for EguiAppContext<'_> {
48 fn central(&mut self, f: &mut dyn FnMut(&mut dyn UiBuilder)) {
49 let vt = &self.viewport_textures;
50 egui::CentralPanel::default()
51 .frame(egui::Frame::new())
52 .show_inside(self.ui, |ui| {
53 let mut builder = EguiUiBuilder::new(ui, vt);
54 f(&mut builder);
55 });
56 }
57
58 fn set_theme(&mut self, theme: &UiTheme) {
59 let ctx = self.ui.ctx().clone();
60 apply_theme(&ctx, theme);
61 }
62
63 fn set_fonts(&mut self, pack: &FontPack) {
64 if pack.is_empty() {
65 return;
66 }
67 use std::sync::Arc;
68 let ctx = self.ui.ctx().clone();
69 let mut defs = egui::FontDefinitions::default();
70 install_family(
71 &mut defs,
72 egui::FontFamily::Proportional,
73 &pack.proportional,
74 );
75 install_family(&mut defs, egui::FontFamily::Monospace, &pack.monospace);
76 if !pack.display.is_empty() {
77 install_family(
78 &mut defs,
79 egui::FontFamily::Name("display".into()),
80 &pack.display,
81 );
82 }
83 if !pack.icons.is_empty() {
84 install_family(
85 &mut defs,
86 egui::FontFamily::Name("icons".into()),
87 &pack.icons,
88 );
89 }
90 for named in ["display", "icons"] {
96 let fallback = defs
97 .families
98 .get(&egui::FontFamily::Proportional)
99 .cloned()
100 .unwrap_or_default();
101 let entry = defs
102 .families
103 .entry(egui::FontFamily::Name(named.into()))
104 .or_default();
105 for key in fallback {
106 if !entry.contains(&key) {
107 entry.push(key);
108 }
109 }
110 }
111 ctx.set_fonts(defs);
112
113 fn install_family(
114 defs: &mut egui::FontDefinitions,
115 family: egui::FontFamily,
116 fonts: &[khora_core::ui::NamedFont],
117 ) {
118 for (idx, named) in fonts.iter().enumerate() {
119 let key = named.name.clone();
120 let bytes = match &named.data {
121 khora_core::ui::FontHandle::Static(s) => s.to_vec(),
122 khora_core::ui::FontHandle::Owned(v) => v.clone(),
123 };
124 defs.font_data
125 .insert(key.clone(), Arc::new(egui::FontData::from_owned(bytes)));
126 let entry = defs.families.entry(family.clone()).or_default();
127 if idx == 0 {
128 entry.insert(0, key);
129 } else {
130 entry.push(key);
131 }
132 }
133 }
134 }
135
136 fn screen_size(&self) -> [f32; 2] {
137 let r = self
138 .ui
139 .ctx()
140 .input(|i| i.viewport().inner_rect.unwrap_or(egui::Rect::ZERO));
141 [r.width(), r.height()]
142 }
143
144 fn pixels_per_point(&self) -> f32 {
145 self.ui.ctx().pixels_per_point()
146 }
147
148 fn request_repaint(&mut self) {
149 self.ui.ctx().request_repaint();
150 }
151
152 fn request_close(&mut self) {
153 self.ui
154 .ctx()
155 .send_viewport_cmd(egui::ViewportCommand::Close);
156 let _ = &self.frame; }
158}