[demo] Move Fractal Clock to WrapApp

This commit is contained in:
Emil Ernerfeldt 2021-01-01 21:27:10 +01:00
parent b1022d01c1
commit 4848c171eb
10 changed files with 100 additions and 140 deletions

View file

@ -137,11 +137,20 @@ impl TopPanel {
/// });
/// ```
#[derive(Default)]
pub struct CentralPanel {}
pub struct CentralPanel {
frame: Option<Frame>,
}
impl CentralPanel {
pub fn frame(mut self, frame: Frame) -> Self {
self.frame = Some(frame);
self
}
}
impl CentralPanel {
pub fn show<R>(self, ctx: &CtxRef, add_contents: impl FnOnce(&mut Ui) -> R) -> (R, Response) {
let Self {} = self;
let Self { frame } = self;
let panel_rect = ctx.available_rect();
@ -151,7 +160,7 @@ impl CentralPanel {
let clip_rect = ctx.input().screen_rect();
let mut panel_ui = Ui::new(ctx.clone(), layer_id, id, panel_rect, clip_rect);
let frame = Frame::central_panel(&ctx.style());
let frame = frame.unwrap_or_else(|| Frame::central_panel(&ctx.style()));
let r = frame.show(&mut panel_ui, |ui| {
let r = add_contents(ui);
ui.expand_to_include_rect(ui.max_rect()); // Use it all

View file

@ -10,7 +10,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("demo_windows_minimal", |b| {
b.iter(|| {
ctx.begin_frame(raw_input.clone());
demo_windows.ui(&ctx, &Default::default(), &mut None, |_ui| {});
demo_windows.ui(&ctx, &mut None, |_ui| {});
ctx.end_frame()
})
});
@ -24,7 +24,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("demo_windows_full", |b| {
b.iter(|| {
ctx.begin_frame(raw_input.clone());
demo_windows.ui(&ctx, &Default::default(), &mut None, |_ui| {});
demo_windows.ui(&ctx, &mut None, |_ui| {});
ctx.end_frame()
})
});
@ -35,7 +35,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
ctx.memory().all_collpasing_are_open = true; // expand the demo window with everything
let mut demo_windows = egui_demo_lib::DemoWindows::default();
ctx.begin_frame(raw_input.clone());
demo_windows.ui(&ctx, &Default::default(), &mut None, |_ui| {});
demo_windows.ui(&ctx, &mut None, |_ui| {});
let (_, paint_commands) = ctx.end_frame();
c.bench_function("tessellate", |b| {

View file

@ -297,24 +297,6 @@ impl epi::App for DemoApp {
self.frame_history
.on_new_frame(ctx.input().time, frame.info().cpu_usage);
let web_location_hash = frame
.info()
.web_info
.as_ref()
.map(|info| info.web_location_hash.clone())
.unwrap_or_default();
let link = if web_location_hash == "clock" {
Some(super::DemoLink::Clock)
} else {
None
};
let demo_environment = super::DemoEnvironment {
seconds_since_midnight: frame.info().seconds_since_midnight,
link,
};
let mean_frame_time = self.frame_history.mean_frame_time();
let Self {
@ -323,7 +305,7 @@ impl epi::App for DemoApp {
..
} = self;
demo_windows.ui(ctx, &demo_environment, frame.tex_allocator(), |ui| {
demo_windows.ui(ctx, frame.tex_allocator(), |ui| {
ui.separator();
ui.checkbox(backend_window_open, "💻 Backend");

View file

@ -2,24 +2,6 @@ use egui::{CtxRef, 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<f64>,
/// Set to `Some` to open a specific part of the demo app.
pub link: Option<DemoLink>,
}
// ----------------------------------------------------------------------------
#[derive(serde::Deserialize, serde::Serialize)]
#[serde(default)]
struct Demos {
@ -67,13 +49,8 @@ pub struct DemoWindows {
#[serde(skip)]
color_test: super::ColorTest,
fractal_clock: super::FractalClock,
/// open, title, view
demos: Demos,
#[serde(skip)]
previous_link: Option<DemoLink>,
}
impl DemoWindows {
@ -82,26 +59,11 @@ impl DemoWindows {
pub fn ui(
&mut self,
ctx: &CtxRef,
env: &DemoEnvironment,
tex_allocator: &mut Option<&mut dyn epi::TextureAllocator>,
sidebar_ui: impl FnOnce(&mut Ui),
) {
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;
}
egui::SidePanel::left("side_panel", 190.0).show(ctx, |ui| {
ui.heading("✒ Egui Demo");
egui::warn_if_debug_build(ui);
ui.separator();
@ -132,24 +94,22 @@ impl DemoWindows {
});
egui::TopPanel::top("menu_bar").show(ctx, |ui| {
show_menu_bar(ui, &mut self.open_windows, env.seconds_since_midnight);
show_menu_bar(ui);
});
self.windows(ctx, env, tex_allocator);
self.windows(ctx, tex_allocator);
}
/// Show the open windows.
fn windows(
&mut self,
ctx: &CtxRef,
env: &DemoEnvironment,
tex_allocator: &mut Option<&mut dyn epi::TextureAllocator>,
) {
let Self {
open_windows,
demo_window,
color_test,
fractal_clock,
demos,
..
} = self;
@ -191,12 +151,6 @@ impl DemoWindows {
demos.show(ctx);
fractal_clock.window(
ctx,
&mut open_windows.fractal_clock,
env.seconds_since_midnight,
);
self.resize_windows(ctx);
}
@ -259,7 +213,6 @@ impl DemoWindows {
#[derive(serde::Deserialize, serde::Serialize)]
struct OpenWindows {
demo: bool,
fractal_clock: bool,
// egui stuff:
settings: bool,
@ -284,7 +237,6 @@ impl OpenWindows {
fn none() -> Self {
Self {
demo: false,
fractal_clock: false,
settings: false,
inspection: false,
@ -298,7 +250,6 @@ impl OpenWindows {
fn checkboxes(&mut self, ui: &mut Ui) {
let Self {
demo,
fractal_clock,
settings,
inspection,
memory,
@ -317,11 +268,10 @@ impl OpenWindows {
.on_hover_text("For testing the integrations painter");
ui.separator();
ui.label("Misc:");
ui.checkbox(fractal_clock, "🕑 Fractal Clock");
}
}
fn show_menu_bar(ui: &mut Ui, windows: &mut OpenWindows, seconds_since_midnight: Option<f64>) {
fn show_menu_bar(ui: &mut Ui) {
use egui::*;
menu::bar(ui, |ui| {
@ -337,24 +287,5 @@ fn show_menu_bar(ui: &mut Ui, windows: &mut OpenWindows, seconds_since_midnight:
*ui.ctx().memory() = Default::default();
}
});
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::right_to_left(), |ui| {
if ui
.add(Button::new(time).text_style(TextStyle::Monospace))
.clicked
{
windows.fractal_clock = !windows.fractal_clock;
}
});
}
});
}

View file

@ -13,7 +13,6 @@ mod drag_and_drop;
mod font_book;
pub mod font_contents_emoji;
pub mod font_contents_ubuntu;
mod fractal_clock;
mod painting;
mod scrolls;
mod sliders;
@ -23,8 +22,8 @@ mod widgets;
pub use {
app::*, color_test::ColorTest, dancing_strings::DancingStrings, demo_window::DemoWindow,
demo_windows::*, drag_and_drop::*, font_book::FontBook, fractal_clock::FractalClock,
painting::Painting, scrolls::Scrolls, sliders::Sliders, tests::Tests, widgets::Widgets,
demo_windows::*, drag_and_drop::*, font_book::FontBook, painting::Painting, scrolls::Scrolls,
sliders::Sliders, tests::Tests, widgets::Widgets,
};
// ----------------------------------------------------------------------------

View file

@ -29,17 +29,19 @@ impl Default for FractalClock {
}
}
impl FractalClock {
pub fn window(&mut self, ctx: &CtxRef, open: &mut bool, seconds_since_midnight: Option<f64>) {
Window::new("🕑 Fractal Clock")
.open(open)
.default_size(vec2(512.0, 512.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, seconds_since_midnight));
impl epi::App for FractalClock {
fn name(&self) -> &str {
"🕑 Fractal Clock"
}
fn update(&mut self, ctx: &egui::CtxRef, frame: &mut epi::Frame<'_>) {
egui::CentralPanel::default()
.frame(Frame::dark_canvas(&ctx.style()))
.show(ctx, |ui| self.ui(ui, frame.info().seconds_since_midnight));
}
}
impl FractalClock {
pub fn ui(&mut self, ui: &mut Ui, seconds_since_midnight: Option<f64>) {
if !self.paused {
self.time = seconds_since_midnight.unwrap_or_else(|| ui.input().time);

View file

@ -1,7 +1,9 @@
mod demo;
mod fractal_clock;
mod http_app;
pub use demo::DemoApp;
pub use fractal_clock::FractalClock;
pub use http_app::HttpApp;
pub use demo::DemoWindows; // used for tests

View file

@ -96,7 +96,7 @@ fn test_egui_e2e() {
const NUM_FRAMES: usize = 5;
for _ in 0..NUM_FRAMES {
ctx.begin_frame(raw_input.clone());
demo_windows.ui(&ctx, &Default::default(), &mut None, |_ui| {});
demo_windows.ui(&ctx, &mut None, |_ui| {});
let (_output, paint_commands) = ctx.end_frame();
let paint_jobs = ctx.tessellate(paint_commands);
assert!(!paint_jobs.is_empty());

View file

@ -2,10 +2,27 @@
#[derive(Default, serde::Deserialize, serde::Serialize)]
#[serde(default)]
pub struct WrapApp {
selectable_demo_name: String,
selected_anchor: String,
apps: Apps,
}
#[derive(Default, serde::Deserialize, serde::Serialize)]
#[serde(default)]
pub struct Apps {
demo: crate::apps::DemoApp,
http: crate::apps::HttpApp,
clock: crate::apps::FractalClock,
}
impl Apps {
fn iter_mut(&mut self) -> impl Iterator<Item = (&str, &mut dyn epi::App)> {
vec![
("demo", &mut self.demo as &mut dyn epi::App),
("http", &mut self.http as &mut dyn epi::App),
("clock", &mut self.clock as &mut dyn epi::App),
]
.into_iter()
}
}
impl epi::App for WrapApp {
@ -22,46 +39,63 @@ impl epi::App for WrapApp {
}
fn update(&mut self, ctx: &egui::CtxRef, frame: &mut epi::Frame<'_>) {
let web_location_hash = frame
.info()
.web_info
.as_ref()
.map(|info| info.web_location_hash.clone())
.unwrap_or_default();
if let Some(web_info) = frame.info().web_info.as_ref() {
if let Some(anchor) = web_info.web_location_hash.strip_prefix("#") {
self.selected_anchor = anchor.to_owned();
}
}
if web_location_hash == "#clock" {
// TODO
} else if web_location_hash == "#http" {
self.selectable_demo_name = self.http.name().to_owned();
if self.selected_anchor.is_empty() {
self.selected_anchor = self.apps.iter_mut().next().unwrap().0.to_owned();
}
egui::TopPanel::top("wrap_app").show(ctx, |ui| {
ui.horizontal(|ui| {
ui.label(format!("web_location_hash: {:?}", web_location_hash));
ui.label("Demo Apps:");
ui.selectable_value(
&mut self.selectable_demo_name,
self.demo.name().to_owned(),
self.demo.name(),
);
ui.selectable_value(
&mut self.selectable_demo_name,
self.http.name().to_owned(),
self.http.name(),
);
// A menu-bar is a horizontal layout with some special styles applied.
egui::menu::bar(ui, |ui| {
for (anchor, app) in self.apps.iter_mut() {
if ui
.selectable_label(self.selected_anchor == anchor, app.name())
.clicked
{
self.selected_anchor = anchor.to_owned();
if frame.is_web() {
ui.output().open_url = Some(format!("#{}", anchor));
}
}
}
ui.with_layout(egui::Layout::right_to_left(), |ui| {
if let Some(seconds_since_midnight) = frame.info().seconds_since_midnight {
if clock_button(ui, seconds_since_midnight).clicked {
self.selected_anchor = "clock".to_owned();
if frame.is_web() {
ui.output().open_url = Some("#clock".to_owned());
}
}
}
egui::warn_if_debug_build(ui);
});
});
});
if self.selectable_demo_name == self.demo.name() {
self.demo.update(ctx, frame);
} else if self.selectable_demo_name == self.http.name() {
self.http.update(ctx, frame);
} else {
self.selectable_demo_name = self.demo.name().to_owned();
for (anchor, app) in self.apps.iter_mut() {
if anchor == self.selected_anchor {
app.update(ctx, frame);
}
}
}
}
fn clock_button(ui: &mut egui::Ui, seconds_since_midnight: f64) -> egui::Response {
let 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.add(egui::Button::new(time).text_style(egui::TextStyle::Monospace))
}

View file

@ -159,6 +159,7 @@ impl<'a> Frame<'a> {
pub struct WebInfo {
/// e.g. "#fragment" part of "www.example.com/index.html#fragment".
/// Note that the leading `#` is included in the string.
/// Also known as "hash-link" or "anchor".
pub web_location_hash: String,
}