1
0
mirror of https://github.com/emilk/egui.git synced 2026-09-02 06:40:06 -04:00

[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

@@ -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

@@ -1,202 +0,0 @@
use egui::{containers::*, widgets::*, *};
use std::f32::consts::TAU;
#[derive(serde::Deserialize, serde::Serialize)]
#[serde(default)]
pub struct FractalClock {
paused: bool,
time: f64,
zoom: f32,
start_line_width: f32,
depth: usize,
length_factor: f32,
luminance_factor: f32,
width_factor: f32,
}
impl Default for FractalClock {
fn default() -> Self {
Self {
paused: false,
time: 0.0,
zoom: 0.25,
start_line_width: 2.5,
depth: 9,
length_factor: 0.8,
luminance_factor: 0.8,
width_factor: 0.9,
}
}
}
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));
}
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);
ui.ctx().request_repaint();
}
let painter = Painter::new(
ui.ctx().clone(),
ui.layer_id(),
ui.available_rect_before_wrap_finite(),
);
self.paint(&painter);
// Make sure we allocate what we used (everything)
ui.expand_to_include_rect(painter.clip_rect());
Frame::popup(ui.style())
.fill(Rgba::luminance_alpha(0.02, 0.5).into())
.stroke(Stroke::none())
.show(ui, |ui| {
ui.set_max_width(270.0);
CollapsingHeader::new("Settings")
.show(ui, |ui| self.options_ui(ui, seconds_since_midnight));
});
}
fn options_ui(&mut self, ui: &mut Ui, seconds_since_midnight: Option<f64>) {
if seconds_since_midnight.is_some() {
ui.label(format!(
"Local time: {:02}:{:02}:{:02}.{:03}",
(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.label("The fractal_clock clock is not showing the correct time");
};
ui.checkbox(&mut self.paused, "Paused");
ui.add(Slider::f32(&mut self.zoom, 0.0..=1.0).text("zoom"));
ui.add(Slider::f32(&mut self.start_line_width, 0.0..=5.0).text("Start line width"));
ui.add(Slider::usize(&mut self.depth, 0..=14).text("depth"));
ui.add(Slider::f32(&mut self.length_factor, 0.0..=1.0).text("length factor"));
ui.add(Slider::f32(&mut self.luminance_factor, 0.0..=1.0).text("luminance factor"));
ui.add(Slider::f32(&mut self.width_factor, 0.0..=1.0).text("width factor"));
if ui.button("Reset").clicked {
*self = Default::default();
}
ui.add(
Hyperlink::new("http://www.dqd.com/~mayoff/programs/FractalClock/")
.text("Inspired by a screensaver by Rob Mayoff"),
);
}
fn paint(&mut self, painter: &Painter) {
let rect = painter.clip_rect();
struct Hand {
length: f32,
angle: f32,
vec: Vec2,
}
impl Hand {
fn from_length_angle(length: f32, angle: f32) -> Self {
Self {
length,
angle,
vec: length * Vec2::angled(angle),
}
}
}
let angle_from_period =
|period| TAU * (self.time.rem_euclid(period) / period) as f32 - TAU / 4.0;
let hands = [
// Second hand:
Hand::from_length_angle(self.length_factor, angle_from_period(60.0)),
// Minute hand:
Hand::from_length_angle(self.length_factor, angle_from_period(60.0 * 60.0)),
// Hour hand:
Hand::from_length_angle(0.5, angle_from_period(12.0 * 60.0 * 60.0)),
];
let scale = self.zoom * rect.width().min(rect.height());
let paint_line = |points: [Pos2; 2], color: Srgba, width: f32| {
let line = [
rect.center() + scale * points[0].to_vec2(),
rect.center() + scale * points[1].to_vec2(),
];
painter.line_segment([line[0], line[1]], (width, color));
};
let hand_rotations = [
hands[0].angle - hands[2].angle + TAU / 2.0,
hands[1].angle - hands[2].angle + TAU / 2.0,
];
let hand_rotors = [
hands[0].length * Rot2::from_angle(hand_rotations[0]),
hands[1].length * Rot2::from_angle(hand_rotations[1]),
];
#[derive(Clone, Copy)]
struct Node {
pos: Pos2,
dir: Vec2,
}
let mut nodes = Vec::new();
let mut width = self.start_line_width;
for (i, hand) in hands.iter().enumerate() {
let center = pos2(0.0, 0.0);
let end = center + hand.vec;
paint_line([center, end], Srgba::additive_luminance(255), width);
if i < 2 {
nodes.push(Node {
pos: end,
dir: hand.vec,
});
}
}
let mut luminance = 0.7; // Start dimmer than main hands
let mut new_nodes = Vec::new();
for _ in 0..self.depth {
new_nodes.clear();
new_nodes.reserve(nodes.len() * 2);
luminance *= self.luminance_factor;
width *= self.width_factor;
let luminance_u8 = (255.0 * luminance).round() as u8;
for &rotor in &hand_rotors {
for a in &nodes {
let new_dir = rotor * a.dir;
let b = Node {
pos: a.pos + new_dir,
dir: new_dir,
};
paint_line(
[a.pos, b.pos],
Srgba::additive_luminance(luminance_u8),
width,
);
new_nodes.push(b);
}
}
std::mem::swap(&mut nodes, &mut new_nodes);
}
}
}

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,
};
// ----------------------------------------------------------------------------