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

Rename the viewport types to "immediate" and "deferred"

This commit is contained in:
Emil Ernerfeldt
2023-11-07 11:50:59 +01:00
parent d4fab25fc8
commit f300c951b3
4 changed files with 66 additions and 47 deletions

View File

@@ -31,7 +31,7 @@ pub const IS_DESKTOP: bool = cfg!(any(
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
thread_local! { thread_local! {
/// This makes `Context::create_viewport_sync` to have a native window in the same frame! /// This makes [`Context::show_viewport_immediate`] to have a native window in the same frame!
pub static WINIT_EVENT_LOOP: RefCell<*const EventLoopWindowTarget<UserEvent>> = RefCell::new(std::ptr::null()); pub static WINIT_EVENT_LOOP: RefCell<*const EventLoopWindowTarget<UserEvent>> = RefCell::new(std::ptr::null());
} }
@@ -1171,7 +1171,7 @@ mod glow_integration {
}; };
glutin glutin
.init_window(&win, event_loop) .init_window(&win, event_loop)
.expect("Cannot init window on egui::Context::create_viewport_sync"); .expect("Cannot init window on egui::Context::show_viewport_immediate");
} }
// Rendering the sync viewport // Rendering the sync viewport
@@ -1218,7 +1218,7 @@ mod glow_integration {
.is_current(glutin.current_gl_context.as_ref().unwrap()) .is_current(glutin.current_gl_context.as_ref().unwrap())
{ {
let builder = &&glutin.builders[&window.id_pair.this]; let builder = &&glutin.builders[&window.id_pair.this];
log::error!("egui::create_viewport_sync with title: `{:?}` is not created in main thread, try to use wgpu!", builder.title.clone().unwrap_or_default()); log::error!("egui::show_viewport_immediate with title: `{:?}` is not created in main thread, try to use wgpu!", builder.title.clone().unwrap_or_default());
} }
egui_glow::painter::clear(gl, screen_size_in_pixels, [0.0, 0.0, 0.0, 0.0]); egui_glow::painter::clear(gl, screen_size_in_pixels, [0.0, 0.0, 0.0, 0.0]);

View File

@@ -2525,7 +2525,7 @@ impl Context {
}); });
} }
/// If `true`, [`Self::create_viewport_async`] and [`Self::create_viewport_sync`] will /// If `true`, [`Self::show_viewport`] and [`Self::show_viewport_immediate`] will
/// embed the new viewports as [`crate::Window`]s instead of spawning a new native window. /// embed the new viewports as [`crate::Window`]s instead of spawning a new native window.
/// ///
/// `eframe` sets this to `false` on supported platforms, /// `eframe` sets this to `false` on supported platforms,
@@ -2534,7 +2534,7 @@ impl Context {
self.read(|ctx| ctx.embed_viewports) self.read(|ctx| ctx.embed_viewports)
} }
/// If `true`, [`Self::create_viewport_async`] and [`Self::create_viewport_sync`] will /// If `true`, [`Self::show_viewport`] and [`Self::show_viewport_immediate`] will
/// embed the new viewports as [`crate::Window`]s instead of spawning a new native window. /// embed the new viewports as [`crate::Window`]s instead of spawning a new native window.
/// ///
/// `eframe` sets this to `false` on supported platforms, /// `eframe` sets this to `false` on supported platforms,
@@ -2555,17 +2555,24 @@ impl Context {
/// This creates a new native window, if possible. /// This creates a new native window, if possible.
/// ///
/// You should call this each frame when the viewport should be visible. /// You need to call this each frame when the child viewport should exist.
///
/// The given callback will be called whenever the child viewport needs repainting,
/// e.g. on an event or when [`Self::request_repaint`] is called.
/// This means it may be called multiple times, for instance while the
/// parent viewport (the caller) is sleeping but the child viewport is animating.
/// ///
/// You will need to wrap your viewport state in an `Arc<RwLock<T>>` or `Arc<Mutex<T>>`. /// You will need to wrap your viewport state in an `Arc<RwLock<T>>` or `Arc<Mutex<T>>`.
/// When this is called again with the same id in `ViewportBuilder` the render function for that viewport will be updated. /// When this is called again with the same id in `ViewportBuilder` the render function for that viewport will be updated.
/// * `viewport_ui_cb`: will be called when the viewport receives a event or is requested to be rendered
/// ///
/// If this is no more called that viewport will be destroyed. /// You can also use [`Self::show_viewport_immediate`], which uses a simpler `FnOnce`
/// with no need for `Send` or `Sync`. The downside is that it will require
/// the parent viewport (the caller) to repaint anytime the child is repainted,
/// and vice versa.
/// ///
/// If you use a [`crate::CentralPanel`] you need to check if the viewport is a new window like: /// If you use a [`crate::CentralPanel`] you need to check if the viewport is a new window like:
/// `ctx.viewport_id() != ctx.parent_viewport_id` if false you should create a [`crate::Window`]. /// `ctx.viewport_id() != ctx.parent_viewport_id` if false you should create a [`crate::Window`].
pub fn create_viewport_async( pub fn show_viewport(
&self, &self,
viewport_builder: ViewportBuilder, viewport_builder: ViewportBuilder,
viewport_ui_cb: impl Fn(&Context) + Send + Sync + 'static, viewport_ui_cb: impl Fn(&Context) + Send + Sync + 'static,
@@ -2600,25 +2607,23 @@ impl Context {
/// This creates a new native window, if possible. /// This creates a new native window, if possible.
/// ///
/// You need to call this each frame when the child viewport should exist.
///
/// The given ui function will be called immediately. /// The given ui function will be called immediately.
/// This can only be called from the main thread. /// This may only be called on the main thread.
/// ///
/// If [`Context::embed_viewports`] is true, or if the current egui /// This call will pause the current viewport and render the child viewport in its own window.
/// backend does not support sync viewports, the given callback /// This means that the child viewport will not be repainted when the parent viewport is repainted, and vice versa.
/// will be called immediately and the function will return. /// This can lead to unnecessary repaint.
/// To avoid this, use [`Self::show_viewport`] instead.
/// ///
/// When this is called the current viewport will be paused /// If [`Context::embed_viewports`] is `true` (e.g. if the current egui
/// This will render in a native window if is possible. /// backend does not support multiple viewports), the given callback
/// When this finishes then the last viewport will continue drawing /// will be called immediately, embedding the new viewport in the current one.
/// This is bad for performance but easy to use.
///
/// For better performance use `Self::create_viewport`
///
/// If this is no more called that viewport will be destroyed.
/// ///
/// If you use a `egui::CentralPanel` you need to check if the viewport is a new window like: /// If you use a `egui::CentralPanel` you need to check if the viewport is a new window like:
/// `ctx.viewport_id() != ctx.parent_viewport_id` if false you should create a [`crate::Window`]. /// `ctx.viewport_id() != ctx.parent_viewport_id` if false you should create a [`crate::Window`].
pub fn create_viewport_sync<T>( pub fn show_viewport_immediate<T>(
&self, &self,
viewport_builder: ViewportBuilder, viewport_builder: ViewportBuilder,
viewport_ui_cb: impl FnOnce(&Context) -> T, viewport_ui_cb: impl FnOnce(&Context) -> T,

View File

@@ -1,9 +1,11 @@
//! egui supports multiple viewports, corresponding to multiple native windows. //! egui supports multiple viewports, corresponding to multiple native windows.
//! //!
//! Viewports come in two flavors: "sync" and "async". //! Viewports come in two flavors: "deferred" (the default) and "immediate".
//! //!
//! * Sync viewports are executed immediately. //! * Deferred viewports have callbacks that are called multiple
//! * Async viewports are executed later. //! 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.
use std::sync::Arc; use std::sync::Arc;
@@ -83,7 +85,7 @@ impl ViewportIdPair {
}; };
} }
/// The user-code that shows the ui in the viewport, used for "async" viewports. /// The user-code that shows the ui in the viewport, used for deferred viewports.
pub type ViewportUiCallback = dyn Fn(&Context) + Sync + Send; pub type ViewportUiCallback = dyn Fn(&Context) + Sync + Send;
/// Render the given viewport, calling the given ui callback. /// Render the given viewport, calling the given ui callback.
@@ -655,9 +657,9 @@ pub(crate) struct Viewport {
/// Has this viewport been updated this frame? /// Has this viewport been updated this frame?
pub(crate) used: bool, pub(crate) used: bool,
/// The user-code that shows the GUI, used for "async" viewports. /// The user-code that shows the GUI, used for deferred viewports.
/// ///
/// `None` for "sync" viewports. /// `None` for immediate viewports.
pub(crate) viewport_ui_cb: Option<Arc<Box<ViewportUiCallback>>>, pub(crate) viewport_ui_cb: Option<Arc<Box<ViewportUiCallback>>>,
} }
@@ -668,8 +670,8 @@ pub struct ViewportOutput {
/// Id of us and our parent. /// Id of us and our parent.
pub id_pair: ViewportIdPair, pub id_pair: ViewportIdPair,
/// The user-code that shows the GUI, used for "async" viewports. /// The user-code that shows the GUI, used for deferred viewports.
/// ///
/// `None` for "sync" viewports. /// `None` for immediate viewports.
pub viewport_ui_cb: Option<Arc<Box<ViewportUiCallback>>>, pub viewport_ui_cb: Option<Arc<Box<ViewportUiCallback>>>,
} }

View File

@@ -25,33 +25,33 @@ fn main() {
pub struct ViewportState { pub struct ViewportState {
pub id: ViewportId, pub id: ViewportId,
pub visible: bool, pub visible: bool,
pub sync: bool, pub immediate: bool,
pub title: String, pub title: String,
pub children: Vec<Arc<RwLock<ViewportState>>>, pub children: Vec<Arc<RwLock<ViewportState>>>,
} }
impl ViewportState { impl ViewportState {
pub fn new_async( pub fn new_deferred(
title: &'static str, title: &'static str,
children: Vec<Arc<RwLock<ViewportState>>>, children: Vec<Arc<RwLock<ViewportState>>>,
) -> Arc<RwLock<Self>> { ) -> Arc<RwLock<Self>> {
Arc::new(RwLock::new(Self { Arc::new(RwLock::new(Self {
id: ViewportId::from_hash_of(title), id: ViewportId::from_hash_of(title),
visible: false, visible: false,
sync: false, immediate: false,
title: title.into(), title: title.into(),
children, children,
})) }))
} }
pub fn new_sync( pub fn new_immediate(
title: &'static str, title: &'static str,
children: Vec<Arc<RwLock<ViewportState>>>, children: Vec<Arc<RwLock<ViewportState>>>,
) -> Arc<RwLock<Self>> { ) -> Arc<RwLock<Self>> {
Arc::new(RwLock::new(Self { Arc::new(RwLock::new(Self {
id: ViewportId::from_hash_of(title), id: ViewportId::from_hash_of(title),
visible: false, visible: false,
sync: true, immediate: true,
title: title.into(), title: title.into(),
children, children,
})) }))
@@ -62,23 +62,23 @@ impl ViewportState {
return; return;
} }
let vp_id = vp_state.read().id; let vp_id = vp_state.read().id;
let sync = vp_state.read().sync; let immediate = vp_state.read().immediate;
let title = vp_state.read().title.clone(); let title = vp_state.read().title.clone();
let vp_builder = ViewportBuilder::new(vp_id) let vp_builder = ViewportBuilder::new(vp_id)
.with_title(&title) .with_title(&title)
.with_inner_size(Some(egui::vec2(450.0, 400.0))); .with_inner_size(Some(egui::vec2(450.0, 400.0)));
if sync { if immediate {
let mut vp_state = vp_state.write(); let mut vp_state = vp_state.write();
ctx.create_viewport_sync(vp_builder, move |ctx| { ctx.show_viewport_immediate(vp_builder, move |ctx| {
show_as_popup(ctx, &title, vp_id.into(), |ui: &mut egui::Ui| { show_as_popup(ctx, &title, vp_id.into(), |ui: &mut egui::Ui| {
generic_child_ui(ui, &mut vp_state); generic_child_ui(ui, &mut vp_state);
}); });
}); });
} else { } else {
let count = Arc::new(RwLock::new(0)); let count = Arc::new(RwLock::new(0));
ctx.create_viewport_async(vp_builder, move |ctx| { ctx.show_viewport(vp_builder, move |ctx| {
let mut vp_state = vp_state.write(); let mut vp_state = vp_state.write();
let count = count.clone(); let count = count.clone();
show_as_popup(ctx, &title, vp_id.into(), move |ui: &mut egui::Ui| { show_as_popup(ctx, &title, vp_id.into(), move |ui: &mut egui::Ui| {
@@ -101,18 +101,30 @@ impl Default for App {
fn default() -> Self { fn default() -> Self {
Self { Self {
top: vec![ top: vec![
ViewportState::new_async( ViewportState::new_deferred(
"Top Async Viewport", "Top Deferred Viewport",
vec![ vec![
ViewportState::new_async("AA: Async Viewport in Async Viewport", vec![]), ViewportState::new_deferred(
ViewportState::new_sync("AS: Sync Viewport in Async Viewport", vec![]), "DD: Deferred Viewport in Deferred Viewport",
vec![],
),
ViewportState::new_immediate(
"DS: Immediate Viewport in Deferred Viewport",
vec![],
),
], ],
), ),
ViewportState::new_sync( ViewportState::new_immediate(
"Top Sync Viewport", "Top Immediate Viewport",
vec![ vec![
ViewportState::new_async("SA: Async Viewport in Sync Viewport", vec![]), ViewportState::new_deferred(
ViewportState::new_sync("SS: Sync Viewport in Sync Viewport", vec![]), "SD: Deferred Viewport in Immediate Viewport",
vec![],
),
ViewportState::new_immediate(
"SS: Immediate Viewport in Immediate Viewport",
vec![],
),
], ],
), ),
], ],