diff --git a/crates/eframe/src/native/epi_integration.rs b/crates/eframe/src/native/epi_integration.rs index 80387dbdb..19f69bb78 100644 --- a/crates/eframe/src/native/epi_integration.rs +++ b/crates/eframe/src/native/epi_integration.rs @@ -85,7 +85,7 @@ pub fn window_builder( .. } = native_options; - let mut viewport_builder = egui::ViewportBuilder::DEFAULTS + let mut viewport_builder = egui::ViewportBuilder::default() .with_title(title) .with_decorations(*decorated) .with_fullscreen(*fullscreen) diff --git a/crates/egui-winit/src/lib.rs b/crates/egui-winit/src/lib.rs index e11d3b382..bae86c266 100644 --- a/crates/egui-winit/src/lib.rs +++ b/crates/egui-winit/src/lib.rs @@ -1005,8 +1005,9 @@ pub fn process_viewport_commands( egui::ViewportCommand::StartDrag => { // if this is not checked on x11 the input will be permanently taken until the app is killed! if is_viewport_focused { - // TODO possible return the error to `egui::Context` - let _ = window.drag_window(); + if let Err(err) = window.drag_window() { + log::warn!("{command:?}: {err}"); + } } } egui::ViewportCommand::InnerSize(size) => { @@ -1014,23 +1015,18 @@ pub fn process_viewport_commands( let height = size.y.max(1.0); window.set_inner_size(LogicalSize::new(width, height)); } - egui::ViewportCommand::BeginResize { - top, - bottom, - right, - left, - } => { - // TODO posibile return the error to `egui::Context` - let _ = window.drag_resize_window(match (top, bottom, right, left) { - (true, false, false, false) => ResizeDirection::North, - (false, true, false, false) => ResizeDirection::South, - (false, false, false, true) => ResizeDirection::West, - (true, false, true, false) => ResizeDirection::NorthEast, - (false, true, true, false) => ResizeDirection::SouthEast, - (true, false, false, true) => ResizeDirection::NorthWest, - (false, true, false, true) => ResizeDirection::SouthWest, - _ => ResizeDirection::East, - }); + egui::ViewportCommand::BeginResize(direction) => { + if let Err(err) = window.drag_resize_window(match direction { + egui::viewport::ResizeDirection::North => ResizeDirection::North, + egui::viewport::ResizeDirection::South => ResizeDirection::South, + egui::viewport::ResizeDirection::West => ResizeDirection::West, + egui::viewport::ResizeDirection::NorthEast => ResizeDirection::NorthEast, + egui::viewport::ResizeDirection::SouthEast => ResizeDirection::SouthEast, + egui::viewport::ResizeDirection::NorthWest => ResizeDirection::NorthWest, + egui::viewport::ResizeDirection::SouthWest => ResizeDirection::SouthWest, + }) { + log::warn!("{command:?}: {err}"); + } } ViewportCommand::Title(title) => window.set_title(&title), ViewportCommand::Transparent(v) => window.set_transparent(v), @@ -1115,7 +1111,7 @@ pub fn process_viewport_commands( ViewportCommand::ContentProtected(v) => window.set_content_protected(v), ViewportCommand::CursorPosition(pos) => { if let Err(err) = window.set_cursor_position(LogicalPosition::new(pos.x, pos.y)) { - log::error!("{err}"); + log::warn!("{command:?}: {err}"); } } ViewportCommand::CursorGrab(o) => { @@ -1124,13 +1120,13 @@ pub fn process_viewport_commands( egui::viewport::CursorGrab::Confined => CursorGrabMode::Confined, egui::viewport::CursorGrab::Locked => CursorGrabMode::Locked, }) { - log::error!("{err}"); + log::warn!("{command:?}: {err}"); } } ViewportCommand::CursorVisible(v) => window.set_cursor_visible(v), ViewportCommand::CursorHitTest(v) => { if let Err(err) = window.set_cursor_hittest(v) { - log::error!("Setting viewport CursorHitTest: {err}"); + log::warn!("{command:?}: {err}"); } } } @@ -1157,21 +1153,20 @@ pub fn create_winit_window_builder(builder: &ViewportBuilder) -> winit::window:: .fullscreen .and_then(|e| e.then_some(winit::window::Fullscreen::Borderless(None))), ) - .with_enabled_buttons( - builder - .minimize_button - .and_then(|v| v.then_some(WindowButtons::MINIMIZE)) - .unwrap_or(WindowButtons::empty()) - | builder - .maximize_button - .and_then(|v| v.then_some(WindowButtons::MAXIMIZE)) - .unwrap_or(WindowButtons::empty()) - | builder - .close_button - .and_then(|v| v.then_some(WindowButtons::CLOSE)) - .unwrap_or(WindowButtons::empty()), - ) - .with_active(builder.active.map_or(false, |e| e)); + .with_enabled_buttons({ + let mut buttons = WindowButtons::empty(); + if builder.minimize_button.unwrap_or(true) { + buttons |= WindowButtons::MINIMIZE; + } + if builder.maximize_button.unwrap_or(true) { + buttons |= WindowButtons::MAXIMIZE; + } + if builder.close_button.unwrap_or(true) { + buttons |= WindowButtons::CLOSE; + } + buttons + }) + .with_active(builder.active.unwrap_or(true)); if let Some(Some(inner_size)) = builder.inner_size { window_builder = window_builder @@ -1222,7 +1217,7 @@ pub fn create_winit_window_builder(builder: &ViewportBuilder) -> winit::window:: #[cfg(target_os = "macos")] { - use winit::platform::macos::WindowBuilderExtMacOS; + use winit::platform::macos::WindowBuilderExtMacOS as _; window_builder = window_builder .with_title_hidden(builder.title_hidden.unwrap_or(false)) .with_titlebar_transparent(builder.titlebar_transparent.unwrap_or(false)) diff --git a/crates/egui/src/data/input.rs b/crates/egui/src/data/input.rs index 1debee8f5..b08732536 100644 --- a/crates/egui/src/data/input.rs +++ b/crates/egui/src/data/input.rs @@ -157,7 +157,8 @@ pub struct ViewportInfo { /// unit = physical pixels pub outer_rect_px: Option, - /// Viewport should close? + /// The user requested the viewport should close, + /// e.g. by pressing the close button in the window decoration. pub close_requested: bool, } diff --git a/crates/egui/src/viewport.rs b/crates/egui/src/viewport.rs index 255600d47..42bc5efac 100644 --- a/crates/egui/src/viewport.rs +++ b/crates/egui/src/viewport.rs @@ -99,6 +99,9 @@ pub type ImmediateViewportRendererCallback = dyn for<'a> Fn(&Context, ImmediateV /// Since egui is immediate mode, `ViewportBuilder` is accumulative in nature. /// Setting any option to `None` means "keep the current value", /// or "Use the default" if it is the first call. +/// +/// The default values are implementation defined, so you may want to explicitly +/// configure the size of the window, and what buttons are shown. #[derive(Clone, Debug, Default, Eq, PartialEq)] #[allow(clippy::option_option)] pub struct ViewportBuilder { @@ -134,63 +137,6 @@ pub struct ViewportBuilder { } impl ViewportBuilder { - /// Default settings for the root viewport. - pub const DEFAULTS: Self = Self { - title: None, - name: None, - position: None, - inner_size: Some(Some(Vec2::new(300.0, 200.0))), - fullscreen: None, - maximized: None, - resizable: Some(true), - transparent: Some(true), - decorations: Some(true), - icon: None, - active: Some(true), - visible: Some(true), - title_hidden: None, - titlebar_transparent: None, - fullsize_content_view: None, - min_inner_size: None, - max_inner_size: None, - drag_and_drop: Some(true), - close_button: Some(true), - minimize_button: Some(true), - maximize_button: Some(true), - hittest: Some(true), - }; - - /// Empty settings for everything. - /// - /// If used the first frame, backend-specific defaults will be used. - /// When used on subsequent frames, the current settings will be kept. - /// - /// The given id must be unique for each viewport. - pub const EMPTY: Self = Self { - title: None, - name: None, - position: None, - inner_size: None, - fullscreen: None, - maximized: None, - resizable: None, - transparent: None, - decorations: None, - icon: None, - active: None, - visible: None, - title_hidden: None, - titlebar_transparent: None, - fullsize_content_view: None, - min_inner_size: None, - max_inner_size: None, - drag_and_drop: None, - close_button: None, - minimize_button: None, - maximize_button: None, - hittest: None, - }; - /// Sets the initial title of the window in the title bar. /// /// Look at winit for more details @@ -294,24 +240,27 @@ impl ViewportBuilder { self } - /// Mac Os only /// Hides the window title. + /// + /// Mac Os only. #[inline] pub fn with_title_hidden(mut self, title_hidden: bool) -> Self { self.title_hidden = Some(title_hidden); self } - /// Mac Os only /// Makes the titlebar transparent and allows the content to appear behind it. + /// + /// Mac Os only. #[inline] pub fn with_titlebar_transparent(mut self, value: bool) -> Self { self.titlebar_transparent = Some(value); self } - /// Mac Os only /// Makes the window content appear behind the titlebar. + /// + /// Mac Os only. #[inline] pub fn with_fullsize_content_view(mut self, value: bool) -> Self { self.fullsize_content_view = Some(value); @@ -584,7 +533,7 @@ impl ViewportBuilder { } } -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub enum WindowLevel { Normal, @@ -592,7 +541,7 @@ pub enum WindowLevel { AlwaysOnTop, } -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub enum IMEPurpose { Normal, @@ -600,7 +549,7 @@ pub enum IMEPurpose { Terminal, } -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub enum SystemTheme { Light, @@ -608,7 +557,7 @@ pub enum SystemTheme { SystemDefault, } -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub enum CursorGrab { None, @@ -616,17 +565,29 @@ pub enum CursorGrab { Locked, } -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub enum UserAttentionType { Informational, Critical, } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub enum ResizeDirection { + North, + South, + West, + NorthEast, + SouthEast, + NorthWest, + SouthWest, +} + /// You can send a [`ViewportCommand`] to the viewport with [`Context::viewport_command`]. /// /// All coordinates are in logical points. -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub enum ViewportCommand { /// Set the title @@ -663,12 +624,7 @@ pub enum ViewportCommand { /// /// There's no guarantee that this will work unless the left mouse button was pressed /// immediately before this function is called. - BeginResize { - top: bool, - bottom: bool, - right: bool, - left: bool, - }, + BeginResize(ResizeDirection), /// Can the window be resized? Resizable(bool), diff --git a/examples/multiple_viewports/src/main.rs b/examples/multiple_viewports/src/main.rs index 930fe3e73..6ac6145c1 100644 --- a/examples/multiple_viewports/src/main.rs +++ b/examples/multiple_viewports/src/main.rs @@ -52,7 +52,7 @@ impl eframe::App for MyApp { if self.show_immediate_viewport { ctx.show_viewport_immediate( egui::ViewportId::from_hash_of("immediate_viewport"), - egui::ViewportBuilder::DEFAULTS.with_title("Immediate Viewport"), + egui::ViewportBuilder::default().with_title("Immediate Viewport"), |ctx| { egui::CentralPanel::default().show(ctx, |ui| { ui.label("Hello from immediate viewport"); @@ -70,7 +70,7 @@ impl eframe::App for MyApp { 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"), + egui::ViewportBuilder::default().with_title("Deferred Viewport"), |ctx| { egui::CentralPanel::default().show(ctx, |ui| { ui.label("Hello from deferred viewport"); diff --git a/examples/test_viewports/src/main.rs b/examples/test_viewports/src/main.rs index 33676830e..e8bba1ae6 100644 --- a/examples/test_viewports/src/main.rs +++ b/examples/test_viewports/src/main.rs @@ -65,7 +65,7 @@ impl ViewportState { let immediate = vp_state.read().immediate; let title = vp_state.read().title.clone(); - let viewport = ViewportBuilder::DEFAULTS + let viewport = ViewportBuilder::default() .with_title(&title) .with_inner_size(Some(egui::vec2(450.0, 400.0)));