workflow_egui/frame/
core.rs

1use crate::frame::app::App;
2use crate::imports::*;
3
4pub struct Core<T>
5where
6    T: App,
7{
8    app: Box<T>,
9
10    is_shutdown_pending: bool,
11    _settings_storage_requested: bool,
12    _last_settings_storage_request: Instant,
13
14    #[allow(dead_code)]
15    runtime: Runtime,
16    events: ApplicationEventsChannel,
17}
18
19impl<T> Core<T>
20where
21    T: App,
22{
23    /// Core initialization
24    pub fn try_new(
25        cc: &eframe::CreationContext<'_>,
26        runtime: Runtime,
27        app_creator: crate::frame::AppCreator<T>,
28    ) -> Result<Self> {
29        let mut app = app_creator(cc, runtime.clone())?;
30        app.init(&runtime, cc);
31
32        let events = runtime.events().clone();
33
34        Ok(Self {
35            runtime,
36            app,
37            is_shutdown_pending: false,
38            _settings_storage_requested: false,
39            _last_settings_storage_request: Instant::now(),
40            events,
41        })
42    }
43}
44
45impl<T> eframe::App for Core<T>
46where
47    T: App,
48{
49    #[cfg(not(target_arch = "wasm32"))]
50    fn on_exit(&mut self, _gl: Option<&eframe::glow::Context>) {
51        self.is_shutdown_pending = true;
52        Runtime::halt();
53        println!("bye!");
54    }
55
56    fn clear_color(&self, _visuals: &egui::Visuals) -> [f32; 4] {
57        egui::Rgba::TRANSPARENT.to_array()
58    }
59
60    /// Called each time the UI needs repainting, which may be many times per second.
61    /// Put your widgets into a `SidePanel`, `TopPanel`, `CentralPanel`, `Window` or `Area`.
62    fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
63        log_info!("--- update ---");
64
65        for event in self.events.iter() {
66            if let Err(err) = self.handle_events(event.clone(), ctx, frame) {
67                log_error!("error processing wallet runtime event: {}", err);
68            }
69        }
70
71        if self.is_shutdown_pending {
72            return;
73        }
74
75        ctx.input(|input| {
76            input.events.iter().for_each(|event| {
77                if let egui::Event::Key {
78                    key,
79                    pressed,
80                    modifiers,
81                    repeat,
82                    // TODO - propagate
83                    physical_key: _,
84                    // ..
85                } = event
86                {
87                    self.handle_keyboard_events(*key, *pressed, modifiers, *repeat);
88                }
89            });
90        });
91
92        if let Some(device) = self.app.device() {
93            device.set_screen_size(&ctx.screen_rect())
94        }
95
96        self.render(ctx, frame);
97
98        // #[cfg(not(target_arch = "wasm32"))]
99        // if let Some(screenshot) = self.screenshot.clone() {
100        //     self.handle_screenshot(ctx, screenshot);
101        // }
102    }
103}
104
105impl<T> Core<T>
106where
107    T: App,
108{
109    fn render(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
110        self.app.render(ctx, frame);
111    }
112
113    // #[cfg(not(target_arch = "wasm32"))]
114    // fn handle_screenshot(&mut self, ctx: &Context, screenshot: Arc<ColorImage>) {
115    //     match rfd::FileDialog::new().save_file() {
116    //         Some(mut path) => {
117    //             path.set_extension("png");
118    //             let screen_rect = ctx.screen_rect();
119    //             let pixels_per_point = ctx.pixels_per_point();
120    //             let screenshot = screenshot.clone();
121    //             let sender = self.sender();
122    //             std::thread::Builder::new()
123    //                 .name("screenshot".to_string())
124    //                 .spawn(move || {
125    //                     let image = screenshot.region(&screen_rect, Some(pixels_per_point));
126    //                     image::save_buffer(
127    //                         &path,
128    //                         image.as_raw(),
129    //                         image.width() as u32,
130    //                         image.height() as u32,
131    //                         image::ColorType::Rgba8,
132    //                     )
133    //                     .unwrap();
134
135    //                     sender
136    //                         .try_send(Events::Notify {
137    //                             user_notification: UserNotification::success(format!(
138    //                                 "Capture saved to\n{}",
139    //                                 path.to_string_lossy()
140    //                             ))
141    //                             .as_toast(),
142    //                         })
143    //                         .unwrap()
144    //                 })
145    //                 .expect("Unable to spawn screenshot thread");
146    //             self.screenshot.take();
147    //         }
148    //         None => {
149    //             self.screenshot.take();
150    //         }
151    //     }
152    // }
153
154    pub fn handle_events(
155        &mut self,
156        event: RuntimeEvent,
157        ctx: &egui::Context,
158        _frame: &mut eframe::Frame,
159    ) -> Result<()> {
160        // log_info!("--- event: {:?}", event);
161        if matches!(event, RuntimeEvent::Exit) {
162            self.is_shutdown_pending = true;
163        }
164
165        self.app.handle_event(ctx, event);
166
167        Ok(())
168    }
169
170    fn handle_keyboard_events(
171        &mut self,
172        key: egui::Key,
173        pressed: bool,
174        modifiers: &egui::Modifiers,
175        _repeat: bool,
176    ) {
177        self.app
178            .handle_keyboard_events(key, pressed, modifiers, false);
179    }
180
181    // pub fn apply_mobile_style(&self, ui: &mut Ui) {
182    //     ui.style_mut().text_styles = self.mobile_style.text_styles.clone();
183    // }
184
185    // pub fn apply_default_style(&self, ui: &mut Ui) {
186    //     ui.style_mut().text_styles = self.default_style.text_styles.clone();
187    // }
188}