mirror of
https://github.com/emilk/egui.git
synced 2026-09-03 15:20:05 -04:00
Classify viewports using enum ViewportClass
This commit is contained in:
@@ -4,7 +4,7 @@ use winit::event_loop::EventLoopWindowTarget;
|
|||||||
|
|
||||||
use raw_window_handle::{HasRawDisplayHandle as _, HasRawWindowHandle as _};
|
use raw_window_handle::{HasRawDisplayHandle as _, HasRawWindowHandle as _};
|
||||||
|
|
||||||
use egui::{NumExt as _, ViewportBuilder, ViewportId, ViewportIdPair, ViewportUiCallback};
|
use egui::{DeferredViewportUiCallback, NumExt as _, ViewportBuilder, ViewportId, ViewportIdPair};
|
||||||
use egui_winit::{native_pixels_per_point, EventResponse, WindowSettings};
|
use egui_winit::{native_pixels_per_point, EventResponse, WindowSettings};
|
||||||
|
|
||||||
use crate::{epi, Theme, WindowInfo};
|
use crate::{epi, Theme, WindowInfo};
|
||||||
@@ -501,7 +501,7 @@ impl EpiIntegration {
|
|||||||
pub fn update(
|
pub fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
app: &mut dyn epi::App,
|
app: &mut dyn epi::App,
|
||||||
viewport_ui_cb: Option<&ViewportUiCallback>,
|
viewport_ui_cb: Option<&DeferredViewportUiCallback>,
|
||||||
mut raw_input: egui::RawInput,
|
mut raw_input: egui::RawInput,
|
||||||
) -> egui::FullOutput {
|
) -> egui::FullOutput {
|
||||||
raw_input.time = Some(self.beginning.elapsed().as_secs_f64());
|
raw_input.time = Some(self.beginning.elapsed().as_secs_f64());
|
||||||
|
|||||||
@@ -457,8 +457,8 @@ mod glow_integration {
|
|||||||
};
|
};
|
||||||
|
|
||||||
use egui::{
|
use egui::{
|
||||||
epaint::ahash::HashMap, ImmediateViewport, NumExt as _, ViewportIdMap, ViewportIdPair,
|
epaint::ahash::HashMap, DeferredViewportUiCallback, ImmediateViewport, NumExt as _,
|
||||||
ViewportIdSet, ViewportOutput, ViewportUiCallback,
|
ViewportClass, ViewportIdMap, ViewportIdPair, ViewportIdSet, ViewportOutput,
|
||||||
};
|
};
|
||||||
use egui_winit::{create_winit_window_builder, process_viewport_commands, EventResponse};
|
use egui_winit::{create_winit_window_builder, process_viewport_commands, EventResponse};
|
||||||
|
|
||||||
@@ -781,11 +781,12 @@ mod glow_integration {
|
|||||||
|
|
||||||
struct Viewport {
|
struct Viewport {
|
||||||
ids: ViewportIdPair,
|
ids: ViewportIdPair,
|
||||||
|
class: ViewportClass,
|
||||||
builder: ViewportBuilder,
|
builder: ViewportBuilder,
|
||||||
|
|
||||||
/// The user-callback that shows the ui.
|
/// The user-callback that shows the ui.
|
||||||
/// None for immediate viewports.
|
/// None for immediate viewports.
|
||||||
viewport_ui_cb: Option<Arc<ViewportUiCallback>>,
|
viewport_ui_cb: Option<Arc<DeferredViewportUiCallback>>,
|
||||||
|
|
||||||
gl_surface: Option<glutin::surface::Surface<glutin::surface::WindowSurface>>,
|
gl_surface: Option<glutin::surface::Surface<glutin::surface::WindowSurface>>,
|
||||||
window: Option<Rc<Window>>,
|
window: Option<Rc<Window>>,
|
||||||
@@ -944,6 +945,7 @@ mod glow_integration {
|
|||||||
ViewportId::ROOT,
|
ViewportId::ROOT,
|
||||||
Viewport {
|
Viewport {
|
||||||
ids: ViewportIdPair::ROOT,
|
ids: ViewportIdPair::ROOT,
|
||||||
|
class: ViewportClass::Root,
|
||||||
builder: viewport_builder,
|
builder: viewport_builder,
|
||||||
viewport_ui_cb: None,
|
viewport_ui_cb: None,
|
||||||
gl_surface: None,
|
gl_surface: None,
|
||||||
@@ -1166,6 +1168,7 @@ mod glow_integration {
|
|||||||
viewport_id,
|
viewport_id,
|
||||||
ViewportOutput {
|
ViewportOutput {
|
||||||
parent,
|
parent,
|
||||||
|
class,
|
||||||
builder,
|
builder,
|
||||||
viewport_ui_cb,
|
viewport_ui_cb,
|
||||||
commands,
|
commands,
|
||||||
@@ -1178,6 +1181,7 @@ mod glow_integration {
|
|||||||
initialize_or_update_viewport(
|
initialize_or_update_viewport(
|
||||||
&mut self.viewports,
|
&mut self.viewports,
|
||||||
ids,
|
ids,
|
||||||
|
class,
|
||||||
builder,
|
builder,
|
||||||
viewport_ui_cb,
|
viewport_ui_cb,
|
||||||
focused_viewport,
|
focused_viewport,
|
||||||
@@ -1208,6 +1212,7 @@ mod glow_integration {
|
|||||||
fn initialize_or_update_viewport(
|
fn initialize_or_update_viewport(
|
||||||
viewports: &mut ViewportIdMap<Viewport>,
|
viewports: &mut ViewportIdMap<Viewport>,
|
||||||
ids: ViewportIdPair,
|
ids: ViewportIdPair,
|
||||||
|
class: ViewportClass,
|
||||||
mut builder: ViewportBuilder,
|
mut builder: ViewportBuilder,
|
||||||
viewport_ui_cb: Option<Arc<dyn Fn(&egui::Context) + Send + Sync>>,
|
viewport_ui_cb: Option<Arc<dyn Fn(&egui::Context) + Send + Sync>>,
|
||||||
focused_viewport: Option<ViewportId>,
|
focused_viewport: Option<ViewportId>,
|
||||||
@@ -1227,6 +1232,7 @@ mod glow_integration {
|
|||||||
log::debug!("Creating new viewport {:?} ({:?})", ids.this, builder.title);
|
log::debug!("Creating new viewport {:?} ({:?})", ids.this, builder.title);
|
||||||
entry.insert(Viewport {
|
entry.insert(Viewport {
|
||||||
ids,
|
ids,
|
||||||
|
class,
|
||||||
builder,
|
builder,
|
||||||
viewport_ui_cb,
|
viewport_ui_cb,
|
||||||
window: None,
|
window: None,
|
||||||
@@ -1240,6 +1246,7 @@ mod glow_integration {
|
|||||||
let viewport = entry.get_mut();
|
let viewport = entry.get_mut();
|
||||||
|
|
||||||
viewport.ids.parent = ids.parent;
|
viewport.ids.parent = ids.parent;
|
||||||
|
viewport.class = class;
|
||||||
viewport.viewport_ui_cb = viewport_ui_cb;
|
viewport.viewport_ui_cb = viewport_ui_cb;
|
||||||
|
|
||||||
let (delta_commands, recreate) = viewport.builder.patch(&builder);
|
let (delta_commands, recreate) = viewport.builder.patch(&builder);
|
||||||
@@ -1519,8 +1526,14 @@ mod glow_integration {
|
|||||||
{
|
{
|
||||||
let mut glutin = glutin.borrow_mut();
|
let mut glutin = glutin.borrow_mut();
|
||||||
|
|
||||||
let viewport =
|
let viewport = initialize_or_update_viewport(
|
||||||
initialize_or_update_viewport(&mut glutin.viewports, ids, builder, None, None);
|
&mut glutin.viewports,
|
||||||
|
ids,
|
||||||
|
ViewportClass::Immediate,
|
||||||
|
builder,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
if viewport.gl_surface.is_none() {
|
if viewport.gl_surface.is_none() {
|
||||||
glutin.init_viewport(ids.this, event_loop).expect(
|
glutin.init_viewport(ids.this, event_loop).expect(
|
||||||
@@ -1799,8 +1812,8 @@ mod wgpu_integration {
|
|||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
use egui::{
|
use egui::{
|
||||||
FullOutput, ImmediateViewport, ViewportIdMap, ViewportIdPair, ViewportIdSet,
|
DeferredViewportUiCallback, FullOutput, ImmediateViewport, ViewportClass, ViewportIdMap,
|
||||||
ViewportOutput, ViewportUiCallback,
|
ViewportIdPair, ViewportIdSet, ViewportOutput,
|
||||||
};
|
};
|
||||||
use egui_winit::{create_winit_window_builder, process_viewport_commands};
|
use egui_winit::{create_winit_window_builder, process_viewport_commands};
|
||||||
|
|
||||||
@@ -1809,10 +1822,12 @@ mod wgpu_integration {
|
|||||||
pub struct Viewport {
|
pub struct Viewport {
|
||||||
ids: ViewportIdPair,
|
ids: ViewportIdPair,
|
||||||
|
|
||||||
|
class: ViewportClass,
|
||||||
|
|
||||||
builder: ViewportBuilder,
|
builder: ViewportBuilder,
|
||||||
|
|
||||||
/// `None` for sync viewports.
|
/// `None` for sync viewports.
|
||||||
viewport_ui_cb: Option<Arc<ViewportUiCallback>>,
|
viewport_ui_cb: Option<Arc<DeferredViewportUiCallback>>,
|
||||||
|
|
||||||
/// Window surface state that's initialized when the app starts running via a Resumed event
|
/// Window surface state that's initialized when the app starts running via a Resumed event
|
||||||
/// and on Android will also be destroyed if the application is paused.
|
/// and on Android will also be destroyed if the application is paused.
|
||||||
@@ -2049,6 +2064,7 @@ mod wgpu_integration {
|
|||||||
ViewportId::ROOT,
|
ViewportId::ROOT,
|
||||||
Viewport {
|
Viewport {
|
||||||
ids: ViewportIdPair::ROOT,
|
ids: ViewportIdPair::ROOT,
|
||||||
|
class: ViewportClass::Root,
|
||||||
builder,
|
builder,
|
||||||
viewport_ui_cb: None,
|
viewport_ui_cb: None,
|
||||||
window: Some(Rc::new(window)),
|
window: Some(Rc::new(window)),
|
||||||
@@ -2139,7 +2155,14 @@ mod wgpu_integration {
|
|||||||
painter,
|
painter,
|
||||||
viewport_from_window,
|
viewport_from_window,
|
||||||
} = &mut *shared.borrow_mut();
|
} = &mut *shared.borrow_mut();
|
||||||
let viewport = initialize_or_update_viewport(viewports, ids, builder, None, None);
|
let viewport = initialize_or_update_viewport(
|
||||||
|
viewports,
|
||||||
|
ids,
|
||||||
|
ViewportClass::Immediate,
|
||||||
|
builder,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
if viewport.window.is_none() {
|
if viewport.window.is_none() {
|
||||||
viewport.init_window(viewport_from_window, painter, event_loop);
|
viewport.init_window(viewport_from_window, painter, event_loop);
|
||||||
@@ -2676,6 +2699,7 @@ mod wgpu_integration {
|
|||||||
viewport_id,
|
viewport_id,
|
||||||
ViewportOutput {
|
ViewportOutput {
|
||||||
parent,
|
parent,
|
||||||
|
class,
|
||||||
builder,
|
builder,
|
||||||
viewport_ui_cb,
|
viewport_ui_cb,
|
||||||
commands,
|
commands,
|
||||||
@@ -2688,6 +2712,7 @@ mod wgpu_integration {
|
|||||||
initialize_or_update_viewport(
|
initialize_or_update_viewport(
|
||||||
viewports,
|
viewports,
|
||||||
ids,
|
ids,
|
||||||
|
class,
|
||||||
builder,
|
builder,
|
||||||
viewport_ui_cb,
|
viewport_ui_cb,
|
||||||
focused_viewport,
|
focused_viewport,
|
||||||
@@ -2706,6 +2731,7 @@ mod wgpu_integration {
|
|||||||
fn initialize_or_update_viewport(
|
fn initialize_or_update_viewport(
|
||||||
viewports: &mut Viewports,
|
viewports: &mut Viewports,
|
||||||
ids: ViewportIdPair,
|
ids: ViewportIdPair,
|
||||||
|
class: ViewportClass,
|
||||||
mut builder: ViewportBuilder,
|
mut builder: ViewportBuilder,
|
||||||
viewport_ui_cb: Option<Arc<dyn Fn(&egui::Context) + Send + Sync>>,
|
viewport_ui_cb: Option<Arc<dyn Fn(&egui::Context) + Send + Sync>>,
|
||||||
focused_viewport: Option<ViewportId>,
|
focused_viewport: Option<ViewportId>,
|
||||||
@@ -2723,6 +2749,7 @@ mod wgpu_integration {
|
|||||||
log::debug!("Creating new viewport {:?} ({:?})", ids.this, builder.title);
|
log::debug!("Creating new viewport {:?} ({:?})", ids.this, builder.title);
|
||||||
entry.insert(Viewport {
|
entry.insert(Viewport {
|
||||||
ids,
|
ids,
|
||||||
|
class,
|
||||||
builder,
|
builder,
|
||||||
viewport_ui_cb,
|
viewport_ui_cb,
|
||||||
window: None,
|
window: None,
|
||||||
@@ -2734,6 +2761,7 @@ mod wgpu_integration {
|
|||||||
// Patch an existing viewport:
|
// Patch an existing viewport:
|
||||||
let viewport = entry.get_mut();
|
let viewport = entry.get_mut();
|
||||||
|
|
||||||
|
viewport.class = class;
|
||||||
viewport.ids.parent = ids.parent;
|
viewport.ids.parent = ids.parent;
|
||||||
viewport.viewport_ui_cb = viewport_ui_cb;
|
viewport.viewport_ui_cb = viewport_ui_cb;
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ use crate::{
|
|||||||
os::OperatingSystem,
|
os::OperatingSystem,
|
||||||
output::FullOutput,
|
output::FullOutput,
|
||||||
util::IdTypeMap,
|
util::IdTypeMap,
|
||||||
|
viewport::ViewportClass,
|
||||||
TextureHandle, ViewportCommand, *,
|
TextureHandle, ViewportCommand, *,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -114,13 +115,19 @@ impl ContextImpl {
|
|||||||
/// State stored per viewport
|
/// State stored per viewport
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct ViewportState {
|
struct ViewportState {
|
||||||
|
/// The type of viewport.
|
||||||
|
///
|
||||||
|
/// This will never be [`ViewportClass::Embedded`],
|
||||||
|
/// since those don't result in real viewports.
|
||||||
|
class: ViewportClass,
|
||||||
|
|
||||||
/// The latest delta
|
/// The latest delta
|
||||||
builder: ViewportBuilder,
|
builder: ViewportBuilder,
|
||||||
|
|
||||||
/// The user-code that shows the GUI, used for deferred viewports.
|
/// The user-code that shows the GUI, used for deferred viewports.
|
||||||
///
|
///
|
||||||
/// `None` for immediate viewports.
|
/// `None` for immediate viewports.
|
||||||
viewport_ui_cb: Option<Arc<ViewportUiCallback>>,
|
viewport_ui_cb: Option<Arc<DeferredViewportUiCallback>>,
|
||||||
|
|
||||||
input: InputState,
|
input: InputState,
|
||||||
|
|
||||||
@@ -1609,6 +1616,7 @@ impl ContextImpl {
|
|||||||
id,
|
id,
|
||||||
ViewportOutput {
|
ViewportOutput {
|
||||||
parent,
|
parent,
|
||||||
|
class: viewport.class,
|
||||||
builder: viewport.builder.clone(),
|
builder: viewport.builder.clone(),
|
||||||
viewport_ui_cb: viewport.viewport_ui_cb.clone(),
|
viewport_ui_cb: viewport.viewport_ui_cb.clone(),
|
||||||
commands,
|
commands,
|
||||||
@@ -2577,68 +2585,75 @@ impl Context {
|
|||||||
/// the parent viewport (the caller) to repaint anytime the child is repainted,
|
/// the parent viewport (the caller) to repaint anytime the child is repainted,
|
||||||
/// and vice versa.
|
/// and vice versa.
|
||||||
///
|
///
|
||||||
/// If you use a [`crate::CentralPanel`] you need to check if the viewport is a new window like:
|
/// If [`Context::embed_viewports`] is `true` (e.g. if the current egui
|
||||||
/// `ctx.viewport_id() != ctx.parent_viewport_id` if false you should create a [`crate::Window`].
|
/// 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.
|
||||||
pub fn show_viewport(
|
pub fn show_viewport(
|
||||||
&self,
|
&self,
|
||||||
new_viewport_id: ViewportId,
|
new_viewport_id: ViewportId,
|
||||||
viewport_builder: ViewportBuilder,
|
viewport_builder: ViewportBuilder,
|
||||||
viewport_ui_cb: impl Fn(&Context) + Send + Sync + 'static,
|
viewport_ui_cb: impl Fn(&Context, ViewportClass) + Send + Sync + 'static,
|
||||||
) {
|
) {
|
||||||
crate::profile_function!();
|
crate::profile_function!();
|
||||||
|
|
||||||
if self.embed_viewports() {
|
if self.embed_viewports() {
|
||||||
viewport_ui_cb(self);
|
viewport_ui_cb(self, ViewportClass::Embedded);
|
||||||
} else {
|
} else {
|
||||||
self.write(|ctx| {
|
self.write(|ctx| {
|
||||||
ctx.viewport_parents
|
ctx.viewport_parents
|
||||||
.insert(new_viewport_id, ctx.viewport_id());
|
.insert(new_viewport_id, ctx.viewport_id());
|
||||||
|
|
||||||
let mut viewport = ctx.viewports.entry(new_viewport_id).or_default();
|
let mut viewport = ctx.viewports.entry(new_viewport_id).or_default();
|
||||||
|
viewport.class = ViewportClass::Deferred;
|
||||||
viewport.builder = viewport_builder;
|
viewport.builder = viewport_builder;
|
||||||
viewport.used = true;
|
viewport.used = true;
|
||||||
viewport.viewport_ui_cb = Some(Arc::new(Box::new(viewport_ui_cb)));
|
viewport.viewport_ui_cb = Some(Arc::new(move |ctx| {
|
||||||
|
(viewport_ui_cb)(ctx, ViewportClass::Deferred);
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This creates a new native window, if possible.
|
/// This creates a new native window, if possible.
|
||||||
///
|
///
|
||||||
|
/// This is the easier type of viewport to use, but it is less performant
|
||||||
|
/// at it requires both parent and child to repaint if any one of them needs repainting,
|
||||||
|
/// which efficvely produce double work for two viewports, and triple work for three viewports, etc.
|
||||||
|
/// To avoid this, use [`Self::show_viewport`] instead.
|
||||||
|
///
|
||||||
/// The given id must be unique for each viewport.
|
/// The given id must be unique for each viewport.
|
||||||
///
|
///
|
||||||
/// You need to call this each frame when the child viewport should exist.
|
/// 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 may only be called on the main thread.
|
/// This may only be called on the main thread.
|
||||||
///
|
|
||||||
/// This call will pause the current viewport and render the child viewport in its own window.
|
/// This call will pause the current viewport and render the child viewport in its own window.
|
||||||
/// This means that the child viewport will not be repainted when the parent viewport is repainted, and vice versa.
|
/// This means that the child viewport will not be repainted when the parent viewport is repainted, and vice versa.
|
||||||
/// This can lead to unnecessary repaint.
|
|
||||||
/// To avoid this, use [`Self::show_viewport`] instead.
|
|
||||||
///
|
///
|
||||||
/// If [`Context::embed_viewports`] is `true` (e.g. if the current egui
|
/// If [`Context::embed_viewports`] is `true` (e.g. if the current egui
|
||||||
/// backend does not support multiple viewports), the given callback
|
/// backend does not support multiple viewports), the given callback
|
||||||
/// will be called immediately, embedding the new viewport in the current one.
|
/// 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 use a `egui::CentralPanel` you need to check if the viewport is a new window like:
|
/// If you find [`ViewportClass::embedded`], you need to create a new [`crate::Window`] for you content.
|
||||||
/// `ctx.viewport_id() != ctx.parent_viewport_id` if false you should create a [`crate::Window`].
|
|
||||||
pub fn show_viewport_immediate<T>(
|
pub fn show_viewport_immediate<T>(
|
||||||
&self,
|
&self,
|
||||||
new_viewport_id: ViewportId,
|
new_viewport_id: ViewportId,
|
||||||
builder: ViewportBuilder,
|
builder: ViewportBuilder,
|
||||||
viewport_ui_cb: impl FnOnce(&Context) -> T,
|
viewport_ui_cb: impl FnOnce(&Context, ViewportClass) -> T,
|
||||||
) -> T {
|
) -> T {
|
||||||
crate::profile_function!();
|
crate::profile_function!();
|
||||||
|
|
||||||
if self.embed_viewports() {
|
if self.embed_viewports() {
|
||||||
return viewport_ui_cb(self);
|
return viewport_ui_cb(self, ViewportClass::Embedded);
|
||||||
}
|
}
|
||||||
|
|
||||||
IMMEDIATE_VIEWPORT_RENDERER.with(|immediate_viewport_renderer| {
|
IMMEDIATE_VIEWPORT_RENDERER.with(|immediate_viewport_renderer| {
|
||||||
let immediate_viewport_renderer = immediate_viewport_renderer.borrow();
|
let immediate_viewport_renderer = immediate_viewport_renderer.borrow();
|
||||||
let Some(immediate_viewport_renderer) = immediate_viewport_renderer.as_ref() else {
|
let Some(immediate_viewport_renderer) = immediate_viewport_renderer.as_ref() else {
|
||||||
// This egui backend does not support multiple viewports.
|
// This egui backend does not support multiple viewports.
|
||||||
return viewport_ui_cb(self);
|
return viewport_ui_cb(self, ViewportClass::Embedded);
|
||||||
};
|
};
|
||||||
|
|
||||||
let ids = self.write(|ctx| {
|
let ids = self.write(|ctx| {
|
||||||
@@ -2662,7 +2677,9 @@ impl Context {
|
|||||||
let viewport = ImmediateViewport {
|
let viewport = ImmediateViewport {
|
||||||
ids,
|
ids,
|
||||||
builder,
|
builder,
|
||||||
viewport_ui_cb: Box::new(move |context| *out = Some(viewport_ui_cb(context))),
|
viewport_ui_cb: Box::new(move |context| {
|
||||||
|
*out = Some(viewport_ui_cb(context, ViewportClass::Immediate));
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
immediate_viewport_renderer(self, viewport);
|
immediate_viewport_renderer(self, viewport);
|
||||||
|
|||||||
@@ -15,6 +15,37 @@ use crate::{Context, Id};
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// The different types of viewports supported by egui.
|
||||||
|
#[derive(Clone, Copy, Default, Hash, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
|
pub enum ViewportClass {
|
||||||
|
/// The root viewport; i.e. the original window.
|
||||||
|
#[default]
|
||||||
|
Root,
|
||||||
|
|
||||||
|
/// A viewport run independently from the parent viewport.
|
||||||
|
///
|
||||||
|
/// This is the preferred type of viewport from a performance perspective.
|
||||||
|
///
|
||||||
|
/// Create these with [`crate::Context::show_viewport`].
|
||||||
|
Deferred,
|
||||||
|
|
||||||
|
/// A viewport run inside the parent viewport.
|
||||||
|
///
|
||||||
|
/// This is the easier type of viewport to use, but it is less performant
|
||||||
|
/// at it requires both parent and child to repaint if any one of them needs repainting,
|
||||||
|
/// which efficvely produce double work for two viewports, and triple work for three viewports, etc.
|
||||||
|
///
|
||||||
|
/// Create these with [`crate::Context::show_viewport_immediate`].
|
||||||
|
Immediate,
|
||||||
|
|
||||||
|
/// The fallback, when the egui integration doesn't support viewports,
|
||||||
|
/// or [`crate::Context::embed_viewports`] is set to `true`.
|
||||||
|
Embedded,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/// A unique identifier of a viewport.
|
/// A unique identifier of a viewport.
|
||||||
///
|
///
|
||||||
/// This is returned by [`Context::viewport_id`] and [`Context::parent_viewport_id`].
|
/// This is returned by [`Context::viewport_id`] and [`Context::parent_viewport_id`].
|
||||||
@@ -91,7 +122,7 @@ impl ViewportIdPair {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The user-code that shows the ui in the viewport, used for deferred 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 DeferredViewportUiCallback = dyn Fn(&Context) + Sync + Send;
|
||||||
|
|
||||||
/// Render the given viewport, calling the given ui callback.
|
/// Render the given viewport, calling the given ui callback.
|
||||||
pub type ImmediateViewportRendererCallback = dyn for<'a> Fn(&Context, ImmediateViewport<'a>);
|
pub type ImmediateViewportRendererCallback = dyn for<'a> Fn(&Context, ImmediateViewport<'a>);
|
||||||
@@ -668,13 +699,19 @@ pub struct ViewportOutput {
|
|||||||
/// Id of our parent viewport.
|
/// Id of our parent viewport.
|
||||||
pub parent: ViewportId,
|
pub parent: ViewportId,
|
||||||
|
|
||||||
|
/// What type of viewport are we?
|
||||||
|
///
|
||||||
|
/// This will never be [`ViewportClass::Embedded`],
|
||||||
|
/// since those don't result in real viewports.
|
||||||
|
pub class: ViewportClass,
|
||||||
|
|
||||||
/// The window attrbiutes such as title, position, size, etc.
|
/// The window attrbiutes such as title, position, size, etc.
|
||||||
pub builder: ViewportBuilder,
|
pub builder: ViewportBuilder,
|
||||||
|
|
||||||
/// The user-code that shows the GUI, used for deferred viewports.
|
/// The user-code that shows the GUI, used for deferred viewports.
|
||||||
///
|
///
|
||||||
/// `None` for immediate viewports and the ROOT viewport.
|
/// `None` for immediate viewports and the ROOT viewport.
|
||||||
pub viewport_ui_cb: Option<Arc<ViewportUiCallback>>,
|
pub viewport_ui_cb: Option<Arc<DeferredViewportUiCallback>>,
|
||||||
|
|
||||||
/// Commands to change the viewport, e.g. window title and size.
|
/// Commands to change the viewport, e.g. window title and size.
|
||||||
pub commands: Vec<ViewportCommand>,
|
pub commands: Vec<ViewportCommand>,
|
||||||
@@ -693,6 +730,7 @@ impl ViewportOutput {
|
|||||||
pub fn append(&mut self, newer: Self) {
|
pub fn append(&mut self, newer: Self) {
|
||||||
let Self {
|
let Self {
|
||||||
parent,
|
parent,
|
||||||
|
class,
|
||||||
builder,
|
builder,
|
||||||
viewport_ui_cb,
|
viewport_ui_cb,
|
||||||
mut commands,
|
mut commands,
|
||||||
@@ -700,6 +738,7 @@ impl ViewportOutput {
|
|||||||
} = newer;
|
} = newer;
|
||||||
|
|
||||||
self.parent = parent;
|
self.parent = parent;
|
||||||
|
self.class = class;
|
||||||
self.builder.patch(&builder);
|
self.builder.patch(&builder);
|
||||||
self.viewport_ui_cb = viewport_ui_cb;
|
self.viewport_ui_cb = viewport_ui_cb;
|
||||||
self.commands.append(&mut commands);
|
self.commands.append(&mut commands);
|
||||||
|
|||||||
@@ -55,10 +55,16 @@ impl eframe::App for MyApp {
|
|||||||
egui::ViewportBuilder::default()
|
egui::ViewportBuilder::default()
|
||||||
.with_title("Immediate Viewport")
|
.with_title("Immediate Viewport")
|
||||||
.with_inner_size([200.0, 100.0]),
|
.with_inner_size([200.0, 100.0]),
|
||||||
|ctx| {
|
|ctx, class| {
|
||||||
|
assert!(
|
||||||
|
class == egui::ViewportClass::Immediate,
|
||||||
|
"This egui backend doesn't support multiple viewports"
|
||||||
|
);
|
||||||
|
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
ui.label("Hello from immediate viewport");
|
ui.label("Hello from immediate viewport");
|
||||||
});
|
});
|
||||||
|
|
||||||
if ctx.input(|i| i.raw.viewport.close_requested) {
|
if ctx.input(|i| i.raw.viewport.close_requested) {
|
||||||
// Tell parent viewport that we should not show next frame:
|
// Tell parent viewport that we should not show next frame:
|
||||||
self.show_immediate_viewport = false;
|
self.show_immediate_viewport = false;
|
||||||
@@ -75,12 +81,17 @@ impl eframe::App for MyApp {
|
|||||||
egui::ViewportBuilder::default()
|
egui::ViewportBuilder::default()
|
||||||
.with_title("Deferred Viewport")
|
.with_title("Deferred Viewport")
|
||||||
.with_inner_size([200.0, 100.0]),
|
.with_inner_size([200.0, 100.0]),
|
||||||
|ctx| {
|
|ctx, class| {
|
||||||
|
assert!(
|
||||||
|
class == egui::ViewportClass::Deferred,
|
||||||
|
"This egui backend doesn't support multiple viewports"
|
||||||
|
);
|
||||||
|
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
ui.label("Hello from deferred viewport");
|
ui.label("Hello from deferred viewport");
|
||||||
});
|
});
|
||||||
if ctx.input(|i| i.raw.viewport.close_requested) {
|
if ctx.input(|i| i.raw.viewport.close_requested) {
|
||||||
// Tell parent to close use
|
// Tell parent to close us.
|
||||||
show_deferred_viewport.store(false, Ordering::Relaxed);
|
show_deferred_viewport.store(false, Ordering::Relaxed);
|
||||||
ctx.request_repaint(); // make sure there is a next frame
|
ctx.request_repaint(); // make sure there is a next frame
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,23 +71,29 @@ impl ViewportState {
|
|||||||
|
|
||||||
if immediate {
|
if immediate {
|
||||||
let mut vp_state = vp_state.write();
|
let mut vp_state = vp_state.write();
|
||||||
ctx.show_viewport_immediate(vp_id, viewport, move |ctx| {
|
ctx.show_viewport_immediate(vp_id, viewport, move |ctx, class| {
|
||||||
show_as_popup(ctx, &title, vp_id.into(), |ui: &mut egui::Ui| {
|
show_as_popup(ctx, class, &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.show_viewport(vp_id, viewport, move |ctx| {
|
ctx.show_viewport(vp_id, viewport, move |ctx, class| {
|
||||||
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,
|
||||||
|
class,
|
||||||
|
&title,
|
||||||
|
vp_id.into(),
|
||||||
|
move |ui: &mut egui::Ui| {
|
||||||
let current_count = *count.read();
|
let current_count = *count.read();
|
||||||
ui.label(format!("Callback has been reused {current_count} times"));
|
ui.label(format!("Callback has been reused {current_count} times"));
|
||||||
*count.write() += 1;
|
*count.write() += 1;
|
||||||
|
|
||||||
generic_child_ui(ui, &mut vp_state);
|
generic_child_ui(ui, &mut vp_state);
|
||||||
});
|
},
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,8 +166,15 @@ impl eframe::App for App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// This will make the content as a popup if cannot has his own native window
|
/// This will make the content as a popup if cannot has his own native window
|
||||||
fn show_as_popup(ctx: &egui::Context, title: &str, id: Id, content: impl FnOnce(&mut egui::Ui)) {
|
fn show_as_popup(
|
||||||
if ctx.viewport_id() == ctx.parent_viewport_id() {
|
ctx: &egui::Context,
|
||||||
|
class: egui::ViewportClass,
|
||||||
|
title: &str,
|
||||||
|
id: Id,
|
||||||
|
content: impl FnOnce(&mut egui::Ui),
|
||||||
|
) {
|
||||||
|
if class == egui::ViewportClass::Embedded {
|
||||||
|
// Not a real viewport
|
||||||
egui::Window::new(title).id(id).show(ctx, content);
|
egui::Window::new(title).id(id).show(ctx, content);
|
||||||
} else {
|
} else {
|
||||||
egui::CentralPanel::default().show(ctx, |ui| ui.push_id(id, content));
|
egui::CentralPanel::default().show(ctx, |ui| ui.push_id(id, content));
|
||||||
|
|||||||
Reference in New Issue
Block a user