Split out the Egui demo code to new crate egui_demo_lib

This commit is contained in:
Emil Ernerfeldt 2020-12-29 13:40:11 +01:00
parent 650450bc3a
commit 6953dc7d5d
31 changed files with 282 additions and 204 deletions

View file

@ -52,7 +52,7 @@ jobs:
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
command: test command: test
args: -p egui # Only test egui due to weird build issues with the others args: -p egui -p egui_demo_lib # TODO: fix weird build issues with the others
fmt: fmt:
name: Rustfmt name: Rustfmt

10
Cargo.lock generated
View file

@ -626,7 +626,6 @@ version = "0.6.0"
dependencies = [ dependencies = [
"ahash", "ahash",
"atomic_refcell", "atomic_refcell",
"criterion",
"parking_lot", "parking_lot",
"rusttype", "rusttype",
"serde", "serde",
@ -638,6 +637,7 @@ name = "egui_demo"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"egui", "egui",
"egui_demo_lib",
"egui_glium", "egui_glium",
"egui_web", "egui_web",
"js-sys", "js-sys",
@ -645,6 +645,14 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "egui_demo_lib"
version = "0.6.0"
dependencies = [
"criterion",
"egui",
]
[[package]] [[package]]
name = "egui_glium" name = "egui_glium"
version = "0.6.0" version = "0.6.0"

View file

@ -1,5 +1,6 @@
[workspace] [workspace]
members = [ members = [
"egui_demo_lib",
"egui_demo", "egui_demo",
"egui_glium", "egui_glium",
"egui_web", "egui_web",

View file

@ -7,7 +7,6 @@ CARGO_INCREMENTAL=0 cargo clippy --workspace --all-targets --all-features -- -D
cargo test --workspace --all-targets --all-features cargo test --workspace --all-targets --all-features
cargo test --workspace --doc cargo test --workspace --doc
cargo check -p egui --lib --target wasm32-unknown-unknown
cargo check -p egui_web --lib --target wasm32-unknown-unknown cargo check -p egui_web --lib --target wasm32-unknown-unknown
cargo check -p egui_demo --lib --target wasm32-unknown-unknown cargo check -p egui_demo --lib --target wasm32-unknown-unknown
cargo check -p example_web --lib --target wasm32-unknown-unknown cargo check -p example_web --lib --target wasm32-unknown-unknown

View file

@ -26,9 +26,6 @@ rusttype = "0.9"
serde = { version = "1", features = ["derive"], optional = true } serde = { version = "1", features = ["derive"], optional = true }
serde_json = { version = "1", optional = true } serde_json = { version = "1", optional = true }
[dev-dependencies]
criterion = { version = "0.3", default-features = false }
[features] [features]
default = ["atomic_refcell", "default_fonts"] default = ["atomic_refcell", "default_fonts"]
@ -38,7 +35,3 @@ default_fonts = []
# Only needed if you plan to use the same egui::Context from multiple threads. # Only needed if you plan to use the same egui::Context from multiple threads.
multi_threaded = ["parking_lot"] multi_threaded = ["parking_lot"]
[[bench]]
name = "benchmark"
harness = false

View file

@ -676,6 +676,12 @@ impl Context {
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
/// Move all the graphics at the given layer.
/// Can be used to implement drag-and-drop (see relevant demo).
pub fn translate_layer(&self, layer_id: LayerId, delta: Vec2) {
self.graphics().list(layer_id).translate(delta);
}
pub fn layer_id_at(&self, pos: Pos2) -> Option<LayerId> { pub fn layer_id_at(&self, pos: Pos2) -> Option<LayerId> {
let resize_grab_radius_side = self.style().interaction.resize_grab_radius_side; let resize_grab_radius_side = self.style().interaction.resize_grab_radius_side;
self.memory().layer_id_at(pos, resize_grab_radius_side) self.memory().layer_id_at(pos, resize_grab_radius_side)

View file

@ -130,15 +130,6 @@ impl Default for Layout {
} }
impl Layout { impl Layout {
pub(crate) fn from_main_dir_and_cross_align(main_dir: Direction, cross_align: Align) -> Self {
Self {
main_dir,
main_wrap: false,
cross_align,
cross_justify: false,
}
}
pub fn left_to_right() -> Self { pub fn left_to_right() -> Self {
Self { Self {
main_dir: Direction::LeftToRight, main_dir: Direction::LeftToRight,
@ -180,6 +171,15 @@ impl Layout {
} }
} }
pub fn from_main_dir_and_cross_align(main_dir: Direction, cross_align: Align) -> Self {
Self {
main_dir,
main_wrap: false,
cross_align,
cross_justify: false,
}
}
#[deprecated = "Use `top_down`"] #[deprecated = "Use `top_down`"]
pub fn vertical(cross_align: Align) -> Self { pub fn vertical(cross_align: Align) -> Self {
Self::top_down(cross_align) Self::top_down(cross_align)

View file

@ -82,7 +82,6 @@ mod animation_manager;
pub mod app; pub mod app;
pub mod containers; pub mod containers;
mod context; mod context;
pub mod demos;
mod id; mod id;
mod input; mod input;
mod introspection; mod introspection;
@ -103,7 +102,6 @@ pub use {
align::Align, align::Align,
containers::*, containers::*,
context::{Context, CtxRef}, context::{Context, CtxRef},
demos::DemoApp,
id::Id, id::Id,
input::*, input::*,
layers::*, layers::*,
@ -122,28 +120,50 @@ pub use {
widgets::*, widgets::*,
}; };
// ----------------------------------------------------------------------------
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
pub(crate) fn has_debug_assertions() -> bool { pub(crate) const fn has_debug_assertions() -> bool {
true true
} }
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
pub(crate) fn has_debug_assertions() -> bool { pub(crate) const fn has_debug_assertions() -> bool {
false false
} }
#[test] /// Helper function that adds a label when compiling with debug assertions enabled.
fn test_egui_e2e() { pub fn warn_if_debug_build(ui: &mut crate::Ui) {
let mut demo_windows = crate::demos::DemoWindows::default(); if crate::has_debug_assertions() {
let mut ctx = crate::CtxRef::default(); ui.label(
let raw_input = crate::RawInput::default(); crate::Label::new("‼ Debug build ‼")
.small()
const NUM_FRAMES: usize = 5; .text_color(crate::color::RED),
for _ in 0..NUM_FRAMES { )
ctx.begin_frame(raw_input.clone()); .on_hover_text("Egui was compiled with debug assertions enabled.");
demo_windows.ui(&ctx, &Default::default(), &mut None, |_ui| {});
let (_output, paint_commands) = ctx.end_frame();
let paint_jobs = ctx.tessellate(paint_commands);
assert!(!paint_jobs.is_empty());
} }
} }
// ----------------------------------------------------------------------------
/// Create a [`Hyperlink`](crate::Hyperlink) to this file (and line) on Github
///
/// Example: `ui.add(github_link_file_line!("https://github.com/YOUR/PROJECT/blob/master/", "(source code)"));`
#[macro_export]
macro_rules! github_link_file_line {
($github_url:expr, $label:expr) => {{
let url = format!("{}{}#L{}", $github_url, file!(), line!());
$crate::Hyperlink::new(url).text($label)
}};
}
/// Create a [`Hyperlink`](crate::Hyperlink) to this file on github.
///
/// Example: `ui.add(github_link_file!("https://github.com/YOUR/PROJECT/blob/master/", "(source code)"));`
#[macro_export]
macro_rules! github_link_file {
($github_url:expr, $label:expr) => {{
let url = format!("{}{}", $github_url, file!());
$crate::Hyperlink::new(url).text($label)
}};
}

View file

@ -10,6 +10,7 @@ crate-type = ["cdylib", "rlib"]
[dependencies] [dependencies]
egui = { path = "../egui", features = ["serde", "serde_json"] } egui = { path = "../egui", features = ["serde", "serde_json"] }
egui_demo_lib = { path = "../egui_demo_lib" }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
# For compiling natively: # For compiling natively:

View file

@ -12,7 +12,7 @@ use wasm_bindgen::prelude::*;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
#[wasm_bindgen] #[wasm_bindgen]
pub fn start(canvas_id: &str) -> Result<(), wasm_bindgen::JsValue> { pub fn start(canvas_id: &str) -> Result<(), wasm_bindgen::JsValue> {
let app = egui::DemoApp::default(); let app = egui_demo_lib::DemoApp::default();
egui_web::start(canvas_id, Box::new(app))?; egui_web::start(canvas_id, Box::new(app))?;
Ok(()) Ok(())
} }

View file

@ -4,6 +4,6 @@
// When compiling natively: // When compiling natively:
fn main() { fn main() {
let app = egui::DemoApp::default(); let app = egui_demo_lib::DemoApp::default();
egui_glium::run(Box::new(app)); egui_glium::run(Box::new(app));
} }

25
egui_demo_lib/Cargo.toml Normal file
View file

@ -0,0 +1,25 @@
[package]
name = "egui_demo_lib"
version = "0.6.0"
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
description = "Example library for Egui"
edition = "2018"
homepage = "https://github.com/emilk/egui"
license = "MIT OR Apache-2.0"
readme = "README.md"
repository = "https://github.com/emilk/egui"
categories = ["gui", "graphics"]
keywords = ["glium", "egui", "gui", "gamedev"]
include = [ "**/*.rs", "Cargo.toml"]
[lib]
[dependencies]
egui = { version = "0.6.0", path = "../egui" }
[dev-dependencies]
criterion = { version = "0.3", default-features = false }
[[bench]]
name = "benchmark"
harness = false

8
egui_demo_lib/README.md Normal file
View file

@ -0,0 +1,8 @@
# Egui Demo Library
This crate contains example code for Egui.
It is in a separate crate for two reasons:
* To ensure it only uses the public `egui` API.
* To remove the amount of code in `egui` proper.

View file

@ -5,7 +5,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
{ {
let mut ctx = egui::CtxRef::default(); let mut ctx = egui::CtxRef::default();
let mut demo_windows = egui::demos::DemoWindows::default(); let mut demo_windows = egui_demo_lib::DemoWindows::default();
c.bench_function("demo_windows_minimal", |b| { c.bench_function("demo_windows_minimal", |b| {
b.iter(|| { b.iter(|| {
@ -19,7 +19,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
{ {
let mut ctx = egui::CtxRef::default(); let mut ctx = egui::CtxRef::default();
ctx.memory().all_collpasing_are_open = true; // expand the demo window with everything ctx.memory().all_collpasing_are_open = true; // expand the demo window with everything
let mut demo_windows = egui::demos::DemoWindows::default(); let mut demo_windows = egui_demo_lib::DemoWindows::default();
c.bench_function("demo_windows_full", |b| { c.bench_function("demo_windows_full", |b| {
b.iter(|| { b.iter(|| {
@ -33,7 +33,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
{ {
let mut ctx = egui::CtxRef::default(); let mut ctx = egui::CtxRef::default();
ctx.memory().all_collpasing_are_open = true; // expand the demo window with everything ctx.memory().all_collpasing_are_open = true; // expand the demo window with everything
let mut demo_windows = egui::demos::DemoWindows::default(); let mut demo_windows = egui_demo_lib::DemoWindows::default();
ctx.begin_frame(raw_input.clone()); ctx.begin_frame(raw_input.clone());
demo_windows.ui(&ctx, &Default::default(), &mut None, |_ui| {}); demo_windows.ui(&ctx, &Default::default(), &mut None, |_ui| {});
let (_, paint_commands) = ctx.end_frame(); let (_, paint_commands) = ctx.end_frame();
@ -49,7 +49,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
egui::CentralPanel::default().show(&ctx, |ui| { egui::CentralPanel::default().show(&ctx, |ui| {
c.bench_function("label", |b| { c.bench_function("label", |b| {
b.iter(|| { b.iter(|| {
ui.label(egui::demos::LOREM_IPSUM_LONG); ui.label(egui_demo_lib::LOREM_IPSUM_LONG);
}) })
}); });
}); });

View file

@ -1,4 +1,4 @@
use crate::{app, demos, util::History, CtxRef, Response, Ui}; use egui::{util::History, *};
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -90,9 +90,9 @@ impl FrameHistory {
"Includes Egui layout and tessellation time.\n\ "Includes Egui layout and tessellation time.\n\
Does not include GPU usage, nor overhead for sending data to GPU.", Does not include GPU usage, nor overhead for sending data to GPU.",
); );
crate::demos::warn_if_debug_build(ui); egui::warn_if_debug_build(ui);
crate::CollapsingHeader::new("📊 CPU usage history") egui::CollapsingHeader::new("📊 CPU usage history")
.default_open(false) .default_open(false)
.show(ui, |ui| { .show(ui, |ui| {
self.graph(ui); self.graph(ui);
@ -100,8 +100,6 @@ impl FrameHistory {
} }
fn graph(&mut self, ui: &mut Ui) -> Response { fn graph(&mut self, ui: &mut Ui) -> Response {
use crate::*;
let graph_top_cpu_usage = 0.010; let graph_top_cpu_usage = 0.010;
ui.label("Egui CPU usage history"); ui.label("Egui CPU usage history");
@ -179,7 +177,7 @@ impl FrameHistory {
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))] #[cfg_attr(feature = "serde", serde(default))]
pub struct DemoApp { pub struct DemoApp {
demo_windows: demos::DemoWindows, demo_windows: crate::DemoWindows,
backend_window_open: bool, backend_window_open: bool,
@ -236,7 +234,7 @@ impl DemoApp {
.or_else(|| Some(ui.ctx().pixels_per_point())); .or_else(|| Some(ui.ctx().pixels_per_point()));
if let Some(pixels_per_point) = &mut self.pixels_per_point { if let Some(pixels_per_point) = &mut self.pixels_per_point {
ui.add( ui.add(
crate::Slider::f32(pixels_per_point, 0.5..=5.0) egui::Slider::f32(pixels_per_point, 0.5..=5.0)
.logarithmic(true) .logarithmic(true)
.text("Scale (physical pixels per point)"), .text("Scale (physical pixels per point)"),
); );
@ -286,16 +284,16 @@ impl app::App for DemoApp {
} }
#[cfg(feature = "serde_json")] #[cfg(feature = "serde_json")]
fn load(&mut self, storage: &dyn crate::app::Storage) { fn load(&mut self, storage: &dyn egui::app::Storage) {
*self = crate::app::get_value(storage, crate::app::APP_KEY).unwrap_or_default() *self = egui::app::get_value(storage, egui::app::APP_KEY).unwrap_or_default()
} }
#[cfg(feature = "serde_json")] #[cfg(feature = "serde_json")]
fn save(&mut self, storage: &mut dyn crate::app::Storage) { fn save(&mut self, storage: &mut dyn egui::app::Storage) {
crate::app::set_value(storage, crate::app::APP_KEY, self); egui::app::set_value(storage, egui::app::APP_KEY, self);
} }
fn ui(&mut self, ctx: &CtxRef, integration_context: &mut crate::app::IntegrationContext<'_>) { fn ui(&mut self, ctx: &CtxRef, integration_context: &mut egui::app::IntegrationContext<'_>) {
self.frame_history self.frame_history
.on_new_frame(ctx.input().time, integration_context.info.cpu_usage); .on_new_frame(ctx.input().time, integration_context.info.cpu_usage);
@ -307,12 +305,12 @@ impl app::App for DemoApp {
.unwrap_or_default(); .unwrap_or_default();
let link = if web_location_hash == "clock" { let link = if web_location_hash == "clock" {
Some(demos::DemoLink::Clock) Some(crate::DemoLink::Clock)
} else { } else {
None None
}; };
let demo_environment = demos::DemoEnvironment { let demo_environment = crate::DemoEnvironment {
seconds_since_midnight: integration_context.info.seconds_since_midnight, seconds_since_midnight: integration_context.info.seconds_since_midnight,
link, link,
}; };
@ -339,7 +337,7 @@ impl app::App for DemoApp {
); );
let mut backend_window_open = self.backend_window_open; let mut backend_window_open = self.backend_window_open;
crate::Window::new("💻 Backend") egui::Window::new("💻 Backend")
.min_width(360.0) .min_width(360.0)
.scroll(false) .scroll(false)
.open(&mut backend_window_open) .open(&mut backend_window_open)

View file

@ -1,6 +1,4 @@
use crate::widgets::color_picker::show_color; use egui::{color::*, widgets::color_picker::show_color, *};
use crate::*;
use color::*;
use std::collections::HashMap; use std::collections::HashMap;
const GRADIENT_SIZE: Vec2 = vec2(256.0, 24.0); const GRADIENT_SIZE: Vec2 = vec2(256.0, 24.0);
@ -266,7 +264,7 @@ impl ColorTest {
} }
fn vertex_gradient(ui: &mut Ui, bg_fill: Srgba, gradient: &Gradient) -> Response { fn vertex_gradient(ui: &mut Ui, bg_fill: Srgba, gradient: &Gradient) -> Response {
use crate::paint::*; use egui::paint::*;
let response = ui.allocate_response(GRADIENT_SIZE, Sense::hover()); let response = ui.allocate_response(GRADIENT_SIZE, Sense::hover());
if bg_fill != Default::default() { if bg_fill != Default::default() {
let mut triangles = Triangles::default(); let mut triangles = Triangles::default();
@ -324,12 +322,12 @@ impl Gradient {
(0..=n) (0..=n)
.map(|i| { .map(|i| {
let t = i as f32 / n as f32; let t = i as f32 / n as f32;
Srgba([ Srgba::from_rgba_premultiplied(
lerp((left[0] as f32)..=(right[0] as f32), t).round() as u8, // Don't ever do this please! lerp((left[0] as f32)..=(right[0] as f32), t).round() as u8, // Don't ever do this please!
lerp((left[1] as f32)..=(right[1] as f32), t).round() as u8, // Don't ever do this please! lerp((left[1] as f32)..=(right[1] as f32), t).round() as u8, // Don't ever do this please!
lerp((left[2] as f32)..=(right[2] as f32), t).round() as u8, // Don't ever do this please! lerp((left[2] as f32)..=(right[2] as f32), t).round() as u8, // Don't ever do this please!
lerp((left[3] as f32)..=(right[3] as f32), t).round() as u8, // Don't ever do this please! lerp((left[3] as f32)..=(right[3] as f32), t).round() as u8, // Don't ever do this please!
]) )
}) })
.collect(), .collect(),
) )

View file

@ -1,4 +1,4 @@
use crate::{containers::*, demos::*, *}; use egui::{containers::*, *};
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))] #[cfg_attr(feature = "serde", serde(default))]
@ -10,12 +10,13 @@ impl Default for DancingStrings {
} }
} }
impl Demo for DancingStrings { impl crate::Demo for DancingStrings {
fn name(&self) -> &str { fn name(&self) -> &str {
"♫ Dancing Strings" "♫ Dancing Strings"
} }
fn show(&mut self, ctx: &CtxRef, open: &mut bool) { fn show(&mut self, ctx: &CtxRef, open: &mut bool) {
use crate::View;
Window::new(self.name()) Window::new(self.name())
.open(open) .open(open)
.default_size(vec2(512.0, 256.0)) .default_size(vec2(512.0, 256.0))
@ -24,7 +25,7 @@ impl Demo for DancingStrings {
} }
} }
impl View for DancingStrings { impl crate::View for DancingStrings {
fn ui(&mut self, ui: &mut Ui) { fn ui(&mut self, ui: &mut Ui) {
Frame::dark_canvas(ui.style()).show(ui, |ui| { Frame::dark_canvas(ui.style()).show(ui, |ui| {
ui.ctx().request_repaint(); ui.ctx().request_repaint();
@ -62,6 +63,6 @@ impl View for DancingStrings {
ui.painter().extend(cmds); ui.painter().extend(cmds);
}); });
ui.add(__egui_github_link_file!()); ui.add(crate::__egui_github_link_file!());
} }
} }

View file

@ -1,4 +1,5 @@
use crate::{color::*, demos::*, *}; use crate::*;
use egui::{color::*, *};
/// Showcase some ui code /// Showcase some ui code
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
@ -221,8 +222,6 @@ impl BoxPainting {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
use crate::layout::*;
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))] #[cfg_attr(feature = "serde", serde(default))]
struct LayoutDemo { struct LayoutDemo {

View file

@ -1,8 +1,4 @@
use crate::{ use egui::{app, CtxRef, Resize, ScrollArea, Ui, Window};
app,
demos::{self, Demo},
CtxRef, Resize, ScrollArea, Ui, Window,
};
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -29,17 +25,17 @@ pub struct DemoEnvironment {
struct Demos { struct Demos {
/// open, view /// open, view
#[cfg_attr(feature = "serde", serde(skip))] // TODO: serialize the `open` state. #[cfg_attr(feature = "serde", serde(skip))] // TODO: serialize the `open` state.
demos: Vec<(bool, Box<dyn Demo>)>, demos: Vec<(bool, Box<dyn crate::Demo>)>,
} }
impl Default for Demos { impl Default for Demos {
fn default() -> Self { fn default() -> Self {
Self { Self {
demos: vec![ demos: vec![
(false, Box::new(crate::demos::FontBook::default())), (false, Box::new(crate::FontBook::default())),
(false, Box::new(crate::demos::Painting::default())), (false, Box::new(crate::Painting::default())),
(false, Box::new(crate::demos::DancingStrings::default())), (false, Box::new(crate::DancingStrings::default())),
(false, Box::new(crate::demos::DragAndDropDemo::default())), (false, Box::new(crate::DragAndDropDemo::default())),
(false, Box::new(crate::demos::Tests::default())), (false, Box::new(crate::Tests::default())),
], ],
} }
} }
@ -67,12 +63,12 @@ impl Demos {
pub struct DemoWindows { pub struct DemoWindows {
open_windows: OpenWindows, open_windows: OpenWindows,
demo_window: demos::DemoWindow, demo_window: crate::DemoWindow,
#[cfg_attr(feature = "serde", serde(skip))] #[cfg_attr(feature = "serde", serde(skip))]
color_test: demos::ColorTest, color_test: crate::ColorTest,
fractal_clock: demos::FractalClock, fractal_clock: crate::FractalClock,
/// open, title, view /// open, title, view
demos: Demos, demos: Demos,
@ -104,16 +100,16 @@ impl DemoWindows {
self.previous_link = env.link; self.previous_link = env.link;
} }
crate::SidePanel::left("side_panel", 190.0).show(ctx, |ui| { egui::SidePanel::left("side_panel", 190.0).show(ctx, |ui| {
ui.heading("✒ Egui Demo"); ui.heading("✒ Egui Demo");
crate::demos::warn_if_debug_build(ui); egui::warn_if_debug_build(ui);
ui.separator(); ui.separator();
ScrollArea::auto_sized().show(ui, |ui| { ScrollArea::auto_sized().show(ui, |ui| {
ui.label("Egui is an immediate mode GUI library written in Rust."); ui.label("Egui is an immediate mode GUI library written in Rust.");
ui.add( ui.add(
crate::Hyperlink::new("https://github.com/emilk/egui").text(" Egui home page"), egui::Hyperlink::new("https://github.com/emilk/egui").text(" Egui home page"),
); );
ui.label("Egui can be run on the web, or natively on 🐧"); ui.label("Egui can be run on the web, or natively on 🐧");
@ -136,7 +132,7 @@ impl DemoWindows {
}); });
}); });
crate::TopPanel::top("menu_bar").show(ctx, |ui| { egui::TopPanel::top("menu_bar").show(ctx, |ui| {
show_menu_bar(ui, &mut self.open_windows, env.seconds_since_midnight); show_menu_bar(ui, &mut self.open_windows, env.seconds_since_midnight);
}); });
@ -215,7 +211,7 @@ impl DemoWindows {
.show(ctx, |ui| { .show(ctx, |ui| {
ui.label("scroll: NO"); ui.label("scroll: NO");
ui.label("resizable: YES"); ui.label("resizable: YES");
ui.label(demos::LOREM_IPSUM); ui.label(crate::LOREM_IPSUM);
}); });
Window::new("resizable + embedded scroll") Window::new("resizable + embedded scroll")
@ -228,8 +224,8 @@ impl DemoWindows {
ui.label("resizable: YES"); ui.label("resizable: YES");
ui.heading("We have a sub-region with scroll bar:"); ui.heading("We have a sub-region with scroll bar:");
ScrollArea::auto_sized().show(ui, |ui| { ScrollArea::auto_sized().show(ui, |ui| {
ui.label(demos::LOREM_IPSUM_LONG); ui.label(crate::LOREM_IPSUM_LONG);
ui.label(demos::LOREM_IPSUM_LONG); ui.label(crate::LOREM_IPSUM_LONG);
}); });
// ui.heading("Some additional text here, that should also be visible"); // this works, but messes with the resizing a bit // ui.heading("Some additional text here, that should also be visible"); // this works, but messes with the resizing a bit
}); });
@ -242,7 +238,7 @@ impl DemoWindows {
.show(ctx, |ui| { .show(ctx, |ui| {
ui.label("scroll: YES"); ui.label("scroll: YES");
ui.label("resizable: YES"); ui.label("resizable: YES");
ui.label(demos::LOREM_IPSUM_LONG); ui.label(crate::LOREM_IPSUM_LONG);
}); });
Window::new("auto_sized") Window::new("auto_sized")
@ -252,7 +248,7 @@ impl DemoWindows {
ui.label("This window will auto-size based on its contents."); ui.label("This window will auto-size based on its contents.");
ui.heading("Resize this area:"); ui.heading("Resize this area:");
Resize::default().show(ui, |ui| { Resize::default().show(ui, |ui| {
ui.label(demos::LOREM_IPSUM); ui.label(crate::LOREM_IPSUM);
}); });
ui.heading("Resize the above area!"); ui.heading("Resize the above area!");
}); });
@ -327,7 +323,7 @@ impl OpenWindows {
} }
fn show_menu_bar(ui: &mut Ui, windows: &mut OpenWindows, seconds_since_midnight: Option<f64>) { fn show_menu_bar(ui: &mut Ui, windows: &mut OpenWindows, seconds_since_midnight: Option<f64>) {
use crate::*; use egui::*;
menu::bar(ui, |ui| { menu::bar(ui, |ui| {
menu::menu(ui, "File", |ui| { menu::menu(ui, "File", |ui| {

View file

@ -1,7 +1,4 @@
use crate::{ use egui::*;
demos::{Demo, View},
*,
};
pub fn drag_source(ui: &mut Ui, id: Id, body: impl FnOnce(&mut Ui)) { pub fn drag_source(ui: &mut Ui, id: Id, body: impl FnOnce(&mut Ui)) {
let is_being_dragged = ui.memory().is_being_dragged(id); let is_being_dragged = ui.memory().is_being_dragged(id);
@ -18,7 +15,7 @@ pub fn drag_source(ui: &mut Ui, id: Id, body: impl FnOnce(&mut Ui)) {
ui.output().cursor_icon = CursorIcon::Grabbing; ui.output().cursor_icon = CursorIcon::Grabbing;
// Paint the body to a new layer: // Paint the body to a new layer:
let layer_id = LayerId::new(layers::Order::Tooltip, id); let layer_id = LayerId::new(Order::Tooltip, id);
let response = ui.with_layer_id(layer_id, body).1; let response = ui.with_layer_id(layer_id, body).1;
// Now we move the visuals of the body to where the mouse is. // Now we move the visuals of the body to where the mouse is.
@ -30,7 +27,7 @@ pub fn drag_source(ui: &mut Ui, id: Id, body: impl FnOnce(&mut Ui)) {
if let Some(mouse_pos) = ui.input().mouse.pos { if let Some(mouse_pos) = ui.input().mouse.pos {
let delta = mouse_pos - response.rect.center(); let delta = mouse_pos - response.rect.center();
ui.ctx().graphics().list(layer_id).translate(delta); ui.ctx().translate_layer(layer_id, delta);
} }
} }
} }
@ -92,12 +89,13 @@ impl Default for DragAndDropDemo {
} }
} }
impl Demo for DragAndDropDemo { impl crate::Demo for DragAndDropDemo {
fn name(&self) -> &str { fn name(&self) -> &str {
"✋ Drag and Drop" "✋ Drag and Drop"
} }
fn show(&mut self, ctx: &CtxRef, open: &mut bool) { fn show(&mut self, ctx: &CtxRef, open: &mut bool) {
use crate::View;
Window::new(self.name()) Window::new(self.name())
.open(open) .open(open)
.default_size(vec2(256.0, 256.0)) .default_size(vec2(256.0, 256.0))
@ -107,7 +105,7 @@ impl Demo for DragAndDropDemo {
} }
} }
impl View for DragAndDropDemo { impl crate::View for DragAndDropDemo {
fn ui(&mut self, ui: &mut Ui) { fn ui(&mut self, ui: &mut Ui) {
ui.label("This is a proof-of-concept of drag-and-drop in Egui"); ui.label("This is a proof-of-concept of drag-and-drop in Egui");
ui.label("Drag items between columns."); ui.label("Drag items between columns.");
@ -153,6 +151,6 @@ impl View for DragAndDropDemo {
} }
} }
ui.add(__egui_github_link_file!()); ui.add(crate::__egui_github_link_file!());
} }
} }

View file

@ -1,10 +1,8 @@
use crate::*;
pub struct FontBook { pub struct FontBook {
standard: bool, standard: bool,
emojis: bool, emojis: bool,
filter: String, filter: String,
text_style: TextStyle, text_style: egui::TextStyle,
} }
impl Default for FontBook { impl Default for FontBook {
@ -13,13 +11,14 @@ impl Default for FontBook {
standard: false, standard: false,
emojis: true, emojis: true,
filter: Default::default(), filter: Default::default(),
text_style: TextStyle::Button, text_style: egui::TextStyle::Button,
} }
} }
} }
impl FontBook { impl FontBook {
fn characters_ui(&self, ui: &mut Ui, characters: &[(u32, char, &str)]) { fn characters_ui(&self, ui: &mut egui::Ui, characters: &[(u32, char, &str)]) {
use egui::{Button, Label};
for &(_, chr, name) in characters { for &(_, chr, name) in characters {
if self.filter.is_empty() if self.filter.is_empty()
|| name.contains(&self.filter) || name.contains(&self.filter)
@ -27,7 +26,7 @@ impl FontBook {
{ {
let button = Button::new(chr).text_style(self.text_style).frame(false); let button = Button::new(chr).text_style(self.text_style).frame(false);
let tooltip_ui = |ui: &mut Ui| { let tooltip_ui = |ui: &mut egui::Ui| {
ui.add(Label::new(chr).text_style(self.text_style)); ui.add(Label::new(chr).text_style(self.text_style));
ui.label(format!("{}\nU+{:X}\n\nClick to copy", name, chr as u32)); ui.label(format!("{}\nU+{:X}\n\nClick to copy", name, chr as u32));
}; };
@ -40,23 +39,23 @@ impl FontBook {
} }
} }
impl demos::Demo for FontBook { impl crate::Demo for FontBook {
fn name(&self) -> &str { fn name(&self) -> &str {
"🔤 Font Book" "🔤 Font Book"
} }
fn show(&mut self, ctx: &crate::CtxRef, open: &mut bool) { fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) {
Window::new(self.name()).open(open).show(ctx, |ui| { egui::Window::new(self.name()).open(open).show(ctx, |ui| {
use demos::View; use crate::View;
self.ui(ui); self.ui(ui);
}); });
} }
} }
impl demos::View for FontBook { impl crate::View for FontBook {
fn ui(&mut self, ui: &mut Ui) { fn ui(&mut self, ui: &mut egui::Ui) {
use crate::demos::font_contents_emoji::FULL_EMOJI_LIST; use crate::font_contents_emoji::FULL_EMOJI_LIST;
use crate::demos::font_contents_ubuntu::UBUNTU_FONT_CHARACTERS; use crate::font_contents_ubuntu::UBUNTU_FONT_CHARACTERS;
ui.label(format!( ui.label(format!(
"Egui supports {} standard characters and {} emojis.\nClick on a character to copy it.", "Egui supports {} standard characters and {} emojis.\nClick on a character to copy it.",
@ -66,8 +65,8 @@ impl demos::View for FontBook {
ui.separator(); ui.separator();
combo_box_with_label(ui, "Text style", format!("{:?}", self.text_style), |ui| { egui::combo_box_with_label(ui, "Text style", format!("{:?}", self.text_style), |ui| {
for style in TextStyle::all() { for style in egui::TextStyle::all() {
ui.selectable_value(&mut self.text_style, style, format!("{:?}", style)); ui.selectable_value(&mut self.text_style, style, format!("{:?}", style));
} }
}); });
@ -89,9 +88,9 @@ impl demos::View for FontBook {
ui.separator(); ui.separator();
crate::ScrollArea::auto_sized().show(ui, |ui| { egui::ScrollArea::auto_sized().show(ui, |ui| {
ui.horizontal_wrapped(|ui| { ui.horizontal_wrapped(|ui| {
ui.style_mut().spacing.item_spacing = Vec2::splat(2.0); ui.style_mut().spacing.item_spacing = egui::Vec2::splat(2.0);
if self.standard { if self.standard {
self.characters_ui(ui, UBUNTU_FONT_CHARACTERS); self.characters_ui(ui, UBUNTU_FONT_CHARACTERS);

View file

@ -1,4 +1,4 @@
use crate::{containers::*, widgets::*, *}; use egui::{containers::*, widgets::*, *};
use std::f32::consts::TAU; use std::f32::consts::TAU;
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]

View file

@ -1,6 +1,52 @@
//! Demo-code for showing how Egui is used. //! Demo-code for showing how Egui is used.
//! //!
//! The demo-code is also used in benchmarks and tests. //! The demo-code is also used in benchmarks and tests.
#![cfg_attr(not(debug_assertions), deny(warnings))] // Forbid warnings in release builds
#![forbid(unsafe_code)]
#![warn(
clippy::all,
clippy::await_holding_lock,
clippy::dbg_macro,
clippy::doc_markdown,
clippy::empty_enum,
clippy::enum_glob_use,
clippy::exit,
clippy::filter_map_next,
clippy::fn_params_excessive_bools,
clippy::if_let_mutex,
clippy::imprecise_flops,
clippy::inefficient_to_string,
clippy::linkedlist,
clippy::lossy_float_literal,
clippy::macro_use_imports,
clippy::match_on_vec_items,
clippy::match_wildcard_for_single_variants,
clippy::mem_forget,
clippy::mismatched_target_os,
clippy::missing_errors_doc,
clippy::missing_safety_doc,
clippy::needless_borrow,
clippy::needless_continue,
clippy::needless_pass_by_value,
clippy::option_option,
clippy::pub_enum_variant_names,
clippy::rest_pat_in_fully_bound_structs,
clippy::todo,
clippy::unimplemented,
clippy::unnested_or_patterns,
clippy::verbose_file_reads,
future_incompatible,
missing_crate_level_docs,
missing_doc_code_examples,
// missing_docs,
nonstandard_style,
rust_2018_idioms,
unused_doc_comments,
)]
// ----------------------------------------------------------------------------
mod app; mod app;
mod color_test; mod color_test;
mod dancing_strings; mod dancing_strings;
@ -34,7 +80,7 @@ Curabitur pretium tincidunt lacus. Nulla gravida orci a odio. Nullam varius, tur
/// Something to view in the demo windows /// Something to view in the demo windows
pub trait View { pub trait View {
fn ui(&mut self, ui: &mut crate::Ui); fn ui(&mut self, ui: &mut egui::Ui);
} }
/// Something to view /// Something to view
@ -42,55 +88,20 @@ pub trait Demo {
fn name(&self) -> &str; fn name(&self) -> &str;
/// Show windows, etc /// Show windows, etc
fn show(&mut self, ctx: &crate::CtxRef, open: &mut bool); fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool);
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
pub fn warn_if_debug_build(ui: &mut crate::Ui) {
if crate::has_debug_assertions() {
ui.label(
crate::Label::new("‼ Debug build ‼")
.small()
.text_color(crate::color::RED),
)
.on_hover_text("Egui was compiled with debug assertions enabled.");
}
}
// ----------------------------------------------------------------------------
/// Create a [`Hyperlink`](crate::Hyperlink) to this file (and line) on Github
///
/// Example: `ui.add(github_link_file_line!("https://github.com/YOUR/PROJECT/blob/master/", "(source code)"));`
#[macro_export]
macro_rules! github_link_file_line {
($github_url:expr, $label:expr) => {{
let url = format!("{}{}#L{}", $github_url, file!(), line!());
$crate::Hyperlink::new(url).text($label)
}};
}
/// Create a [`Hyperlink`](crate::Hyperlink) to this file on github.
///
/// Example: `ui.add(github_link_file!("https://github.com/YOUR/PROJECT/blob/master/", "(source code)"));`
#[macro_export]
macro_rules! github_link_file {
($github_url:expr, $label:expr) => {{
let url = format!("{}{}", $github_url, file!());
$crate::Hyperlink::new(url).text($label)
}};
}
/// Create a [`Hyperlink`](crate::Hyperlink) to this egui source code file on github. /// Create a [`Hyperlink`](crate::Hyperlink) to this egui source code file on github.
#[doc(hidden)] #[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! __egui_github_link_file { macro_rules! __egui_github_link_file {
() => { () => {
__egui_github_link_file!("(source code)") crate::__egui_github_link_file!("(source code)")
}; };
($label:expr) => { ($label:expr) => {
github_link_file!("https://github.com/emilk/egui/blob/master/", $label).small() egui::github_link_file!("https://github.com/emilk/egui/blob/master/", $label).small()
}; };
} }
@ -99,9 +110,27 @@ macro_rules! __egui_github_link_file {
#[macro_export] #[macro_export]
macro_rules! __egui_github_link_file_line { macro_rules! __egui_github_link_file_line {
() => { () => {
__egui_github_link_file_line!("(source code)") crate::__egui_github_link_file_line!("(source code)")
}; };
($label:expr) => { ($label:expr) => {
github_link_file_line!("https://github.com/emilk/egui/blob/master/", $label).small() egui::github_link_file_line!("https://github.com/emilk/egui/blob/master/", $label).small()
}; };
} }
// ----------------------------------------------------------------------------
#[test]
fn test_egui_e2e() {
let mut demo_windows = crate::DemoWindows::default();
let mut ctx = egui::CtxRef::default();
let raw_input = egui::RawInput::default();
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| {});
let (_output, paint_commands) = ctx.end_frame();
let paint_jobs = ctx.tessellate(paint_commands);
assert!(!paint_jobs.is_empty());
}
}

View file

@ -1,4 +1,5 @@
use crate::{demos::*, *}; use crate::*;
use egui::*;
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))] #[cfg_attr(feature = "serde", serde(default))]
@ -58,7 +59,7 @@ impl Painting {
} }
} }
impl demos::Demo for Painting { impl crate::Demo for Painting {
fn name(&self) -> &str { fn name(&self) -> &str {
"🖊 Painting" "🖊 Painting"
} }
@ -72,9 +73,9 @@ impl demos::Demo for Painting {
} }
} }
impl demos::View for Painting { impl crate::View for Painting {
fn ui(&mut self, ui: &mut Ui) { fn ui(&mut self, ui: &mut Ui) {
ui.add(__egui_github_link_file!("(source code)")); ui.add(crate::__egui_github_link_file!("(source code)"));
self.ui_control(ui); self.ui_control(ui);
ui.label("Paint with your mouse/touch!"); ui.label("Paint with your mouse/touch!");
Frame::dark_canvas(ui.style()).show(ui, |ui| { Frame::dark_canvas(ui.style()).show(ui, |ui| {

View file

@ -1,4 +1,5 @@
use crate::{color::*, demos::LOREM_IPSUM_LONG, *}; use crate::LOREM_IPSUM_LONG;
use egui::{color::*, *};
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))] #[cfg_attr(feature = "serde", serde(default))]

View file

@ -1,4 +1,4 @@
use crate::*; use egui::*;
use std::f64::INFINITY; use std::f64::INFINITY;
/// Showcase sliders /// Showcase sliders

View file

@ -1,23 +1,21 @@
use crate::*;
#[derive(Default)] #[derive(Default)]
pub struct Tests {} pub struct Tests {}
impl demos::Demo for Tests { impl crate::Demo for Tests {
fn name(&self) -> &str { fn name(&self) -> &str {
"📋 Tests" "📋 Tests"
} }
fn show(&mut self, ctx: &crate::CtxRef, open: &mut bool) { fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) {
Window::new(self.name()).open(open).show(ctx, |ui| { egui::Window::new(self.name()).open(open).show(ctx, |ui| {
use demos::View; use crate::View;
self.ui(ui); self.ui(ui);
}); });
} }
} }
impl demos::View for Tests { impl crate::View for Tests {
fn ui(&mut self, ui: &mut Ui) { fn ui(&mut self, ui: &mut egui::Ui) {
ui.heading("Name collision example"); ui.heading("Name collision example");
ui.label("\ ui.label("\
@ -46,6 +44,6 @@ impl demos::View for Tests {
let _ = ui.button("Button"); let _ = ui.button("Button");
let _ = ui.button("Button"); let _ = ui.button("Button");
ui.add(__egui_github_link_file!()); ui.add(crate::__egui_github_link_file!());
} }
} }

View file

@ -1,6 +1,5 @@
//! Source code example of how to create your own widget. //! Source code example of how to create your own widget.
//! This is meant to be read as a tutorial, hence the plethora of comments. //! This is meant to be read as a tutorial, hence the plethora of comments.
use crate::*;
/// iOS-style toggle switch: /// iOS-style toggle switch:
/// ///
@ -10,7 +9,7 @@ use crate::*;
/// | |.......| /// | |.......|
/// \_______\_____/ /// \_______\_____/
/// ``` /// ```
pub fn toggle(ui: &mut Ui, on: &mut bool) -> Response { pub fn toggle(ui: &mut egui::Ui, on: &mut bool) -> egui::Response {
// Widget code can be broken up in four steps: // Widget code can be broken up in four steps:
// 1. Decide a size for the widget // 1. Decide a size for the widget
// 2. Allocate space for it // 2. Allocate space for it
@ -25,7 +24,7 @@ pub fn toggle(ui: &mut Ui, on: &mut bool) -> Response {
// 2. Allocating space: // 2. Allocating space:
// This is where we get a region of the screen assigned. // This is where we get a region of the screen assigned.
// We also tell the Ui to sense clicks in the allocated region. // We also tell the Ui to sense clicks in the allocated region.
let response = ui.allocate_response(desired_size, Sense::click()); let response = ui.allocate_response(desired_size, egui::Sense::click());
// 3. Interact: Time to check for clicks!. // 3. Interact: Time to check for clicks!.
if response.clicked { if response.clicked {
@ -41,16 +40,16 @@ pub fn toggle(ui: &mut Ui, on: &mut bool) -> Response {
// "how should something that is being interacted with be painted?". // "how should something that is being interacted with be painted?".
// This will, for instance, give us different colors when the widget is hovered or clicked. // This will, for instance, give us different colors when the widget is hovered or clicked.
let visuals = ui.style().interact(&response); let visuals = ui.style().interact(&response);
let off_bg_fill = Rgba::new(0.0, 0.0, 0.0, 0.0); let off_bg_fill = egui::Rgba::new(0.0, 0.0, 0.0, 0.0);
let on_bg_fill = Rgba::new(0.0, 0.5, 0.25, 1.0); let on_bg_fill = egui::Rgba::new(0.0, 0.5, 0.25, 1.0);
let bg_fill = lerp(off_bg_fill..=on_bg_fill, how_on); let bg_fill = egui::lerp(off_bg_fill..=on_bg_fill, how_on);
// All coordinates are in absolute screen coordinates so we use `rect` to place the elements. // All coordinates are in absolute screen coordinates so we use `rect` to place the elements.
let rect = response.rect; let rect = response.rect;
let radius = 0.5 * rect.height(); let radius = 0.5 * rect.height();
ui.painter().rect(rect, radius, bg_fill, visuals.bg_stroke); ui.painter().rect(rect, radius, bg_fill, visuals.bg_stroke);
// Paint the circle, animating it from left to right with `how_on`: // Paint the circle, animating it from left to right with `how_on`:
let circle_x = lerp((rect.left() + radius)..=(rect.right() - radius), how_on); let circle_x = egui::lerp((rect.left() + radius)..=(rect.right() - radius), how_on);
let center = pos2(circle_x, rect.center().y); let center = egui::pos2(circle_x, rect.center().y);
ui.painter() ui.painter()
.circle(center, 0.75 * radius, visuals.fg_fill, visuals.fg_stroke); .circle(center, 0.75 * radius, visuals.fg_fill, visuals.fg_stroke);
@ -61,32 +60,32 @@ pub fn toggle(ui: &mut Ui, on: &mut bool) -> Response {
/// Here is the same code again, but a bit more compact: /// Here is the same code again, but a bit more compact:
#[allow(dead_code)] #[allow(dead_code)]
fn toggle_compact(ui: &mut Ui, on: &mut bool) -> Response { fn toggle_compact(ui: &mut egui::Ui, on: &mut bool) -> egui::Response {
let desired_size = ui.style().spacing.interact_size; let desired_size = ui.style().spacing.interact_size;
let response = ui.allocate_response(desired_size, Sense::click()); let response = ui.allocate_response(desired_size, egui::Sense::click());
*on ^= response.clicked; // toggle if clicked *on ^= response.clicked; // toggle if clicked
let how_on = ui.ctx().animate_bool(response.id, *on); let how_on = ui.ctx().animate_bool(response.id, *on);
let visuals = ui.style().interact(&response); let visuals = ui.style().interact(&response);
let off_bg_fill = Rgba::new(0.0, 0.0, 0.0, 0.0); let off_bg_fill = egui::Rgba::new(0.0, 0.0, 0.0, 0.0);
let on_bg_fill = Rgba::new(0.0, 0.5, 0.25, 1.0); let on_bg_fill = egui::Rgba::new(0.0, 0.5, 0.25, 1.0);
let bg_fill = lerp(off_bg_fill..=on_bg_fill, how_on); let bg_fill = egui::lerp(off_bg_fill..=on_bg_fill, how_on);
let rect = response.rect; let rect = response.rect;
let radius = 0.5 * rect.height(); let radius = 0.5 * rect.height();
ui.painter().rect(rect, radius, bg_fill, visuals.bg_stroke); ui.painter().rect(rect, radius, bg_fill, visuals.bg_stroke);
let circle_x = lerp((rect.left() + radius)..=(rect.right() - radius), how_on); let circle_x = egui::lerp((rect.left() + radius)..=(rect.right() - radius), how_on);
let center = pos2(circle_x, rect.center().y); let center = egui::pos2(circle_x, rect.center().y);
ui.painter() ui.painter()
.circle(center, 0.75 * radius, visuals.fg_fill, visuals.fg_stroke); .circle(center, 0.75 * radius, visuals.fg_fill, visuals.fg_stroke);
response response
} }
pub fn demo(ui: &mut Ui, on: &mut bool) { pub fn demo(ui: &mut egui::Ui, on: &mut bool) {
ui.horizontal_wrapped_for_text(TextStyle::Button, |ui| { ui.horizontal_wrapped_for_text(egui::TextStyle::Button, |ui| {
ui.label("It's easy to create your own widgets!"); ui.label("It's easy to create your own widgets!");
ui.label("This toggle switch is just one function and 15 lines of code:"); ui.label("This toggle switch is just one function and 15 lines of code:");
toggle(ui, on).on_hover_text("Click to toggle"); toggle(ui, on).on_hover_text("Click to toggle");
ui.add(__egui_github_link_file!()); ui.add(crate::__egui_github_link_file!());
}); });
} }

View file

@ -1,4 +1,4 @@
use crate::{color::*, demos::Sliders, *}; use egui::{color::*, *};
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
@ -20,7 +20,7 @@ pub struct Widgets {
button_enabled: bool, button_enabled: bool,
count: usize, count: usize,
radio: Enum, radio: Enum,
sliders: Sliders, sliders: crate::Sliders,
angle: f32, angle: f32,
color: Srgba, color: Srgba,
single_line_text_input: String, single_line_text_input: String,
@ -46,7 +46,7 @@ impl Default for Widgets {
impl Widgets { impl Widgets {
pub fn ui(&mut self, ui: &mut Ui) { pub fn ui(&mut self, ui: &mut Ui) {
ui.add(__egui_github_link_file_line!()); ui.add(crate::__egui_github_link_file_line!());
ui.horizontal_wrapped_for_text(TextStyle::Body, |ui| { ui.horizontal_wrapped_for_text(TextStyle::Body, |ui| {
ui.add(Label::new("Text can have").text_color(srgba(110, 255, 110, 255))); ui.add(Label::new("Text can have").text_color(srgba(110, 255, 110, 255)));
@ -83,7 +83,7 @@ impl Widgets {
ui.radio_value(&mut self.radio, Enum::Third, "Third"); ui.radio_value(&mut self.radio, Enum::Third, "Third");
}); });
combo_box_with_label(ui, "Combo Box", format!("{:?}", self.radio), |ui| { egui::combo_box_with_label(ui, "Combo Box", format!("{:?}", self.radio), |ui| {
ui.selectable_value(&mut self.radio, Enum::First, "First"); ui.selectable_value(&mut self.radio, Enum::First, "First");
ui.selectable_value(&mut self.radio, Enum::Second, "Second"); ui.selectable_value(&mut self.radio, Enum::Second, "Second");
ui.selectable_value(&mut self.radio, Enum::Third, "Third"); ui.selectable_value(&mut self.radio, Enum::Third, "Third");
@ -110,12 +110,12 @@ impl Widgets {
}); });
ui.add( ui.add(
Slider::f64(&mut self.sliders.value, 1.0..=100.0) egui::Slider::f64(&mut self.sliders.value, 1.0..=100.0)
.logarithmic(true) .logarithmic(true)
.text("A slider"), .text("A slider"),
); );
CollapsingHeader::new("More sliders") egui::CollapsingHeader::new("More sliders")
.default_open(false) .default_open(false)
.show(ui, |ui| { .show(ui, |ui| {
self.sliders.ui(ui); self.sliders.ui(ui);
@ -136,7 +136,7 @@ impl Widgets {
ui.separator(); ui.separator();
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.add(Label::new("Click to select a different text color: ").text_color(self.color)); ui.colored_label(self.color, "Click to select a different text color: ");
ui.color_edit_button_srgba(&mut self.color); ui.color_edit_button_srgba(&mut self.color);
}); });
@ -154,6 +154,6 @@ impl Widgets {
ui.text_edit_multiline(&mut self.multiline_text_input); ui.text_edit_multiline(&mut self.multiline_text_input);
ui.separator(); ui.separator();
super::toggle_switch::demo(ui, &mut self.toggle_switch); crate::toggle_switch::demo(ui, &mut self.toggle_switch);
} }
} }