diff --git a/egui/src/app.rs b/egui/src/app.rs index 22817f25..6330b3df 100644 --- a/egui/src/app.rs +++ b/egui/src/app.rs @@ -36,6 +36,11 @@ pub trait Backend { /// Smoothed frames per second fn fps(&self) -> f32; + /// Local time. Used for the clock in the demo app. + fn seconds_since_midnight(&self) -> Option { + None + } + /// Signal the backend that we'd like to exit the app now. /// This does nothing for web apps. fn quit(&mut self) {} diff --git a/egui/src/demos/app.rs b/egui/src/demos/app.rs index c87d86e3..a4a9db8b 100644 --- a/egui/src/demos/app.rs +++ b/egui/src/demos/app.rs @@ -47,6 +47,17 @@ impl Default for RunMode { // ---------------------------------------------------------------------------- +/// Special input to the demo-app. +#[derive(Default)] +pub struct DemoEnvironment { + /// For web demo only. e.g. "#fragment". + /// Used to link to specific part of the demo app. + pub web_location_hash: String, + + /// Local time. Used for the clock in the demo app. + pub seconds_since_midnight: Option, +} + /// Demonstrates how to make an app using Egui. /// /// Implements `egui::app::App` so it can be used with @@ -69,27 +80,25 @@ pub struct DemoApp { impl DemoApp { /// Show the app ui (menu bar and windows). - /// - /// * `web_location_hash`: for web demo only. e.g. "#fragment". Set to "". - pub fn ui(&mut self, ui: &mut Ui, web_location_hash: &str) { - if self.previous_web_location_hash != web_location_hash { + pub fn ui(&mut self, ui: &mut Ui, env: &DemoEnvironment) { + if self.previous_web_location_hash != env.web_location_hash { // #fragment end of URL: - if web_location_hash == "#clock" { + if env.web_location_hash == "#clock" { self.open_windows = OpenWindows { fractal_clock: true, ..OpenWindows::none() }; } - self.previous_web_location_hash = web_location_hash.to_owned(); + self.previous_web_location_hash = env.web_location_hash.clone(); } - show_menu_bar(ui, &mut self.open_windows); - self.windows(ui.ctx()); + show_menu_bar(ui, &mut self.open_windows, env); + self.windows(ui.ctx(), env); } /// Show the open windows. - pub fn windows(&mut self, ctx: &Arc) { + pub fn windows(&mut self, ctx: &Arc, env: &DemoEnvironment) { let DemoApp { open_windows, demo_window, @@ -124,7 +133,11 @@ impl DemoApp { ctx.memory_ui(ui); }); - fractal_clock.window(ctx, &mut open_windows.fractal_clock); + fractal_clock.window( + ctx, + &mut open_windows.fractal_clock, + env.seconds_since_midnight, + ); self.resize_windows(ctx); } @@ -273,9 +286,15 @@ impl app::App for DemoApp { let web_info = backend.web_info(); let web_location_hash = web_info .as_ref() - .map(|info| info.web_location_hash.as_str()) + .map(|info| info.web_location_hash.clone()) .unwrap_or_default(); - self.ui(ui, web_location_hash); + + let environment = DemoEnvironment { + web_location_hash, + seconds_since_midnight: backend.seconds_since_midnight(), + }; + + self.ui(ui, &environment); if self.run_mode == RunMode::Continuous { // Tell the backend to repaint as soon as possible @@ -326,7 +345,7 @@ impl OpenWindows { } } -fn show_menu_bar(ui: &mut Ui, windows: &mut OpenWindows) { +fn show_menu_bar(ui: &mut Ui, windows: &mut OpenWindows, env: &DemoEnvironment) { menu::bar(ui, |ui| { menu::menu(ui, "File", |ui| { if ui.add(Button::new("Reorganize windows")).clicked { @@ -362,7 +381,7 @@ fn show_menu_bar(ui: &mut Ui, windows: &mut OpenWindows) { ui.add(Hyperlink::new("https://github.com/emilk/egui").text("Egui home page")); }); - if let Some(time) = ui.input().seconds_since_midnight { + if let Some(time) = env.seconds_since_midnight { let time = format!( "{:02}:{:02}:{:02}.{:02}", (time.rem_euclid(24.0 * 60.0 * 60.0) / 3600.0).floor(), diff --git a/egui/src/demos/fractal_clock.rs b/egui/src/demos/fractal_clock.rs index f6cac5c9..672a8c07 100644 --- a/egui/src/demos/fractal_clock.rs +++ b/egui/src/demos/fractal_clock.rs @@ -31,22 +31,24 @@ impl Default for FractalClock { } impl FractalClock { - pub fn window(&mut self, ctx: &Arc, open: &mut bool) { + pub fn window( + &mut self, + ctx: &Arc, + open: &mut bool, + seconds_since_midnight: Option, + ) { Window::new("FractalClock") .open(open) .default_rect(ctx.rect().expand(-42.0)) .scroll(false) // Dark background frame to make it pop: .frame(Frame::window(&ctx.style()).fill(Srgba::black_alpha(250))) - .show(ctx, |ui| self.ui(ui)); + .show(ctx, |ui| self.ui(ui, seconds_since_midnight)); } - pub fn ui(&mut self, ui: &mut Ui) { + pub fn ui(&mut self, ui: &mut Ui, seconds_since_midnight: Option) { if !self.paused { - self.time = ui - .input() - .seconds_since_midnight - .unwrap_or_else(|| ui.input().time); + self.time = seconds_since_midnight.unwrap_or_else(|| ui.input().time); ui.ctx().request_repaint(); } @@ -57,15 +59,16 @@ impl FractalClock { .fill(Rgba::luminance_alpha(0.02, 0.5).into()) .stroke(Stroke::none()) .show(&mut ui.left_column(320.0), |ui| { - CollapsingHeader::new("Settings").show(ui, |ui| self.options_ui(ui)); + CollapsingHeader::new("Settings") + .show(ui, |ui| self.options_ui(ui, seconds_since_midnight)); }); // Make sure we allocate what we used (everything) ui.allocate_space(painter.clip_rect().size()); } - fn options_ui(&mut self, ui: &mut Ui) { - if ui.input().seconds_since_midnight.is_some() { + fn options_ui(&mut self, ui: &mut Ui, seconds_since_midnight: Option) { + if seconds_since_midnight.is_some() { ui.add(label!( "Local time: {:02}:{:02}:{:02}.{:03}", (self.time.rem_euclid(24.0 * 60.0 * 60.0) / 3600.0).floor(), diff --git a/egui/src/input.rs b/egui/src/input.rs index 5eb89360..3c6846c7 100644 --- a/egui/src/input.rs +++ b/egui/src/input.rs @@ -13,12 +13,13 @@ const MAX_CLICK_DELAY: f64 = 0.3; #[derive(Clone, Debug, Default)] pub struct RawInput { /// Is the button currently down? + /// NOTE: Egui currently only supports the primary mouse button. pub mouse_down: bool, /// Current position of the mouse in points. pub mouse_pos: Option, - /// How many pixels the user scrolled + /// How many points (logical pixels) the user scrolled pub scroll_delta: Vec2, /// Size of the screen in points. @@ -32,9 +33,6 @@ pub struct RawInput { /// Time in seconds. Relative to whatever. Used for animations. pub time: f64, - /// Local time. Only used for the clock in the demo app. - pub seconds_since_midnight: Option, - /// In-order events received this frame pub events: Vec, } @@ -49,7 +47,6 @@ impl RawInput { screen_size: self.screen_size, pixels_per_point: self.pixels_per_point, time: self.time, - seconds_since_midnight: self.seconds_since_midnight, events: std::mem::take(&mut self.events), } } @@ -83,9 +80,6 @@ pub struct InputState { /// Should be set to the expected time between frames when painting at vsync speeds. pub predicted_dt: f32, - /// Local time. Only used for the clock in the demo app. - pub seconds_since_midnight: Option, - /// In-order events received this frame pub events: Vec, } @@ -208,8 +202,7 @@ impl InputState { pixels_per_point: new.pixels_per_point.or(self.pixels_per_point), time: new.time, unstable_dt, - predicted_dt: 1.0 / 60.0, // TODO: remove this hack - seconds_since_midnight: new.seconds_since_midnight, + predicted_dt: 1.0 / 60.0, // TODO: remove this hack events: new.events.clone(), // TODO: remove clone() and use raw.events raw: new, } @@ -351,10 +344,6 @@ impl RawInput { "Also called HDPI factor.\nNumber of physical pixels per each logical pixel.", ); ui.add(label!("time: {:.3} s", self.time)); - ui.add(label!( - "seconds_since_midnight: {:?} s", - self.seconds_since_midnight - )); ui.add(label!("events: {:?}", self.events)) .tooltip_text("key presses etc"); } @@ -380,10 +369,6 @@ impl InputState { )); ui.add(label!("time: {:.3} s", self.time)); ui.add(label!("dt: {:.1} ms", 1e3 * self.unstable_dt)); - ui.add(label!( - "seconds_since_midnight: {:?} s", - self.seconds_since_midnight - )); ui.add(label!("events: {:?}", self.events)) .tooltip_text("key presses etc"); } diff --git a/egui_glium/src/backend.rs b/egui_glium/src/backend.rs index 1912cbfd..8c6b4805 100644 --- a/egui_glium/src/backend.rs +++ b/egui_glium/src/backend.rs @@ -38,6 +38,10 @@ impl Backend for GliumBackend { 1.0 / self.frame_times.mean_time_interval().unwrap_or_default() } + fn seconds_since_midnight(&self) -> Option { + Some(seconds_since_midnight()) + } + fn quit(&mut self) { self.quit = true; } @@ -90,7 +94,6 @@ pub fn run(title: &str, mut storage: FileStorage, mut app: impl App + 'static) - let mut redraw = || { let egui_start = Instant::now(); raw_input.time = start_time.elapsed().as_nanos() as f64 * 1e-9; - raw_input.seconds_since_midnight = Some(local_time_of_day()); let mut ui = ctx.begin_frame(raw_input.take()); app.ui(&mut ui, &mut runner); diff --git a/egui_glium/src/lib.rs b/egui_glium/src/lib.rs index 435eb601..11d9feaf 100644 --- a/egui_glium/src/lib.rs +++ b/egui_glium/src/lib.rs @@ -205,7 +205,7 @@ pub fn init_clipboard() -> Option { // ---------------------------------------------------------------------------- /// Time of day as seconds since midnight. Used for clock in demo app. -pub fn local_time_of_day() -> f64 { +pub fn seconds_since_midnight() -> f64 { use chrono::Timelike; let time = chrono::Local::now().time(); time.num_seconds_from_midnight() as f64 + 1e-9 * (time.nanosecond() as f64) diff --git a/egui_web/src/backend.rs b/egui_web/src/backend.rs index c79520a9..8f4014be 100644 --- a/egui_web/src/backend.rs +++ b/egui_web/src/backend.rs @@ -96,6 +96,10 @@ impl Backend for WebBackend { 1.0 / self.frame_times.mean_time_interval().unwrap_or_default() } + fn seconds_since_midnight(&self) -> Option { + Some(seconds_since_midnight()) + } + fn new_texture_srgba_premultiplied( &mut self, size: (usize, usize), @@ -128,7 +132,6 @@ impl WebInput { screen_size: screen_size().unwrap(), pixels_per_point: Some(pixels_per_point()), time: now_sec(), - seconds_since_midnight: Some(seconds_since_midnight()), events: std::mem::take(&mut self.events), } }