corundum_framework_gui/window/
mod.rs1use crate::gpu;
29
30#[cfg(all(target_os = "android", feature = "android"))]
31mod android;
32#[cfg(target_os = "ios")]
33mod ios;
34#[cfg_attr(not(all(target_os = "android", feature = "android")), allow(dead_code))]
36mod text_input;
37
38#[cfg(all(target_os = "android", feature = "android"))]
39pub use android::{AndroidApp, run_android};
40
41pub type InstallFonts = Box<dyn FnOnce(&egui::Context)>;
43
44pub struct WindowOptions {
46 title: String,
47 inner_size: [f32; 2],
48 min_inner_size: [f32; 2],
49 fonts: Option<InstallFonts>,
50 #[cfg(feature = "serde")]
51 store: Option<crate::store::Store>,
52}
53
54impl WindowOptions {
55 pub fn new(title: impl Into<String>) -> WindowOptions {
57 WindowOptions {
58 title: title.into(),
59 inner_size: [900.0, 600.0],
60 min_inner_size: [600.0, 400.0],
61 fonts: None,
62 #[cfg(feature = "serde")]
63 store: None,
64 }
65 }
66
67 pub fn inner_size(mut self, size: [f32; 2]) -> WindowOptions {
69 self.inner_size = size;
70 self
71 }
72
73 pub fn min_inner_size(mut self, size: [f32; 2]) -> WindowOptions {
75 self.min_inner_size = size;
76 self
77 }
78
79 pub fn fonts(mut self, install: impl FnOnce(&egui::Context) + 'static) -> WindowOptions {
82 self.fonts = Some(Box::new(install));
83 self
84 }
85
86 #[cfg(feature = "serde")]
90 pub fn remember(mut self, store: crate::store::Store) -> WindowOptions {
91 self.store = Some(store);
92 self
93 }
94
95 #[cfg_attr(not(feature = "serde"), allow(unused_mut))]
97 pub(crate) fn wrap_create<'f>(
98 &mut self,
99 create: impl FnOnce(&eframe::CreationContext<'_>) -> Box<dyn eframe::App> + 'f,
100 ) -> impl FnOnce(&eframe::CreationContext<'_>) -> Box<dyn eframe::App> + 'f {
101 #[cfg(feature = "serde")]
102 let store = self.store.take();
103 move |cc| {
104 #[cfg(feature = "serde")]
105 if let Some(store) = store {
106 crate::store::attach(&cc.egui_ctx, store);
107 }
108 create(cc)
109 }
110 }
111}
112
113pub fn run(
118 options: WindowOptions,
119 create: impl FnOnce(&eframe::CreationContext<'_>) -> Box<dyn eframe::App>,
120) -> eframe::Result<()> {
121 let mut options = options;
122 let create = options.wrap_create(create);
123 let WindowOptions {
124 title,
125 inner_size,
126 min_inner_size,
127 fonts,
128 ..
129 } = options;
130 gpu::install_panic_hook();
131 let native = eframe::NativeOptions {
132 viewport: egui::ViewportBuilder::default()
133 .with_inner_size(inner_size)
134 .with_min_inner_size(min_inner_size)
135 .with_title(&title),
136 wgpu_options: gpu::wgpu_options(),
137 ..Default::default()
138 };
139 open(&title, native, fonts, create)
140}
141
142pub fn open(
146 title: &str,
147 native: eframe::NativeOptions,
148 fonts: Option<InstallFonts>,
149 create: impl FnOnce(&eframe::CreationContext<'_>) -> Box<dyn eframe::App>,
150) -> eframe::Result<()> {
151 eframe::run_native(
152 title,
153 native,
154 Box::new(move |cc| {
155 gpu::on_render_state(cc.wgpu_render_state.as_ref());
156 match fonts {
157 Some(install) => install(&cc.egui_ctx),
158 None => {
159 crate::fonts::install_system_cjk_fallback(&cc.egui_ctx);
160 }
161 }
162 let app = create(cc);
163 #[cfg(target_os = "ios")]
165 let app = ios::full_screen(cc, app);
166 Ok(app)
167 }),
168 )
169}
170
171#[cfg(test)]
172mod tests {
173 use super::*;
174
175 #[test]
176 fn options_default_and_override_the_window_size() {
177 let options = WindowOptions::new("Example");
178 assert_eq!(options.title, "Example");
179 assert_eq!(options.inner_size, [900.0, 600.0]);
180 assert_eq!(options.min_inner_size, [600.0, 400.0]);
181 assert!(options.fonts.is_none());
182 let options = options
183 .inner_size([1000.0, 640.0])
184 .min_inner_size([720.0, 440.0])
185 .fonts(|_| {});
186 assert_eq!(options.inner_size, [1000.0, 640.0]);
187 assert_eq!(options.min_inner_size, [720.0, 440.0]);
188 assert!(options.fonts.is_some());
189 }
190}