mirror of
https://github.com/emilk/egui.git
synced 2026-09-01 22:30:03 -04:00
Show how to close a child viewport in the example
This commit is contained in:
@@ -123,6 +123,7 @@ pub trait App {
|
|||||||
///
|
///
|
||||||
/// This is called for the root viewport ([`egui::ViewportId::ROOT`]).
|
/// This is called for the root viewport ([`egui::ViewportId::ROOT`]).
|
||||||
/// Use [`egui::Context::show_viewport`] to spawn additional viewports (windows).
|
/// Use [`egui::Context::show_viewport`] to spawn additional viewports (windows).
|
||||||
|
/// (A "viewport" in egui means an native OS window).
|
||||||
fn update(&mut self, ctx: &egui::Context, frame: &mut Frame);
|
fn update(&mut self, ctx: &egui::Context, frame: &mut Frame);
|
||||||
|
|
||||||
/// Get a handle to the app.
|
/// Get a handle to the app.
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ pub fn window_builder<E>(
|
|||||||
..
|
..
|
||||||
} = native_options;
|
} = native_options;
|
||||||
|
|
||||||
let mut viewport_builder = egui::ViewportBuilder::ROOT
|
let mut viewport_builder = egui::ViewportBuilder::DEFAULTS
|
||||||
.with_title(title)
|
.with_title(title)
|
||||||
.with_decorations(*decorated)
|
.with_decorations(*decorated)
|
||||||
.with_fullscreen(*fullscreen)
|
.with_fullscreen(*fullscreen)
|
||||||
|
|||||||
@@ -201,18 +201,16 @@ impl State {
|
|||||||
let screen_size_in_pixels = screen_size_in_pixels(window);
|
let screen_size_in_pixels = screen_size_in_pixels(window);
|
||||||
let screen_size_in_points = screen_size_in_pixels / pixels_per_point;
|
let screen_size_in_points = screen_size_in_pixels / pixels_per_point;
|
||||||
|
|
||||||
let getting_info = !window.is_minimized().unwrap_or_else(|| {
|
self.egui_input.screen_rect = (screen_size_in_points.x > 0.0
|
||||||
eprintln!("Cannot determine the Viewport/native window minimized state");
|
&& screen_size_in_points.y > 0.0)
|
||||||
true
|
.then(|| Rect::from_min_size(Pos2::ZERO, screen_size_in_points));
|
||||||
});
|
|
||||||
|
|
||||||
self.egui_input.screen_rect = if getting_info {
|
let has_a_position = match window.is_minimized() {
|
||||||
Some(egui::Rect::from_min_size(Pos2::ZERO, screen_size_in_points))
|
None | Some(true) => false,
|
||||||
} else {
|
Some(false) => true,
|
||||||
None
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let inner_pos_px = if getting_info {
|
let inner_pos_px = if has_a_position {
|
||||||
window
|
window
|
||||||
.inner_position()
|
.inner_position()
|
||||||
.map(|pos| Pos2::new(pos.x as f32, pos.y as f32))
|
.map(|pos| Pos2::new(pos.x as f32, pos.y as f32))
|
||||||
@@ -221,7 +219,7 @@ impl State {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let outer_pos_px = if getting_info {
|
let outer_pos_px = if has_a_position {
|
||||||
window
|
window
|
||||||
.outer_position()
|
.outer_position()
|
||||||
.map(|pos| Pos2::new(pos.x as f32, pos.y as f32))
|
.map(|pos| Pos2::new(pos.x as f32, pos.y as f32))
|
||||||
@@ -230,14 +228,14 @@ impl State {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let inner_size_px = if getting_info {
|
let inner_size_px = if has_a_position {
|
||||||
let size = window.inner_size();
|
let size = window.inner_size();
|
||||||
Some(Vec2::new(size.width as f32, size.height as f32))
|
Some(Vec2::new(size.width as f32, size.height as f32))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let outer_size_px = if getting_info {
|
let outer_size_px = if has_a_position {
|
||||||
let size = window.outer_size();
|
let size = window.outer_size();
|
||||||
Some(Vec2::new(size.width as f32, size.height as f32))
|
Some(Vec2::new(size.width as f32, size.height as f32))
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ pub struct RawInput {
|
|||||||
impl Default for RawInput {
|
impl Default for RawInput {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
viewport: ViewportInfo::default(),
|
||||||
screen_rect: None,
|
screen_rect: None,
|
||||||
pixels_per_point: None,
|
pixels_per_point: None,
|
||||||
max_texture_side: None,
|
max_texture_side: None,
|
||||||
@@ -85,7 +86,6 @@ impl Default for RawInput {
|
|||||||
hovered_files: Default::default(),
|
hovered_files: Default::default(),
|
||||||
dropped_files: Default::default(),
|
dropped_files: Default::default(),
|
||||||
focused: true, // integrations opt into global focus tracking
|
focused: true, // integrations opt into global focus tracking
|
||||||
viewport: ViewportInfo::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,6 +97,7 @@ impl RawInput {
|
|||||||
/// * [`Self::dropped_files`] is moved.
|
/// * [`Self::dropped_files`] is moved.
|
||||||
pub fn take(&mut self) -> RawInput {
|
pub fn take(&mut self) -> RawInput {
|
||||||
RawInput {
|
RawInput {
|
||||||
|
viewport: self.viewport.take(),
|
||||||
screen_rect: self.screen_rect.take(),
|
screen_rect: self.screen_rect.take(),
|
||||||
pixels_per_point: self.pixels_per_point.take(),
|
pixels_per_point: self.pixels_per_point.take(),
|
||||||
max_texture_side: self.max_texture_side.take(),
|
max_texture_side: self.max_texture_side.take(),
|
||||||
@@ -107,13 +108,13 @@ impl RawInput {
|
|||||||
hovered_files: self.hovered_files.clone(),
|
hovered_files: self.hovered_files.clone(),
|
||||||
dropped_files: std::mem::take(&mut self.dropped_files),
|
dropped_files: std::mem::take(&mut self.dropped_files),
|
||||||
focused: self.focused,
|
focused: self.focused,
|
||||||
viewport: self.viewport.take(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add on new input.
|
/// Add on new input.
|
||||||
pub fn append(&mut self, newer: Self) {
|
pub fn append(&mut self, newer: Self) {
|
||||||
let Self {
|
let Self {
|
||||||
|
viewport,
|
||||||
screen_rect,
|
screen_rect,
|
||||||
pixels_per_point,
|
pixels_per_point,
|
||||||
max_texture_side,
|
max_texture_side,
|
||||||
@@ -124,13 +125,12 @@ impl RawInput {
|
|||||||
mut hovered_files,
|
mut hovered_files,
|
||||||
mut dropped_files,
|
mut dropped_files,
|
||||||
focused,
|
focused,
|
||||||
viewport,
|
|
||||||
} = newer;
|
} = newer;
|
||||||
|
|
||||||
|
self.viewport = viewport;
|
||||||
self.screen_rect = screen_rect.or(self.screen_rect);
|
self.screen_rect = screen_rect.or(self.screen_rect);
|
||||||
self.pixels_per_point = pixels_per_point.or(self.pixels_per_point);
|
self.pixels_per_point = pixels_per_point.or(self.pixels_per_point);
|
||||||
self.max_texture_side = max_texture_side.or(self.max_texture_side);
|
self.max_texture_side = max_texture_side.or(self.max_texture_side);
|
||||||
self.viewport = viewport;
|
|
||||||
self.time = time; // use latest time
|
self.time = time; // use latest time
|
||||||
self.predicted_dt = predicted_dt; // use latest dt
|
self.predicted_dt = predicted_dt; // use latest dt
|
||||||
self.modifiers = modifiers; // use latest
|
self.modifiers = modifiers; // use latest
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ pub struct Memory {
|
|||||||
#[cfg_attr(feature = "persistence", serde(skip))]
|
#[cfg_attr(feature = "persistence", serde(skip))]
|
||||||
pub(crate) new_font_definitions: Option<epaint::text::FontDefinitions>,
|
pub(crate) new_font_definitions: Option<epaint::text::FontDefinitions>,
|
||||||
|
|
||||||
// Current viewport
|
// Current active viewport
|
||||||
#[cfg_attr(feature = "persistence", serde(skip))]
|
#[cfg_attr(feature = "persistence", serde(skip))]
|
||||||
pub(crate) viewport_id: ViewportId,
|
pub(crate) viewport_id: ViewportId,
|
||||||
|
|
||||||
@@ -96,7 +96,6 @@ pub struct Memory {
|
|||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
// Per-viewport:
|
// Per-viewport:
|
||||||
#[cfg_attr(feature = "persistence", serde(skip))]
|
|
||||||
areas: ViewportIdMap<Areas>,
|
areas: ViewportIdMap<Areas>,
|
||||||
|
|
||||||
#[cfg_attr(feature = "persistence", serde(skip))]
|
#[cfg_attr(feature = "persistence", serde(skip))]
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ pub struct ViewportBuilder {
|
|||||||
|
|
||||||
impl ViewportBuilder {
|
impl ViewportBuilder {
|
||||||
/// Default settings for the root viewport.
|
/// Default settings for the root viewport.
|
||||||
pub const ROOT: Self = Self {
|
pub const DEFAULTS: Self = Self {
|
||||||
title: None,
|
title: None,
|
||||||
name: None,
|
name: None,
|
||||||
position: None,
|
position: None,
|
||||||
@@ -154,18 +154,12 @@ impl ViewportBuilder {
|
|||||||
min_inner_size: None,
|
min_inner_size: None,
|
||||||
max_inner_size: None,
|
max_inner_size: None,
|
||||||
drag_and_drop: Some(true),
|
drag_and_drop: Some(true),
|
||||||
close_button: Some(false), // We disable the close button by default because we haven't implemented closing of child viewports yet
|
close_button: Some(true),
|
||||||
minimize_button: Some(true),
|
minimize_button: Some(true),
|
||||||
maximize_button: Some(true),
|
maximize_button: Some(true),
|
||||||
hittest: Some(true),
|
hittest: Some(true),
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Default settings for a new child viewport.
|
|
||||||
pub const CHILD: Self = Self {
|
|
||||||
close_button: Some(false), // We disable the close button by default because we haven't implemented closing of child viewports yet
|
|
||||||
..Self::ROOT
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Empty settings for everything.
|
/// Empty settings for everything.
|
||||||
///
|
///
|
||||||
/// If used the first frame, backend-specific defaults will be used.
|
/// If used the first frame, backend-specific defaults will be used.
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||||
|
|
||||||
|
use std::sync::{
|
||||||
|
atomic::{AtomicBool, Ordering},
|
||||||
|
Arc,
|
||||||
|
};
|
||||||
|
|
||||||
use eframe::egui;
|
use eframe::egui;
|
||||||
|
|
||||||
fn main() -> Result<(), eframe::Error> {
|
fn main() -> Result<(), eframe::Error> {
|
||||||
@@ -9,7 +14,7 @@ fn main() -> Result<(), eframe::Error> {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
eframe::run_native(
|
eframe::run_native(
|
||||||
"Confirm exit",
|
"Multiple viewports",
|
||||||
options,
|
options,
|
||||||
Box::new(|_cc| Box::<MyApp>::default()),
|
Box::new(|_cc| Box::<MyApp>::default()),
|
||||||
)
|
)
|
||||||
@@ -17,7 +22,15 @@ fn main() -> Result<(), eframe::Error> {
|
|||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct MyApp {
|
struct MyApp {
|
||||||
show_child_viewport: bool,
|
/// Immediate viewports are show immediately, so passing state to/from them is easy.
|
||||||
|
/// The downside is that their painting is linked with the parent viewport:
|
||||||
|
/// if either needs repainting, they are both repainted.
|
||||||
|
show_immediate_viewport: bool,
|
||||||
|
|
||||||
|
/// Deferred viewports run independant of the parent viewport, which can save
|
||||||
|
/// CPU if only some of the viewports require repainting.
|
||||||
|
/// However, this requires passing state with `Arc` and locks.
|
||||||
|
show_deferred_viewport: Arc<AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl eframe::App for MyApp {
|
impl eframe::App for MyApp {
|
||||||
@@ -25,17 +38,48 @@ impl eframe::App for MyApp {
|
|||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
ui.label("Hello from the root viewport");
|
ui.label("Hello from the root viewport");
|
||||||
|
|
||||||
ui.checkbox(&mut self.show_child_viewport, "Show secondary viewport");
|
ui.checkbox(
|
||||||
|
&mut self.show_immediate_viewport,
|
||||||
|
"Show immediate child viewport",
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut show_deferred_viewport = self.show_deferred_viewport.load(Ordering::Relaxed);
|
||||||
|
ui.checkbox(&mut show_deferred_viewport, "Show deferred child viewport");
|
||||||
|
self.show_deferred_viewport
|
||||||
|
.store(show_deferred_viewport, Ordering::Relaxed);
|
||||||
});
|
});
|
||||||
|
|
||||||
if self.show_child_viewport {
|
if self.show_immediate_viewport {
|
||||||
ctx.show_viewport(
|
ctx.show_viewport_immediate(
|
||||||
egui::ViewportId::from_hash_of("secondary_viewport"),
|
egui::ViewportId::from_hash_of("immediate_viewport"),
|
||||||
egui::ViewportBuilder::CHILD.with_title("Secondary Viewport"),
|
egui::ViewportBuilder::DEFAULTS.with_title("Immediate Viewport"),
|
||||||
|ctx| {
|
|ctx| {
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
ui.label("Hello from secondary viewport");
|
ui.label("Hello from immediate viewport");
|
||||||
});
|
});
|
||||||
|
if ctx.input(|i| i.raw.viewport.close_requested) {
|
||||||
|
// Tell parent viewport that we should not show next frame:
|
||||||
|
self.show_immediate_viewport = false;
|
||||||
|
ctx.request_repaint(); // make sure there is a next frame
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.show_deferred_viewport.load(Ordering::Relaxed) {
|
||||||
|
let show_deferred_viewport = self.show_deferred_viewport.clone();
|
||||||
|
ctx.show_viewport_immediate(
|
||||||
|
egui::ViewportId::from_hash_of("deferred_viewport"),
|
||||||
|
egui::ViewportBuilder::DEFAULTS.with_title("Deferred Viewport"),
|
||||||
|
|ctx| {
|
||||||
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
|
ui.label("Hello from deferred viewport");
|
||||||
|
});
|
||||||
|
if ctx.input(|i| i.raw.viewport.close_requested) {
|
||||||
|
// Tell parent to close use
|
||||||
|
show_deferred_viewport.store(false, Ordering::Relaxed);
|
||||||
|
ctx.request_repaint(); // make sure there is a next frame
|
||||||
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ impl ViewportState {
|
|||||||
let immediate = vp_state.read().immediate;
|
let immediate = vp_state.read().immediate;
|
||||||
let title = vp_state.read().title.clone();
|
let title = vp_state.read().title.clone();
|
||||||
|
|
||||||
let viewport = ViewportBuilder::ROOT
|
let viewport = ViewportBuilder::DEFAULTS
|
||||||
.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)));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user