From 5ce681ef1648be61c6bae09261b20986e362e76b Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Sun, 7 Feb 2021 14:55:39 +0100 Subject: [PATCH] Improve documentation --- README.md | 2 +- egui/src/containers/frame.rs | 4 +-- egui/src/containers/panel.rs | 1 + egui/src/containers/window.rs | 5 +-- egui/src/context.rs | 49 +++++++++++++++++++++++--- egui/src/data/input.rs | 4 +-- egui/src/lib.rs | 60 ++++++++++++++++++++++---------- egui/src/widgets/color_picker.rs | 2 +- emath/src/rect.rs | 7 ++-- 9 files changed, 99 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index d1749614..4051dcc6 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ ui.label(format!("Hello '{}', age {}", name, age)); * Friendly: difficult to make mistakes, and shouldn't panic * Portable: the same code works on the web and as a native app * Easy to integrate into any environment -* A simple 2D graphics API for custom painting +* A simple 2D graphics API for custom painting ([`epaint`](https://docs.rs/epaint)). * No callbacks * Pure immediate mode * Extensible: [easy to write your own widgets for egui](https://github.com/emilk/egui/blob/master/egui_demo_lib/src/apps/demo/toggle_switch.rs) diff --git a/egui/src/containers/frame.rs b/egui/src/containers/frame.rs index 9594bf7c..c969853b 100644 --- a/egui/src/containers/frame.rs +++ b/egui/src/containers/frame.rs @@ -2,10 +2,10 @@ use crate::{layers::ShapeIdx, paint::*, *}; -/// Adds a rectangular frame and background to some [`Ui`]. +/// Color and margin of a rectangular background of a [`Ui`]. #[derive(Clone, Copy, Debug, Default, PartialEq)] pub struct Frame { - // On each side + /// On each side pub margin: Vec2, pub corner_radius: f32, pub shadow: Shadow, diff --git a/egui/src/containers/panel.rs b/egui/src/containers/panel.rs index 80b671a1..e08744e8 100644 --- a/egui/src/containers/panel.rs +++ b/egui/src/containers/panel.rs @@ -158,6 +158,7 @@ pub struct CentralPanel { } impl CentralPanel { + /// Change the background color, margins, etc. pub fn frame(mut self, frame: Frame) -> Self { self.frame = Some(frame); self diff --git a/egui/src/containers/window.rs b/egui/src/containers/window.rs index c9b9b57b..95b5758f 100644 --- a/egui/src/containers/window.rs +++ b/egui/src/containers/window.rs @@ -90,8 +90,7 @@ impl<'open> Window<'open> { self } - /// Usage: `Window::new(...).frame(|f| f.fill(Some(BLUE)))` - /// Not sure this is a good interface for this. + /// Change the background color, margins, etc. pub fn frame(mut self, frame: Frame) -> Self { self.frame = Some(frame); self @@ -399,6 +398,7 @@ struct PossibleInteractions { resizable: bool, } +/// Either a move or resize #[derive(Clone, Copy, Debug)] pub(crate) struct WindowInteraction { pub(crate) area_layer_id: LayerId, @@ -486,6 +486,7 @@ fn move_and_resize_window(ctx: &Context, window_interaction: &WindowInteraction) Some(rect) } +/// Returns `Some` if there is a move or resize fn window_interaction( ctx: &Context, possible: PossibleInteractions, diff --git a/egui/src/context.rs b/egui/src/context.rs index bf749ed4..c91ca0d0 100644 --- a/egui/src/context.rs +++ b/egui/src/context.rs @@ -127,6 +127,37 @@ impl FrameState { /// A wrapper around [`Arc`](std::sync::Arc)`<`[`Context`]`>`. /// This is how you will normally create and access a [`Context`]. +/// +/// Almost all methods are marked `&self`, `Context` has interior mutability (protected by mutexes). +/// +/// [`CtxRef`] is cheap to clone, and any clones refers to the same mutable data. +/// +/// # Example: +/// +/// ``` no_run +/// # fn handle_output(_: egui::Output) {} +/// # fn paint(_: Vec) {} +/// let mut ctx = egui::CtxRef::default(); +/// +/// // Game loop: +/// loop { +/// let raw_input = egui::RawInput::default(); +/// ctx.begin_frame(raw_input); +/// +/// egui::CentralPanel::default().show(&ctx, |ui| { +/// ui.label("Hello world!"); +/// if ui.button("Click me").clicked() { +/// /* take some action here */ +/// } +/// }); +/// +/// let (output, shapes) = ctx.end_frame(); +/// let clipped_meshes = ctx.tessellate(shapes); // create triangles to paint +/// handle_output(output); +/// paint(clipped_meshes); +/// } +/// ``` +/// #[derive(Clone)] pub struct CtxRef(std::sync::Arc); @@ -168,7 +199,11 @@ impl Default for CtxRef { } impl CtxRef { - /// Call at the start of every frame. + /// Call at the start of every frame. Match with a call to [`Context::end_frame`]. + /// + /// This will modify the internal reference to point to a new generation of [`Context`]. + /// Any old clones of this [`CtxRef`] will refer to the old [`Context`], which will not get new input. + /// /// Put your widgets into a [`SidePanel`], [`TopPanel`], [`CentralPanel`], [`Window`] or [`Area`]. pub fn begin_frame(&mut self, new_input: RawInput) { let mut self_: Context = (*self.0).clone(); @@ -354,7 +389,14 @@ impl CtxRef { /// This is the first thing you need when working with egui. Create using [`CtxRef`]. /// /// Contains the [`InputState`], [`Memory`], [`Output`], and more. -// TODO: too many mutexes. Maybe put it all behind one Mutex instead. +/// +/// Your handle to Egui. +/// +/// Almost all methods are marked `&self`, `Context` has interior mutability (protected by mutexes). +/// Multi-threaded access to a [`Context`] is behind the feature flag `multi_threaded`. +/// Normally you'd always do all ui work on one thread, or perhaps use multiple contexts, +/// but if you really want to access the same Context from multiple threads, it *SHOULD* be fine, +/// but you are likely the first person to try it. #[derive(Default)] pub struct Context { /// None until first call to `begin_frame`. @@ -591,8 +633,7 @@ impl Context { /// Call at the end of each frame. /// Returns what has happened this frame (`Output`) as well as what you need to paint. - /// You can transform the returned shapes into triangles with a call to - /// `Context::tessellate`. + /// You can transform the returned shapes into triangles with a call to `Context::tessellate`. #[must_use] pub fn end_frame(&self) -> (Output, Vec) { if self.input.wants_repaint() { diff --git a/egui/src/data/input.rs b/egui/src/data/input.rs index e6f44665..fc72a1c1 100644 --- a/egui/src/data/input.rs +++ b/egui/src/data/input.rs @@ -12,13 +12,13 @@ pub struct RawInput { /// How many points (logical pixels) the user scrolled pub scroll_delta: Vec2, - #[deprecated = "Use screen_rect instead: `Some(Rect::from_pos_size(Default::default(), vec2(window_width, window_height)))`"] + #[deprecated = "Use instead: `screen_rect: Some(Rect::from_pos_size(Default::default(), screen_size))`"] pub screen_size: Vec2, /// Position and size of the area that egui should use. /// Usually you would set this to /// - /// `Some(Rect::from_pos_size(Default::default(), vec2(window_width, window_height)))`. + /// `Some(Rect::from_pos_size(Default::default(), screen_size))`. /// /// but you could also constrain egui to some smaller portion of your window if you like. /// diff --git a/egui/src/lib.rs b/egui/src/lib.rs index b9c42947..c9f5c180 100644 --- a/egui/src/lib.rs +++ b/egui/src/lib.rs @@ -4,6 +4,40 @@ //! which uses [`eframe`](https://docs.rs/eframe). //! //! To create a GUI using egui you first need a [`CtxRef`] (by convention referred to by `ctx`). +//! Then you add a [`Window`] or a [`SidePanel`] to get a [`Ui`], which is what you'll be using to add all the buttons and labels that you need. +//! +//! ## Integrating with egui +//! To write your own integration for egui you need to do this: +//! +//! ``` no_run +//! # fn handle_output(_: egui::Output) {} +//! # fn paint(_: Vec) {} +//! # fn gather_input() -> egui::RawInput { egui::RawInput::default() } +//! let mut ctx = egui::CtxRef::default(); +//! +//! // Game loop: +//! loop { +//! let raw_input: egui::RawInput = gather_input(); +//! ctx.begin_frame(raw_input); +//! +//! egui::CentralPanel::default().show(&ctx, |ui| { +//! ui.label("Hello world!"); +//! if ui.button("Click me").clicked() { +//! /* take some action here */ +//! } +//! }); +//! +//! let (output, shapes) = ctx.end_frame(); +//! let clipped_meshes = ctx.tessellate(shapes); // create triangles to paint +//! handle_output(output); +//! paint(clipped_meshes); +//! } +//! ``` +//! +//! ## Using egui +//! +//! To see what is possible to build we egui you can check out the online demo at . +//! //! Use one of [`SidePanel`], [`TopPanel`], [`CentralPanel`], [`Window`] or [`Area`] to //! get access to an [`Ui`] where you can put widgets. For example: //! @@ -11,28 +45,14 @@ //! # let mut ctx = egui::CtxRef::default(); //! # ctx.begin_frame(Default::default()); //! egui::CentralPanel::default().show(&ctx, |ui| { -//! ui.label("Hello"); +//! ui.add(egui::Label::new("Hello World!")); +//! ui.label("A shorter and more convenient way to add a label."); +//! if ui.button("Click me").clicked() { +//! /* take some action here */ +//! } //! }); -//! ``` //! //! -//! To write your own integration for egui you need to do this: -//! -//! ``` ignore -//! let mut egui_ctx = egui::CtxRef::default(); -//! -//! // Game loop: -//! loop { -//! let raw_input: egui::RawInput = my_integration.gather_input(); -//! egui_ctx.begin_frame(raw_input); -//! my_app.ui(&egui_ctx); // add panels, windows and widgets to `egui_ctx` here -//! let (output, shapes) = egui_ctx.end_frame(); -//! let clipped_meshes = egui_ctx.tessellate(shapes); // create triangles to paint -//! my_integration.paint(clipped_meshes); -//! my_integration.set_cursor_icon(output.cursor_icon); -//! // Also see `egui::Output` for more -//! } -//! ``` #![cfg_attr(not(debug_assertions), deny(warnings))] // Forbid warnings in release builds #![forbid(unsafe_code)] @@ -133,11 +153,13 @@ pub use { // ---------------------------------------------------------------------------- +/// `true` if egui was compiled with debug assertions enabled. #[cfg(debug_assertions)] pub(crate) const fn has_debug_assertions() -> bool { true } +/// `true` if egui was compiled with debug assertions enabled. #[cfg(not(debug_assertions))] pub(crate) const fn has_debug_assertions() -> bool { false diff --git a/egui/src/widgets/color_picker.rs b/egui/src/widgets/color_picker.rs index 7f533640..3a29de65 100644 --- a/egui/src/widgets/color_picker.rs +++ b/egui/src/widgets/color_picker.rs @@ -348,7 +348,7 @@ pub fn color_edit_button_hsva(ui: &mut Ui, hsva: &mut Hsva, alpha: Alpha) -> Res /// Shows a button with the given color. /// If the user clicks the button, a full color picker is shown. pub fn color_edit_button_srgba(ui: &mut Ui, srgba: &mut Color32, alpha: Alpha) -> Response { - // To ensure we keep hue slider when `srgba` is grey we store the + // To ensure we keep hue slider when `srgba` is gray we store the // full `Hsva` in a cache: let mut hsva = ui diff --git a/emath/src/rect.rs b/emath/src/rect.rs index 2f14f063..e98555ff 100644 --- a/emath/src/rect.rs +++ b/emath/src/rect.rs @@ -91,12 +91,11 @@ impl Rect { max: pos2(*x_range.end(), *y_range.end()), } } + pub fn from_two_pos(a: Pos2, b: Pos2) -> Self { - let (left, right) = if a.x > b.x { (b.x, a.x) } else { (a.x, b.x) }; - let (top, bottom) = if a.y > b.y { (b.y, a.y) } else { (a.y, b.y) }; Rect { - min: pos2(left, top), - max: pos2(right, bottom), + min: pos2(a.x.min(b.x), a.y.min(b.y)), + max: pos2(a.x.max(b.x), a.y.max(b.y)), } }