mirror of
https://github.com/emilk/egui.git
synced 2026-06-27 23:13:13 -04:00
* Implement changes_between_builders
* Now process_viewport_commands was renamed to process_viewports_commands * Added process_viewport_commands * eframe glutin backend uses changes_between_builders
This commit is contained in:
@@ -414,7 +414,10 @@ mod glow_integration {
|
||||
use egui::{
|
||||
epaint::ahash::HashMap, mutex::RwLock, NumExt as _, ViewportBuilder, ViewportRender,
|
||||
};
|
||||
use egui_winit::{create_winit_window_builder, EventResponse};
|
||||
use egui_winit::{
|
||||
changes_between_builders, create_winit_window_builder, process_viewport_commands,
|
||||
process_viewports_commands, EventResponse,
|
||||
};
|
||||
use glutin::{
|
||||
display::GetGlDisplay,
|
||||
prelude::{GlDisplay, NotCurrentGlContextSurfaceAccessor, PossiblyCurrentGlContext},
|
||||
@@ -1060,7 +1063,7 @@ mod glow_integration {
|
||||
}
|
||||
}
|
||||
Self::process_viewport_builders(&glutin, output.viewports);
|
||||
egui_winit::process_viewport_commands(
|
||||
egui_winit::process_viewports_commands(
|
||||
output.viewport_commands,
|
||||
*focused.read(),
|
||||
|id| {
|
||||
@@ -1103,13 +1106,17 @@ mod glow_integration {
|
||||
viewports.retain_mut(|(id, _, builder, render)| {
|
||||
if let Some(w) = glutin_ctx.read().windows.get(id) {
|
||||
let mut w = w.write();
|
||||
if w.builder != *builder {
|
||||
let (commands, recreate) = changes_between_builders(builder, &mut w.builder);
|
||||
if recreate {
|
||||
w.window = None;
|
||||
w.gl_surface = None;
|
||||
w.render = render.clone();
|
||||
w.builder = builder.clone();
|
||||
w.parent_id = *id;
|
||||
}
|
||||
if let Some(w) = w.window.clone() {
|
||||
process_viewport_commands(commands, *id, None, w);
|
||||
}
|
||||
active_viewports_ids.push(*id);
|
||||
false
|
||||
} else {
|
||||
@@ -1438,7 +1445,7 @@ mod glow_integration {
|
||||
|
||||
Self::process_viewport_builders(&glutin_ctx, viewports);
|
||||
|
||||
egui_winit::process_viewport_commands(
|
||||
egui_winit::process_viewports_commands(
|
||||
viewport_commands,
|
||||
*self.is_focused.read(),
|
||||
|viewport_id| {
|
||||
@@ -2030,7 +2037,7 @@ mod wgpu_integration {
|
||||
active_viewports_ids.push(id);
|
||||
}
|
||||
|
||||
egui_winit::process_viewport_commands(
|
||||
egui_winit::process_viewports_commands(
|
||||
output.viewport_commands,
|
||||
*focused.read(),
|
||||
|id| _windows.read().get(&id).and_then(|w| w.0.clone()),
|
||||
@@ -2223,7 +2230,7 @@ mod wgpu_integration {
|
||||
active_viewports_ids.push(id);
|
||||
}
|
||||
|
||||
egui_winit::process_viewport_commands(
|
||||
egui_winit::process_viewports_commands(
|
||||
viewport_commands,
|
||||
*self.is_focused.read(),
|
||||
|viewport_id| windows.read().get(&viewport_id).and_then(|w| w.0.clone()),
|
||||
|
||||
@@ -908,134 +908,141 @@ fn translate_cursor(cursor_icon: egui::CursorIcon) -> Option<winit::window::Curs
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
pub fn process_viewport_commands(
|
||||
commands: Vec<ViewportCommand>,
|
||||
viewport_id: ViewportId,
|
||||
focused: Option<ViewportId>,
|
||||
window: Arc<RwLock<winit::window::Window>>,
|
||||
) {
|
||||
use winit::dpi::PhysicalSize;
|
||||
use winit::window::ResizeDirection;
|
||||
let win = window.read();
|
||||
|
||||
for command in commands {
|
||||
match command {
|
||||
egui::ViewportCommand::Drag => {
|
||||
// if this is not checked on x11 the input will be permanently taken until the app is killed!
|
||||
if let Some(focus) = focused {
|
||||
if focus == viewport_id {
|
||||
// TODO possibile return the error to `egui::Context`
|
||||
let _ = win.drag_window();
|
||||
}
|
||||
}
|
||||
}
|
||||
egui::ViewportCommand::InnerSize(width, height) => {
|
||||
let width = width.max(1);
|
||||
let height = height.max(1);
|
||||
win.set_inner_size(PhysicalSize::new(width, height));
|
||||
}
|
||||
egui::ViewportCommand::Resize(top, bottom, right, left) => {
|
||||
// TODO posibile return the error to `egui::Context`
|
||||
let _ = win.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,
|
||||
});
|
||||
}
|
||||
ViewportCommand::Title(title) => win.set_title(&title),
|
||||
ViewportCommand::Transparent(v) => win.set_transparent(v),
|
||||
ViewportCommand::Visible(v) => win.set_visible(v),
|
||||
ViewportCommand::OuterPosition(x, y) => {
|
||||
win.set_outer_position(LogicalPosition::new(x, y))
|
||||
}
|
||||
ViewportCommand::InnerSize(w, h) => win.set_inner_size(LogicalSize::new(w, h)),
|
||||
ViewportCommand::MinInnerSize(s) => {
|
||||
win.set_min_inner_size(s.map(|s| LogicalSize::new(s.0, s.1)))
|
||||
}
|
||||
ViewportCommand::MaxInnerSize(s) => {
|
||||
win.set_max_inner_size(s.map(|s| LogicalSize::new(s.0, s.1)))
|
||||
}
|
||||
ViewportCommand::ResizeIncrements(s) => {
|
||||
win.set_resize_increments(s.map(|s| LogicalSize::new(s.0, s.1)))
|
||||
}
|
||||
ViewportCommand::Resizable(v) => win.set_resizable(v),
|
||||
ViewportCommand::EnableButtons {
|
||||
close,
|
||||
mimimize,
|
||||
maximize,
|
||||
} => win.set_enabled_buttons(
|
||||
close
|
||||
.then_some(WindowButtons::CLOSE)
|
||||
.unwrap_or(WindowButtons::empty())
|
||||
| mimimize
|
||||
.then_some(WindowButtons::MINIMIZE)
|
||||
.unwrap_or(WindowButtons::empty())
|
||||
| maximize
|
||||
.then_some(WindowButtons::MAXIMIZE)
|
||||
.unwrap_or(WindowButtons::empty()),
|
||||
),
|
||||
ViewportCommand::Minimized(v) => win.set_minimized(v),
|
||||
ViewportCommand::Maximized(v) => win.set_maximized(v),
|
||||
ViewportCommand::Fullscreen(v) => {
|
||||
win.set_fullscreen(v.then_some(winit::window::Fullscreen::Borderless(None)))
|
||||
}
|
||||
ViewportCommand::Decorations(v) => win.set_decorations(v),
|
||||
ViewportCommand::WindowLevel(o) => win.set_window_level(match o {
|
||||
1 => WindowLevel::AlwaysOnBottom,
|
||||
2 => WindowLevel::AlwaysOnTop,
|
||||
_ => WindowLevel::Normal,
|
||||
}),
|
||||
ViewportCommand::WindowIcon(icon) => {
|
||||
win.set_window_icon(icon.map(|(bytes, width, height)| {
|
||||
winit::window::Icon::from_rgba(bytes, width, height)
|
||||
.expect("Invalid ICON data!")
|
||||
}))
|
||||
}
|
||||
ViewportCommand::IMEPossition(x, y) => win.set_ime_position(LogicalPosition::new(x, y)),
|
||||
ViewportCommand::IMEAllowed(v) => win.set_ime_allowed(v),
|
||||
ViewportCommand::IMEPurpose(o) => win.set_ime_purpose(match o {
|
||||
1 => winit::window::ImePurpose::Password,
|
||||
2 => winit::window::ImePurpose::Terminal,
|
||||
_ => winit::window::ImePurpose::Normal,
|
||||
}),
|
||||
ViewportCommand::RequestUserAttention(o) => win.request_user_attention(o.map(|o| {
|
||||
if o == 1 {
|
||||
winit::window::UserAttentionType::Critical
|
||||
} else {
|
||||
winit::window::UserAttentionType::Informational
|
||||
}
|
||||
})),
|
||||
ViewportCommand::SetTheme(o) => win.set_theme(o.map(|o| {
|
||||
if o == 1 {
|
||||
winit::window::Theme::Dark
|
||||
} else {
|
||||
winit::window::Theme::Light
|
||||
}
|
||||
})),
|
||||
ViewportCommand::ContentProtected(v) => win.set_content_protected(v),
|
||||
ViewportCommand::CursorPosition(x, y) => {
|
||||
win.set_cursor_position(LogicalPosition::new(x, y));
|
||||
}
|
||||
ViewportCommand::CursorGrab(o) => {
|
||||
win.set_cursor_grab(match o {
|
||||
1 => CursorGrabMode::Confined,
|
||||
2 => CursorGrabMode::Locked,
|
||||
_ => CursorGrabMode::None,
|
||||
});
|
||||
}
|
||||
ViewportCommand::CursorVisible(v) => win.set_cursor_visible(v),
|
||||
ViewportCommand::CursorHitTest(v) => {
|
||||
win.set_cursor_hittest(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_viewports_commands(
|
||||
commands: Vec<(ViewportId, ViewportCommand)>,
|
||||
focused: Option<ViewportId>,
|
||||
get_window: impl Fn(ViewportId) -> Option<Arc<RwLock<winit::window::Window>>>,
|
||||
) {
|
||||
use winit::dpi::PhysicalSize;
|
||||
use winit::window::ResizeDirection;
|
||||
for (viewport_id, command) in commands {
|
||||
if let Some(window) = get_window(viewport_id) {
|
||||
let win = window.read();
|
||||
|
||||
match command {
|
||||
egui::ViewportCommand::Drag => {
|
||||
// if this is not checked on x11 the input will be permanently taken until the app is killed!
|
||||
if let Some(focus) = focused {
|
||||
if focus == viewport_id {
|
||||
// TODO possibile return the error to `egui::Context`
|
||||
let _ = win.drag_window();
|
||||
}
|
||||
}
|
||||
}
|
||||
egui::ViewportCommand::InnerSize(width, height) => {
|
||||
let width = width.max(1);
|
||||
let height = height.max(1);
|
||||
win.set_inner_size(PhysicalSize::new(width, height));
|
||||
}
|
||||
egui::ViewportCommand::Resize(top, bottom, right, left) => {
|
||||
// TODO posibile return the error to `egui::Context`
|
||||
let _ = win.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,
|
||||
});
|
||||
}
|
||||
ViewportCommand::Title(title) => win.set_title(&title),
|
||||
ViewportCommand::Transparent(v) => win.set_transparent(v),
|
||||
ViewportCommand::Visible(v) => win.set_visible(v),
|
||||
ViewportCommand::OuterPosition(x, y) => {
|
||||
win.set_outer_position(LogicalPosition::new(x, y))
|
||||
}
|
||||
ViewportCommand::InnerSize(w, h) => win.set_inner_size(LogicalSize::new(w, h)),
|
||||
ViewportCommand::MinInnerSize(s) => {
|
||||
win.set_min_inner_size(s.map(|s| LogicalSize::new(s.0, s.1)))
|
||||
}
|
||||
ViewportCommand::MaxInnerSize(s) => {
|
||||
win.set_max_inner_size(s.map(|s| LogicalSize::new(s.0, s.1)))
|
||||
}
|
||||
ViewportCommand::ResizeIncrements(s) => {
|
||||
win.set_resize_increments(s.map(|s| LogicalSize::new(s.0, s.1)))
|
||||
}
|
||||
ViewportCommand::Resizable(v) => win.set_resizable(v),
|
||||
ViewportCommand::EnableButtons {
|
||||
close,
|
||||
mimimize,
|
||||
maximize,
|
||||
} => win.set_enabled_buttons(
|
||||
close
|
||||
.then_some(WindowButtons::CLOSE)
|
||||
.unwrap_or(WindowButtons::empty())
|
||||
| mimimize
|
||||
.then_some(WindowButtons::MINIMIZE)
|
||||
.unwrap_or(WindowButtons::empty())
|
||||
| maximize
|
||||
.then_some(WindowButtons::MAXIMIZE)
|
||||
.unwrap_or(WindowButtons::empty()),
|
||||
),
|
||||
ViewportCommand::Minimized(v) => win.set_minimized(v),
|
||||
ViewportCommand::Maximized(v) => win.set_maximized(v),
|
||||
ViewportCommand::Fullscreen(v) => {
|
||||
win.set_fullscreen(v.then_some(winit::window::Fullscreen::Borderless(None)))
|
||||
}
|
||||
ViewportCommand::Decorations(v) => win.set_decorations(v),
|
||||
ViewportCommand::WindowLevel(o) => win.set_window_level(match o {
|
||||
1 => WindowLevel::AlwaysOnBottom,
|
||||
2 => WindowLevel::AlwaysOnTop,
|
||||
_ => WindowLevel::Normal,
|
||||
}),
|
||||
ViewportCommand::WindowIcon(icon) => {
|
||||
win.set_window_icon(icon.map(|(bytes, width, height)| {
|
||||
winit::window::Icon::from_rgba(bytes, width, height)
|
||||
.expect("Invalid ICON data!")
|
||||
}))
|
||||
}
|
||||
ViewportCommand::IMEPossition(x, y) => {
|
||||
win.set_ime_position(LogicalPosition::new(x, y))
|
||||
}
|
||||
ViewportCommand::IMEAllowed(v) => win.set_ime_allowed(v),
|
||||
ViewportCommand::IMEPurpose(o) => win.set_ime_purpose(match o {
|
||||
1 => winit::window::ImePurpose::Password,
|
||||
2 => winit::window::ImePurpose::Terminal,
|
||||
_ => winit::window::ImePurpose::Normal,
|
||||
}),
|
||||
ViewportCommand::RequestUserAttention(o) => {
|
||||
win.request_user_attention(o.map(|o| {
|
||||
if o == 1 {
|
||||
winit::window::UserAttentionType::Critical
|
||||
} else {
|
||||
winit::window::UserAttentionType::Informational
|
||||
}
|
||||
}))
|
||||
}
|
||||
ViewportCommand::SetTheme(o) => win.set_theme(o.map(|o| {
|
||||
if o == 1 {
|
||||
winit::window::Theme::Dark
|
||||
} else {
|
||||
winit::window::Theme::Light
|
||||
}
|
||||
})),
|
||||
ViewportCommand::ContentProtected(v) => win.set_content_protected(v),
|
||||
ViewportCommand::CursorPosition(x, y) => {
|
||||
win.set_cursor_position(LogicalPosition::new(x, y));
|
||||
}
|
||||
ViewportCommand::CursorGrab(o) => {
|
||||
win.set_cursor_grab(match o {
|
||||
1 => CursorGrabMode::Confined,
|
||||
2 => CursorGrabMode::Locked,
|
||||
_ => CursorGrabMode::None,
|
||||
});
|
||||
}
|
||||
ViewportCommand::CursorVisible(v) => win.set_cursor_visible(v),
|
||||
ViewportCommand::CursorHitTest(v) => {
|
||||
win.set_cursor_hittest(v);
|
||||
}
|
||||
}
|
||||
process_viewport_commands(vec![command], viewport_id, focused, window)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1094,11 +1101,156 @@ pub fn create_winit_window_builder(builder: &ViewportBuilder) -> winit::window::
|
||||
window_builder
|
||||
}
|
||||
|
||||
pub fn changes_betwen_builders(
|
||||
now: &ViewportBuilder,
|
||||
last: &ViewportBuilder,
|
||||
) -> Vec<ViewportCommand> {
|
||||
vec![]
|
||||
pub fn changes_between_builders(
|
||||
new: &ViewportBuilder,
|
||||
last: &mut ViewportBuilder,
|
||||
) -> (Vec<ViewportCommand>, bool) {
|
||||
let mut commands = Vec::new();
|
||||
|
||||
// Title is not compared because if has a new title will create a new window
|
||||
// The title of a avalibile window can only be changed with ViewportCommand::Title
|
||||
|
||||
if let Some(position) = new.position {
|
||||
if Some(position) != last.position {
|
||||
last.position = Some(position);
|
||||
if let Some(position) = position {
|
||||
commands.push(ViewportCommand::OuterPosition(position.0, position.1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(inner_size) = new.inner_size {
|
||||
if Some(inner_size) != last.inner_size {
|
||||
last.inner_size = Some(inner_size);
|
||||
if let Some(inner_size) = inner_size {
|
||||
commands.push(ViewportCommand::InnerSize(inner_size.0, inner_size.1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(min_inner_size) = new.min_inner_size {
|
||||
if Some(min_inner_size) != last.min_inner_size {
|
||||
last.min_inner_size = Some(min_inner_size);
|
||||
commands.push(ViewportCommand::MinInnerSize(min_inner_size));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(max_inner_size) = new.max_inner_size {
|
||||
if Some(max_inner_size) != last.max_inner_size {
|
||||
last.max_inner_size = Some(max_inner_size);
|
||||
commands.push(ViewportCommand::MaxInnerSize(max_inner_size));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(fullscreen) = new.fullscreen {
|
||||
if Some(fullscreen) != last.fullscreen {
|
||||
last.fullscreen = Some(fullscreen);
|
||||
commands.push(ViewportCommand::Fullscreen(fullscreen));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(minimized) = new.minimized {
|
||||
if Some(minimized) != last.minimized {
|
||||
last.minimized = Some(minimized);
|
||||
commands.push(ViewportCommand::Minimized(minimized));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(maximized) = new.maximized {
|
||||
if Some(maximized) != last.maximized {
|
||||
last.maximized = Some(maximized);
|
||||
commands.push(ViewportCommand::Maximized(maximized));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(resizable) = new.resizable {
|
||||
if Some(resizable) != last.resizable {
|
||||
last.resizable = Some(resizable);
|
||||
commands.push(ViewportCommand::Resizable(resizable));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(transparent) = new.transparent {
|
||||
if Some(transparent) != last.transparent {
|
||||
last.transparent = Some(transparent);
|
||||
commands.push(ViewportCommand::Transparent(transparent));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(decorations) = new.decorations {
|
||||
if Some(decorations) != last.decorations {
|
||||
last.decorations = Some(decorations);
|
||||
commands.push(ViewportCommand::Decorations(decorations));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(icon) = new.icon.clone() {
|
||||
let eq = match &icon {
|
||||
Some(icon) => {
|
||||
if let Some(last_icon) = &last.icon {
|
||||
matches!(last_icon, Some(last_icon) if Arc::ptr_eq(icon, last_icon))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
None => last.icon == Some(None),
|
||||
};
|
||||
|
||||
if !eq {
|
||||
commands.push(ViewportCommand::WindowIcon(
|
||||
icon.as_ref().map(|i| (i.2.clone(), i.0, i.1)),
|
||||
));
|
||||
last.icon = Some(icon);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(visible) = new.visible {
|
||||
if Some(visible) != last.active {
|
||||
last.visible = Some(visible);
|
||||
commands.push(ViewportCommand::Visible(visible));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Implement compare for windows buttons
|
||||
|
||||
let mut recreate_window = false;
|
||||
|
||||
if let Some(active) = new.active {
|
||||
if Some(active) != last.active {
|
||||
last.active = Some(active);
|
||||
recreate_window = true;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(close_button) = new.close_button {
|
||||
if Some(close_button) != last.close_button {
|
||||
last.close_button = Some(close_button);
|
||||
recreate_window = true;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(title_hidden) = new.title_hidden {
|
||||
if Some(title_hidden) != last.title_hidden {
|
||||
last.title_hidden = Some(title_hidden);
|
||||
recreate_window = true;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(titlebar_transparent) = new.titlebar_transparent {
|
||||
if Some(titlebar_transparent) != last.titlebar_transparent {
|
||||
last.titlebar_transparent = Some(titlebar_transparent);
|
||||
recreate_window = true;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(value) = new.fullsize_content_view {
|
||||
if Some(value) != last.fullsize_content_view {
|
||||
last.fullsize_content_view = Some(value);
|
||||
recreate_window = true;
|
||||
}
|
||||
}
|
||||
|
||||
(commands, recreate_window)
|
||||
}
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ pub struct ViewportBuilder {
|
||||
pub inner_size: Option<Option<(u32, u32)>>,
|
||||
pub fullscreen: Option<bool>,
|
||||
pub maximized: Option<bool>,
|
||||
pub minimized: Option<bool>,
|
||||
pub resizable: Option<bool>,
|
||||
pub transparent: Option<bool>,
|
||||
pub decorations: Option<bool>,
|
||||
@@ -70,6 +71,7 @@ impl Default for ViewportBuilder {
|
||||
max_inner_size: None,
|
||||
drag_and_drop: None,
|
||||
close_button: None,
|
||||
minimized: Some(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,6 +98,7 @@ impl ViewportBuilder {
|
||||
max_inner_size: None,
|
||||
drag_and_drop: None,
|
||||
close_button: None,
|
||||
minimized: None,
|
||||
}
|
||||
}
|
||||
pub fn with_title(mut self, title: impl Into<String>) -> Self {
|
||||
@@ -118,6 +121,11 @@ impl ViewportBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_mimimized(mut self, minimized: bool) -> Self {
|
||||
self.minimized = Some(minimized);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_resizable(mut self, resizable: bool) -> Self {
|
||||
self.resizable = Some(resizable);
|
||||
self
|
||||
|
||||
Reference in New Issue
Block a user