From 82863f8ec258bfb032e6e373607e449c7264fb87 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Thu, 16 Nov 2023 10:25:02 +0100 Subject: [PATCH] Add a lot more documentation --- crates/egui/src/containers/window.rs | 3 ++ crates/egui/src/context.rs | 14 ++++--- crates/egui/src/lib.rs | 4 ++ crates/egui/src/viewport.rs | 58 +++++++++++++++++++++++++--- examples/test_viewports/src/main.rs | 2 +- 5 files changed, 69 insertions(+), 12 deletions(-) diff --git a/crates/egui/src/containers/window.rs b/crates/egui/src/containers/window.rs index 3fcc5de0b23..64de28e2029 100644 --- a/crates/egui/src/containers/window.rs +++ b/crates/egui/src/containers/window.rs @@ -24,6 +24,9 @@ use super::*; /// ``` /// /// The previous rectangle used by this window can be obtained through [`crate::Memory::area_rect()`]. +/// +/// Note that this is NOT a native OS window. +/// To create a new native OS window, use [`crate::Context::show_viewport`]. #[must_use = "You should call .show()"] pub struct Window<'open> { title: WidgetText, diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index 4babd81c74c..9dc28a543b0 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -2555,14 +2555,14 @@ impl Context { /// Send a command to the current viewport. /// /// This lets you affect the current viewport, e.g. resizing the window. - pub fn viewport_command(&self, command: ViewportCommand) { - self.viewport_command_for(self.viewport_id(), command); + pub fn send_viewport_command(&self, command: ViewportCommand) { + self.send_viewport_command_to(self.viewport_id(), command); } /// Send a command to a speicfic viewport. /// /// This lets you affect another viewport, e.g. resizing its window. - pub fn viewport_command_for(&self, id: ViewportId, command: ViewportCommand) { + pub fn send_viewport_command_to(&self, id: ViewportId, command: ViewportCommand) { self.write(|ctx| ctx.viewport_for(id).commands.push(command)); } @@ -2589,7 +2589,9 @@ impl Context { /// backend does not support multiple viewports), the given callback /// will be called immediately, embedding the new viewport in the current one. /// You can check this with the [`ViewportClass`] given in the callback. - /// If you find [`ViewportClass::embedded`], you need to create a new [`crate::Window`] for you content. + /// If you find [`ViewportClass::Embedded`], you need to create a new [`crate::Window`] for you content. + /// + /// See [`crate::viewport`] for more information about viewports. pub fn show_viewport( &self, new_viewport_id: ViewportId, @@ -2636,7 +2638,9 @@ impl Context { /// backend does not support multiple viewports), the given callback /// will be called immediately, embedding the new viewport in the current one. /// You can check this with the [`ViewportClass`] given in the callback. - /// If you find [`ViewportClass::embedded`], you need to create a new [`crate::Window`] for you content. + /// If you find [`ViewportClass::Embedded`], you need to create a new [`crate::Window`] for you content. + /// + /// See [`crate::viewport`] for more information about viewports. pub fn show_viewport_immediate( &self, new_viewport_id: ViewportId, diff --git a/crates/egui/src/lib.rs b/crates/egui/src/lib.rs index 773667b44ba..760475fb9be 100644 --- a/crates/egui/src/lib.rs +++ b/crates/egui/src/lib.rs @@ -96,6 +96,10 @@ //! # }); //! ``` //! +//! ## Viewports +//! Some egui backends support multiple _viewports_, which is what egui calls the native OS windows it resides in. +//! See [`crate::viewport`] for more information. +//! //! ## Coordinate system //! The left-top corner of the screen is `(0.0, 0.0)`, //! with X increasing to the right and Y increasing downwards. diff --git a/crates/egui/src/viewport.rs b/crates/egui/src/viewport.rs index 8fbecfa4441..c3fa7cec009 100644 --- a/crates/egui/src/viewport.rs +++ b/crates/egui/src/viewport.rs @@ -1,11 +1,57 @@ //! egui supports multiple viewports, corresponding to multiple native windows. //! -//! Viewports come in two flavors: "deferred" (the default) and "immediate". +//! Not all egui backends support multiple viewports, but `eframe` native does +//! (but not on web). //! -//! * Deferred viewports have callbacks that are called multiple -//! times as the viewport receives events, or need repaitning. -//! * Immediate viewports are executed immediately with an [`FnOnce`] callback, -//! locking the parent and child viewports together so that they both must update at the same time. +//! You can spawn a new viewport using [`Context::show_viewport`] and [`Context::show_viewport_immediate`]. +//! These needs to be called every frame the viewport should be visible. +//! +//! This is implemented by the native `eframe` backend, but not the web one. +//! +//! ## Viewport classes +//! The viewports form a tree of parent-child relationships. +//! +//! There are different classes of viewports. +//! +//! ### Root viewport +//! The root viewport is the original viewport, and cannot be closed without closing the application. +//! +//! ### Deferred viewports +//! These are created with [`Context::show_viewport`]. +//! Deferred viewports take a closure that is called by the integration at a later time, perhaps multiple times. +//! Deferred viewports are repainted independenantly of the parent viewport. +//! This means communication with them need to done via channels, or `Arc/Mutex`. +//! +//! This is the most performant type of child viewport, though a bit more cumbersome to work with compared to immediate viewports. +//! +//! ### Immediate viewports +//! These are created with [`Context::show_viewport_immediate`]. +//! Immediate viewports take a `FnOnce` closure, similar to other egui functions, and is called immediately. +//! This makes communication with them much simpler than with deferred viewports, but this simplicity comes at a cost: whenever the parent viewports needs to be repainted, so will the child viewport, and vice versa. +//! This means that if you have `N` viewports you are potentially doing `N` times as much CPU work. However, if all your viewports are showing animations, and thus are repainting constantly anyway, this doesn't matter. +//! +//! In short: immediate viewports are simpler to use, but can waste a lot of CPU time. +//! +//! ### Embedded viewports +//! These are not real, independenant viewports, but is a fallback mode for when the integration does not support real viewports. In your callback is called with [`ViewportClass::Embedded`] it means you need to create an [`crate::Window`] to wrap your ui in, which will then be embedded in the parent viewport, unable to escape it. +//! +//! +//! ## Using the viewports +//! Only one viewport is active at any one time, identified with [`Context::viewport_id`]. +//! You can send commands to other viewports using [`Context::send_viewport_command_to`]. +//! +//! There is an example in . +//! +//! ## For integrations +//! * There is a [`crate::RawInput::viewport`] with information about the current viewport. +//! * The repaint callback set by [`Context::set_request_repaint_callback`] points to which viewport should be repainted. +//! * [`crate::FullOutput::viewport_output`] is a list of viewports which should result in their own independent windows. +//! * To support immediate viewports you need to call [`Context::set_immediate_viewport_renderer`]. +//! * If you support viewports, you need to call [`Context::set_embed_viewports`] with `false`, or all new viewports will be embedded (the default behavior). +//! +//! ## Future work +//! There are several more things related to viewports that we want to add. +//! Read more at . use std::sync::Arc; @@ -609,7 +655,7 @@ pub enum ResizeDirection { SouthWest, } -/// You can send a [`ViewportCommand`] to the viewport with [`Context::viewport_command`]. +/// You can send a [`ViewportCommand`] to the viewport with [`Context::send_viewport_command`]. /// /// All coordinates are in logical points. /// diff --git a/examples/test_viewports/src/main.rs b/examples/test_viewports/src/main.rs index 8153509f698..99908cd906b 100644 --- a/examples/test_viewports/src/main.rs +++ b/examples/test_viewports/src/main.rs @@ -263,7 +263,7 @@ fn generic_ui(ui: &mut egui::Ui, children: &[Arc>]) { if ctx.viewport_id() != ctx.parent_viewport_id() { let parent = ctx.parent_viewport_id(); if ui.button("Set parent pos 0,0").clicked() { - ctx.viewport_command_for( + ctx.send_viewport_command_to( parent, egui::ViewportCommand::OuterPosition(egui::pos2(0.0, 0.0)), );