From 6bbdf08482bae7dc09b474fda17f99bf69cd3613 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 19 Oct 2020 23:06:11 +0200 Subject: [PATCH] [refactor] Split DemoWindows out of demos::DemoApp --- egui/benches/benchmark.rs | 12 +- egui/src/demos/app.rs | 296 +++----------------------------- egui/src/demos/color_test.rs | 98 ++++++----- egui/src/demos/demo_windows.rs | 284 ++++++++++++++++++++++++++++++ egui/src/demos/fractal_clock.rs | 8 +- egui/src/demos/mod.rs | 5 +- egui/src/lib.rs | 4 +- 7 files changed, 377 insertions(+), 330 deletions(-) create mode 100644 egui/src/demos/demo_windows.rs diff --git a/egui/benches/benchmark.rs b/egui/benches/benchmark.rs index 782b6aec..7ab1c251 100644 --- a/egui/benches/benchmark.rs +++ b/egui/benches/benchmark.rs @@ -8,12 +8,12 @@ pub fn criterion_benchmark(c: &mut Criterion) { { let mut ctx = egui::Context::new(); - let mut demo_app = egui::demos::DemoApp::default(); + let mut demo_windows = egui::demos::DemoWindows::default(); - c.bench_function("demo_app_minimal", |b| { + c.bench_function("demo_windows_minimal", |b| { b.iter(|| { let mut ui = ctx.begin_frame(raw_input.clone()); - demo_app.ui(&mut ui, &Default::default()); + demo_windows.ui(&mut ui, &Default::default(), None); ctx.end_frame() }) }); @@ -22,12 +22,12 @@ pub fn criterion_benchmark(c: &mut Criterion) { { let mut ctx = egui::Context::new(); ctx.memory().all_collpasing_are_open = true; // expand the demo window with everything - let mut demo_app = egui::demos::DemoApp::default(); + let mut demo_windows = egui::demos::DemoWindows::default(); - c.bench_function("demo_app_full", |b| { + c.bench_function("demo_windows_full", |b| { b.iter(|| { let mut ui = ctx.begin_frame(raw_input.clone()); - demo_app.ui(&mut ui, &Default::default()); + demo_windows.ui(&mut ui, &Default::default(), None); ctx.end_frame() }) }); diff --git a/egui/src/demos/app.rs b/egui/src/demos/app.rs index f7a671ac..d6b89fd3 100644 --- a/egui/src/demos/app.rs +++ b/egui/src/demos/app.rs @@ -1,6 +1,4 @@ -use std::sync::Arc; - -use crate::{app, color::*, containers::*, demos::*, paint::*, widgets::*, *}; +use crate::{app, demos, History, Ui}; // ---------------------------------------------------------------------------- @@ -88,7 +86,7 @@ impl FrameHistory { Does not include GPU usage, nor overhead for sending data to GPU.", ); - CollapsingHeader::new("CPU usage history") + crate::CollapsingHeader::new("CPU usage history") .default_open(false) .show(ui, |ui| { self.graph(ui); @@ -96,6 +94,8 @@ impl FrameHistory { } fn graph(&mut self, ui: &mut Ui) { + use crate::*; + let graph_top_cpu_usage = 0.010; ui.label("Egui CPU usage history"); @@ -161,162 +161,27 @@ impl FrameHistory { // ---------------------------------------------------------------------------- -/// 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 /// [`egui_glium`](https://crates.io/crates/egui_glium) and [`egui_web`](https://crates.io/crates/egui_web). -// TODO: split into `DemoWindows` and `app::DemoApp` #[derive(Default)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "serde", serde(default))] pub struct DemoApp { + demo_windows: demos::DemoWindows, + #[cfg_attr(feature = "serde", serde(skip))] // go back to `Reactive` mode each time we start run_mode: RunMode, - previous_web_location_hash: String, - open_windows: OpenWindows, - demo_window: DemoWindow, - fractal_clock: FractalClock, /// current slider value for current gui scale (backend demo only) pixels_per_point: Option, #[cfg_attr(feature = "serde", serde(skip))] frame_history: FrameHistory, - - #[cfg_attr(feature = "serde", serde(skip))] - color_test: ColorTest, - show_color_test: bool, } impl DemoApp { - /// Show the app ui (menu bar and windows). - 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 env.web_location_hash == "#clock" { - self.open_windows = OpenWindows { - fractal_clock: true, - ..OpenWindows::none() - }; - } - - self.previous_web_location_hash = env.web_location_hash.clone(); - } - - 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, env: &DemoEnvironment) { - let DemoApp { - open_windows, - demo_window, - fractal_clock, - .. - } = self; - - Window::new("Demo") - .open(&mut open_windows.demo) - .scroll(true) - .show(ctx, |ui| { - demo_window.ui(ui); - }); - - Window::new("Settings") - .open(&mut open_windows.settings) - .show(ctx, |ui| { - ctx.settings_ui(ui); - }); - - Window::new("Inspection") - .open(&mut open_windows.inspection) - .scroll(true) - .show(ctx, |ui| { - ctx.inspection_ui(ui); - }); - - Window::new("Memory") - .open(&mut open_windows.memory) - .resizable(false) - .show(ctx, |ui| { - ctx.memory_ui(ui); - }); - - fractal_clock.window( - ctx, - &mut open_windows.fractal_clock, - env.seconds_since_midnight, - ); - - self.resize_windows(ctx); - } - - fn resize_windows(&mut self, ctx: &Arc) { - let open = &mut self.open_windows.resize; - - Window::new("resizable") - .open(open) - .scroll(false) - .resizable(true) - .show(ctx, |ui| { - ui.label("scroll: NO"); - ui.label("resizable: YES"); - ui.label(LOREM_IPSUM); - }); - - Window::new("resizable + embedded scroll") - .open(open) - .scroll(false) - .resizable(true) - .default_height(300.0) - .show(ctx, |ui| { - ui.label("scroll: NO"); - ui.label("resizable: YES"); - ui.heading("We have a sub-region with scroll bar:"); - ScrollArea::auto_sized().show(ui, |ui| { - ui.label(LOREM_IPSUM_LONG); - ui.label(LOREM_IPSUM_LONG); - }); - // ui.heading("Some additional text here, that should also be visible"); // this works, but messes with the resizing a bit - }); - - Window::new("resizable + scroll") - .open(open) - .scroll(true) - .resizable(true) - .default_height(300.0) - .show(ctx, |ui| { - ui.label("scroll: YES"); - ui.label("resizable: YES"); - ui.label(LOREM_IPSUM_LONG); - }); - - Window::new("auto_sized") - .open(open) - .auto_sized() - .show(ctx, |ui| { - ui.label("This window will auto-size based on its contents."); - ui.heading("Resize this area:"); - Resize::default().show(ui, |ui| { - ui.label(LOREM_IPSUM); - }); - ui.heading("Resize the above area!"); - }); - } - - // TODO: give cpu_usage and web_info via `struct BackendInfo` fn backend_ui(&mut self, ui: &mut Ui, info: &app::BackendInfo) -> app::AppOutput { self.frame_history .on_new_frame(ui.input().time, info.cpu_usage); @@ -340,21 +205,15 @@ impl DemoApp { ui.separator(); - let mut output = app::AppOutput::default(); - output.pixels_per_point = self.pixels_per_point_ui(ui, info); - - ui.separator(); - - ui.separator(); self.frame_history.ui(ui); ui.separator(); - ui.checkbox( - &mut self.show_color_test, - "Show color blend test (debug backend painter)", - ); + + let mut output = app::AppOutput::default(); + output.pixels_per_point = self.pixels_per_point_ui(ui, info); if !is_web { + ui.separator(); output.quit |= ui.button("Quit").clicked; } @@ -368,7 +227,7 @@ impl DemoApp { .or_else(|| Some(ui.ctx().pixels_per_point())); if let Some(pixels_per_point) = &mut self.pixels_per_point { ui.add( - Slider::f32(pixels_per_point, 0.5..=5.0) + crate::Slider::f32(pixels_per_point, 0.5..=5.0) .logarithmic(true) .text("Scale (physical pixels per point)"), ); @@ -421,47 +280,30 @@ impl app::App for DemoApp { ) -> app::AppOutput { let mut output = app::AppOutput::default(); - Window::new("Backend") + crate::Window::new("Backend") .min_width(360.0) .scroll(false) .show(ui.ctx(), |ui| { output = self.backend_ui(ui, info); }); - let Self { - show_color_test, - color_test, - .. - } = self; - - // TODO: enable color test even without `tex_allocator` - if let Some(tex_allocator) = tex_allocator { - if *show_color_test { - let mut tex_loader = |size: (usize, usize), pixels: &[Srgba]| { - tex_allocator.new_texture_srgba_premultiplied(size, pixels) - }; - Window::new("Color Test") - .default_size(vec2(1024.0, 1024.0)) - .scroll(true) - .open(show_color_test) - .show(ui.ctx(), |ui| { - color_test.ui(ui, &mut tex_loader); - }); - } - } - let web_location_hash = info .web_info .as_ref() .map(|info| info.web_location_hash.clone()) .unwrap_or_default(); - - let environment = DemoEnvironment { - web_location_hash, - seconds_since_midnight: info.seconds_since_midnight, + let link = if web_location_hash == "clock" { + Some(demos::DemoLink::Clock) + } else { + None }; - self.ui(ui, &environment); + let demo_environment = demos::DemoEnvironment { + seconds_since_midnight: info.seconds_since_midnight, + link, + }; + + self.demo_windows.ui(ui, &demo_environment, tex_allocator); if self.run_mode == RunMode::Continuous { // Tell the backend to repaint as soon as possible @@ -476,97 +318,3 @@ impl app::App for DemoApp { app::set_value(storage, app::APP_KEY, self); } } - -// ---------------------------------------------------------------------------- - -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -struct OpenWindows { - demo: bool, - fractal_clock: bool, - - // egui stuff: - settings: bool, - inspection: bool, - memory: bool, - resize: bool, -} - -impl Default for OpenWindows { - fn default() -> Self { - Self { - demo: true, - ..OpenWindows::none() - } - } -} - -impl OpenWindows { - fn none() -> Self { - Self { - demo: false, - fractal_clock: false, - - settings: false, - inspection: false, - memory: false, - resize: false, - } - } -} - -fn show_menu_bar(ui: &mut Ui, windows: &mut OpenWindows, env: &DemoEnvironment) { - menu::bar(ui, |ui| { - menu::menu(ui, "File", |ui| { - if ui.button("Reorganize windows").clicked { - ui.ctx().memory().reset_areas(); - } - if ui - .button("Clear entire Egui memory") - .on_hover_text("Forget scroll, collapsibles etc") - .clicked - { - *ui.ctx().memory() = Default::default(); - } - }); - menu::menu(ui, "Windows", |ui| { - let OpenWindows { - demo, - fractal_clock, - settings, - inspection, - memory, - resize, - } = windows; - ui.checkbox(demo, "Demo"); - ui.checkbox(fractal_clock, "Fractal Clock"); - ui.separator(); - ui.checkbox(settings, "Settings"); - ui.checkbox(inspection, "Inspection"); - ui.checkbox(memory, "Memory"); - ui.checkbox(resize, "Resize examples"); - }); - menu::menu(ui, "About", |ui| { - ui.label("This is Egui"); - ui.add(Hyperlink::new("https://github.com/emilk/egui").text("Egui home page")); - }); - - 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(), - (time.rem_euclid(60.0 * 60.0) / 60.0).floor(), - (time.rem_euclid(60.0)).floor(), - (time.rem_euclid(1.0) * 100.0).floor() - ); - - ui.with_layout(Layout::horizontal(Align::Center).reverse(), |ui| { - if ui - .add(Button::new(time).text_style(TextStyle::Monospace)) - .clicked - { - windows.fractal_clock = !windows.fractal_clock; - } - }); - } - }); -} diff --git a/egui/src/demos/color_test.rs b/egui/src/demos/color_test.rs index 2391931a..5f614002 100644 --- a/egui/src/demos/color_test.rs +++ b/egui/src/demos/color_test.rs @@ -3,8 +3,6 @@ use crate::*; use color::*; use std::collections::HashMap; -pub type TextureLoader<'a> = dyn FnMut((usize, usize), &[crate::Srgba]) -> TextureId + 'a; - const GRADIENT_SIZE: Vec2 = vec2(256.0, 24.0); pub struct ColorTest { @@ -26,7 +24,11 @@ impl Default for ColorTest { } impl ColorTest { - pub fn ui(&mut self, ui: &mut Ui, tex_loader: &mut TextureLoader<'_>) { + pub fn ui( + &mut self, + ui: &mut Ui, + mut tex_allocator: &mut Option<&mut dyn app::TextureAllocator>, + ) { ui.label("This is made to test if your Egui painter backend is set up correctly"); ui.label("It is meant to ensure you do proper sRGBA decoding of both texture and vertex colors, and blend using premultiplied alpha."); ui.label("If everything is set up correctly, all groups of gradients will look uniform"); @@ -43,7 +45,7 @@ impl ColorTest { self.vertex_gradient(ui, "orange rgb(255, 165, 0) - vertex", WHITE, &g); self.tex_gradient( ui, - tex_loader, + tex_allocator, "orange rgb(255, 165, 0) - texture", WHITE, &g, @@ -70,38 +72,39 @@ impl ColorTest { { let g = Gradient::one_color(Srgba::from(tex_color * vertex_color)); self.vertex_gradient(ui, "Ground truth (vertices)", WHITE, &g); - self.tex_gradient(ui, tex_loader, "Ground truth (texture)", WHITE, &g); + self.tex_gradient(ui, tex_allocator, "Ground truth (texture)", WHITE, &g); + } + if let Some(tex_allocator) = &mut tex_allocator { + ui.horizontal(|ui| { + let g = Gradient::one_color(Srgba::from(tex_color)); + let tex = self.tex_mngr.get(*tex_allocator, &g); + let texel_offset = 0.5 / (g.0.len() as f32); + let uv = + Rect::from_min_max(pos2(texel_offset, 0.0), pos2(1.0 - texel_offset, 1.0)); + ui.add(Image::new(tex, GRADIENT_SIZE).tint(vertex_color).uv(uv)) + .on_hover_text(format!("A texture that is {} texels wide", g.0.len())); + ui.label("GPU result"); + }); } - ui.horizontal(|ui| { - let g = Gradient::one_color(Srgba::from(tex_color)); - let tex = self.tex_mngr.get(tex_loader, &g); - let texel_offset = 0.5 / (g.0.len() as f32); - let uv = Rect::from_min_max(pos2(texel_offset, 0.0), pos2(1.0 - texel_offset, 1.0)); - ui.add(Image::new(tex, GRADIENT_SIZE).tint(vertex_color).uv(uv)) - .on_hover_text(format!("A texture that is {} texels wide", g.0.len())); - ui.label("GPU result"); - }); }); ui.separator(); - ui.separator(); - // TODO: test color multiplication (image tint), // to make sure vertex and texture color multiplication is done in linear space. - self.show_gradients(ui, tex_loader, WHITE, (RED, GREEN)); + self.show_gradients(ui, tex_allocator, WHITE, (RED, GREEN)); if self.srgb { ui.label("Notice the darkening in the center of the naive sRGB interpolation."); } ui.separator(); - self.show_gradients(ui, tex_loader, RED, (TRANSPARENT, GREEN)); + self.show_gradients(ui, tex_allocator, RED, (TRANSPARENT, GREEN)); ui.separator(); - self.show_gradients(ui, tex_loader, WHITE, (TRANSPARENT, GREEN)); + self.show_gradients(ui, tex_allocator, WHITE, (TRANSPARENT, GREEN)); if self.srgb { ui.label( "Notice how the linear blend stays green while the naive sRGBA interpolation looks gray in the middle.", @@ -112,13 +115,18 @@ impl ColorTest { // TODO: another ground truth where we do the alpha-blending against the background also. // TODO: exactly the same thing, but with vertex colors (no textures) - self.show_gradients(ui, tex_loader, WHITE, (TRANSPARENT, BLACK)); + self.show_gradients(ui, tex_allocator, WHITE, (TRANSPARENT, BLACK)); ui.separator(); - self.show_gradients(ui, tex_loader, BLACK, (TRANSPARENT, WHITE)); + self.show_gradients(ui, tex_allocator, BLACK, (TRANSPARENT, WHITE)); ui.separator(); ui.label("Additive blending: add more and more blue to the red background:"); - self.show_gradients(ui, tex_loader, RED, (TRANSPARENT, Srgba::new(0, 0, 255, 0))); + self.show_gradients( + ui, + tex_allocator, + RED, + (TRANSPARENT, Srgba::new(0, 0, 255, 0)), + ); ui.separator(); } @@ -126,7 +134,7 @@ impl ColorTest { fn show_gradients( &mut self, ui: &mut Ui, - tex_loader: &mut TextureLoader<'_>, + tex_allocator: &mut Option<&mut dyn app::TextureAllocator>, bg_fill: Srgba, (left, right): (Srgba, Srgba), ) { @@ -151,7 +159,7 @@ impl ColorTest { self.vertex_gradient(ui, "Ground Truth (CPU gradient) - vertices", bg_fill, &g); self.tex_gradient( ui, - tex_loader, + tex_allocator, "Ground Truth (CPU gradient) - texture", bg_fill, &g, @@ -166,7 +174,7 @@ impl ColorTest { ); self.tex_gradient( ui, - tex_loader, + tex_allocator, "Ground Truth (CPU gradient, CPU blending) - texture", bg_fill, &g, @@ -175,7 +183,7 @@ impl ColorTest { self.vertex_gradient(ui, "CPU gradient, GPU blending - vertices", bg_fill, &g); self.tex_gradient( ui, - tex_loader, + tex_allocator, "CPU gradient, GPU blending - texture", bg_fill, &g, @@ -191,7 +199,7 @@ impl ColorTest { ); self.tex_gradient( ui, - tex_loader, + tex_allocator, "Texture of width 2 (test texture sampler)", bg_fill, &g, @@ -208,7 +216,7 @@ impl ColorTest { ); self.tex_gradient( ui, - tex_loader, + tex_allocator, "Naive sRGBA interpolation (WRONG)", bg_fill, &g, @@ -220,7 +228,7 @@ impl ColorTest { fn tex_gradient( &mut self, ui: &mut Ui, - tex_loader: &mut TextureLoader<'_>, + tex_allocator: &mut Option<&mut dyn app::TextureAllocator>, label: &str, bg_fill: Srgba, gradient: &Gradient, @@ -228,17 +236,19 @@ impl ColorTest { if !self.texture_gradients { return; } - ui.horizontal(|ui| { - let tex = self.tex_mngr.get(tex_loader, gradient); - let texel_offset = 0.5 / (gradient.0.len() as f32); - let uv = Rect::from_min_max(pos2(texel_offset, 0.0), pos2(1.0 - texel_offset, 1.0)); - ui.add(Image::new(tex, GRADIENT_SIZE).bg_fill(bg_fill).uv(uv)) - .on_hover_text(format!( - "A texture that is {} texels wide", - gradient.0.len() - )); - ui.label(label); - }); + if let Some(tex_allocator) = tex_allocator { + ui.horizontal(|ui| { + let tex = self.tex_mngr.get(*tex_allocator, gradient); + let texel_offset = 0.5 / (gradient.0.len() as f32); + let uv = Rect::from_min_max(pos2(texel_offset, 0.0), pos2(1.0 - texel_offset, 1.0)); + ui.add(Image::new(tex, GRADIENT_SIZE).bg_fill(bg_fill).uv(uv)) + .on_hover_text(format!( + "A texture that is {} texels wide", + gradient.0.len() + )); + ui.label(label); + }); + } } fn vertex_gradient(&mut self, ui: &mut Ui, label: &str, bg_fill: Srgba, gradient: &Gradient) { @@ -348,12 +358,16 @@ impl Gradient { struct TextureManager(HashMap); impl TextureManager { - fn get(&mut self, tex_loader: &mut TextureLoader<'_>, gradient: &Gradient) -> TextureId { + fn get( + &mut self, + tex_allocator: &mut dyn app::TextureAllocator, + gradient: &Gradient, + ) -> TextureId { *self.0.entry(gradient.clone()).or_insert_with(|| { let pixels = gradient.to_pixel_row(); let width = pixels.len(); let height = 1; - tex_loader((width, height), &pixels) + tex_allocator.new_texture_srgba_premultiplied((width, height), &pixels) }) } } diff --git a/egui/src/demos/demo_windows.rs b/egui/src/demos/demo_windows.rs new file mode 100644 index 00000000..994b196a --- /dev/null +++ b/egui/src/demos/demo_windows.rs @@ -0,0 +1,284 @@ +use std::sync::Arc; + +use crate::{app, demos, Context, Resize, ScrollArea, Ui, Window}; + +// ---------------------------------------------------------------------------- + +/// Link to show a specific part of the demo app. +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum DemoLink { + Clock, +} + +/// Special input to the demo-app. +#[derive(Default)] +pub struct DemoEnvironment { + /// Local time. Used for the clock in the demo app. + pub seconds_since_midnight: Option, + + /// Set to `Some` to open a specific part of the demo app. + pub link: Option, +} + +// ---------------------------------------------------------------------------- + +/// A menu bar in which you can select different demo windows to show. +#[derive(Default)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[cfg_attr(feature = "serde", serde(default))] +pub struct DemoWindows { + open_windows: OpenWindows, + + demo_window: demos::DemoWindow, + + #[cfg_attr(feature = "serde", serde(skip))] + color_test: demos::ColorTest, + + fractal_clock: demos::FractalClock, + + #[cfg_attr(feature = "serde", serde(skip))] + previous_link: Option, +} + +impl DemoWindows { + /// Show the app ui (menu bar and windows). + pub fn ui( + &mut self, + ui: &mut Ui, + env: &DemoEnvironment, + tex_allocator: Option<&mut dyn app::TextureAllocator>, + ) { + if self.previous_link != env.link { + match env.link { + None => {} + Some(DemoLink::Clock) => { + self.open_windows = OpenWindows { + fractal_clock: true, + ..OpenWindows::none() + }; + } + } + self.previous_link = env.link; + } + + show_menu_bar(ui, &mut self.open_windows, env.seconds_since_midnight); + self.windows(ui.ctx(), env, tex_allocator); + } + + /// Show the open windows. + fn windows( + &mut self, + ctx: &Arc, + env: &DemoEnvironment, + mut tex_allocator: Option<&mut dyn app::TextureAllocator>, + ) { + let Self { + open_windows, + demo_window, + color_test, + fractal_clock, + .. + } = self; + + Window::new("Demo") + .open(&mut open_windows.demo) + .scroll(true) + .show(ctx, |ui| { + demo_window.ui(ui); + }); + + Window::new("Settings") + .open(&mut open_windows.settings) + .show(ctx, |ui| { + ctx.settings_ui(ui); + }); + + Window::new("Inspection") + .open(&mut open_windows.inspection) + .scroll(true) + .show(ctx, |ui| { + ctx.inspection_ui(ui); + }); + + Window::new("Memory") + .open(&mut open_windows.memory) + .resizable(false) + .show(ctx, |ui| { + ctx.memory_ui(ui); + }); + + Window::new("Color Test") + .default_size([800.0, 1024.0]) + .scroll(true) + .open(&mut open_windows.color_test) + .show(ctx, |ui| { + color_test.ui(ui, &mut tex_allocator); + }); + + fractal_clock.window( + ctx, + &mut open_windows.fractal_clock, + env.seconds_since_midnight, + ); + + self.resize_windows(ctx); + } + + fn resize_windows(&mut self, ctx: &Arc) { + let open = &mut self.open_windows.resize; + + Window::new("resizable") + .open(open) + .scroll(false) + .resizable(true) + .show(ctx, |ui| { + ui.label("scroll: NO"); + ui.label("resizable: YES"); + ui.label(demos::LOREM_IPSUM); + }); + + Window::new("resizable + embedded scroll") + .open(open) + .scroll(false) + .resizable(true) + .default_height(300.0) + .show(ctx, |ui| { + ui.label("scroll: NO"); + ui.label("resizable: YES"); + ui.heading("We have a sub-region with scroll bar:"); + ScrollArea::auto_sized().show(ui, |ui| { + ui.label(demos::LOREM_IPSUM_LONG); + ui.label(demos::LOREM_IPSUM_LONG); + }); + // ui.heading("Some additional text here, that should also be visible"); // this works, but messes with the resizing a bit + }); + + Window::new("resizable + scroll") + .open(open) + .scroll(true) + .resizable(true) + .default_height(300.0) + .show(ctx, |ui| { + ui.label("scroll: YES"); + ui.label("resizable: YES"); + ui.label(demos::LOREM_IPSUM_LONG); + }); + + Window::new("auto_sized") + .open(open) + .auto_sized() + .show(ctx, |ui| { + ui.label("This window will auto-size based on its contents."); + ui.heading("Resize this area:"); + Resize::default().show(ui, |ui| { + ui.label(demos::LOREM_IPSUM); + }); + ui.heading("Resize the above area!"); + }); + } +} + +// ---------------------------------------------------------------------------- + +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +struct OpenWindows { + demo: bool, + fractal_clock: bool, + + // egui stuff: + settings: bool, + inspection: bool, + memory: bool, + resize: bool, + + // debug stuff: + color_test: bool, +} + +impl Default for OpenWindows { + fn default() -> Self { + Self { + demo: true, + ..OpenWindows::none() + } + } +} + +impl OpenWindows { + fn none() -> Self { + Self { + demo: false, + fractal_clock: false, + + settings: false, + inspection: false, + memory: false, + resize: false, + + color_test: false, + } + } +} + +fn show_menu_bar(ui: &mut Ui, windows: &mut OpenWindows, seconds_since_midnight: Option) { + use crate::*; + + menu::bar(ui, |ui| { + menu::menu(ui, "File", |ui| { + if ui.button("Reorganize windows").clicked { + ui.ctx().memory().reset_areas(); + } + if ui + .button("Clear entire Egui memory") + .on_hover_text("Forget scroll, collapsibles etc") + .clicked + { + *ui.ctx().memory() = Default::default(); + } + }); + menu::menu(ui, "Windows", |ui| { + let OpenWindows { + demo, + fractal_clock, + settings, + inspection, + memory, + resize, + color_test, + } = windows; + ui.checkbox(demo, "Demo"); + ui.checkbox(fractal_clock, "Fractal Clock"); + ui.separator(); + ui.checkbox(settings, "Settings"); + ui.checkbox(inspection, "Inspection"); + ui.checkbox(memory, "Memory"); + ui.checkbox(resize, "Resize examples"); + ui.separator(); + ui.checkbox(color_test, "Color test") + .on_hover_text("For testing the integrations painter"); + }); + menu::menu(ui, "About", |ui| { + ui.label("This is Egui"); + ui.add(Hyperlink::new("https://github.com/emilk/egui").text("Egui home page")); + }); + + if let Some(time) = seconds_since_midnight { + let time = format!( + "{:02}:{:02}:{:02}.{:02}", + (time % (24.0 * 60.0 * 60.0) / 3600.0).floor(), + (time % (60.0 * 60.0) / 60.0).floor(), + (time % 60.0).floor(), + (time % 1.0 * 100.0).floor() + ); + + ui.with_layout(Layout::horizontal(Align::Center).reverse(), |ui| { + if ui + .add(Button::new(time).text_style(TextStyle::Monospace)) + .clicked + { + windows.fractal_clock = !windows.fractal_clock; + } + }); + } + }); +} diff --git a/egui/src/demos/fractal_clock.rs b/egui/src/demos/fractal_clock.rs index c4a9119f..a23411ff 100644 --- a/egui/src/demos/fractal_clock.rs +++ b/egui/src/demos/fractal_clock.rs @@ -71,10 +71,10 @@ impl FractalClock { 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(), - (self.time.rem_euclid(60.0 * 60.0) / 60.0).floor(), - (self.time.rem_euclid(60.0)).floor(), - (self.time.rem_euclid(1.0) * 1000.0).floor() + (self.time % (24.0 * 60.0 * 60.0) / 3600.0).floor(), + (self.time % (60.0 * 60.0) / 60.0).floor(), + (self.time % 60.0).floor(), + (self.time % 1.0 * 100.0).floor() )); } else { ui.add(label!( diff --git a/egui/src/demos/mod.rs b/egui/src/demos/mod.rs index 4c41cb90..8b025995 100644 --- a/egui/src/demos/mod.rs +++ b/egui/src/demos/mod.rs @@ -4,14 +4,15 @@ mod app; mod color_test; pub mod demo_window; +mod demo_windows; mod fractal_clock; mod sliders; pub mod toggle_switch; mod widgets; pub use { - app::*, color_test::ColorTest, demo_window::DemoWindow, fractal_clock::FractalClock, - sliders::Sliders, widgets::Widgets, + app::*, color_test::ColorTest, demo_window::DemoWindow, demo_windows::*, + fractal_clock::FractalClock, sliders::Sliders, widgets::Widgets, }; pub const LOREM_IPSUM: &str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; diff --git a/egui/src/lib.rs b/egui/src/lib.rs index 7dd31e89..3374ffd1 100644 --- a/egui/src/lib.rs +++ b/egui/src/lib.rs @@ -89,7 +89,7 @@ pub use { #[test] pub fn text_egui_e2e() { - let mut demo_app = crate::demos::DemoApp::default(); + let mut demo_windows = crate::demos::DemoWindows::default(); let mut ctx = crate::Context::new(); let raw_input = crate::RawInput { screen_size: crate::vec2(1280.0, 1024.0), @@ -99,7 +99,7 @@ pub fn text_egui_e2e() { const NUM_FRAMES: usize = 5; for _ in 0..NUM_FRAMES { let mut ui = ctx.begin_frame(raw_input.clone()); - demo_app.ui(&mut ui, &Default::default()); + demo_windows.ui(&mut ui, &Default::default(), None); let (_output, paint_jobs) = ctx.end_frame(); assert!(!paint_jobs.is_empty()); }