1
0
mirror of https://github.com/emilk/egui.git synced 2026-09-01 06:10:06 -04:00

Get hello world simple to compile

This commit is contained in:
lucasmerlin
2025-11-19 12:14:08 +01:00
parent 7980401b25
commit e285050abc
25 changed files with 1016 additions and 766 deletions

View File

@@ -57,11 +57,13 @@ x11 = ["winit/x11", "bytemuck"]
[dependencies]
egui = { workspace = true, default-features = false }
dpi.workspace = true
log.workspace = true
profiling.workspace = true
raw-window-handle.workspace = true
web-time.workspace = true
winit = { workspace = true, default-features = false }
winit-core.workspace = true
#! ### Optional dependencies

View File

@@ -9,6 +9,7 @@
#![allow(clippy::manual_range_contains)]
use std::ops::Deref;
#[cfg(feature = "accesskit")]
pub use accesskit_winit;
pub use egui;
@@ -31,21 +32,22 @@ use winit::{
event_loop::ActiveEventLoop,
window::{CursorGrabMode, Window, WindowButtons, WindowLevel},
};
use winit_core::event::Ime;
pub fn screen_size_in_pixels(window: &Window) -> egui::Vec2 {
pub fn screen_size_in_pixels(window: &dyn Window) -> egui::Vec2 {
let size = if cfg!(target_os = "ios") {
// `outer_size` Includes the area behind the "dynamic island".
// It is up to the eframe user to make sure the dynamic island doesn't cover anything important.
// That will be easier once https://github.com/rust-windowing/winit/pull/3890 lands
window.outer_size()
} else {
window.inner_size()
window.surface_size()
};
egui::vec2(size.width as f32, size.height as f32)
}
/// Calculate the `pixels_per_point` for a given window, given the current egui zoom factor
pub fn pixels_per_point(egui_ctx: &egui::Context, window: &Window) -> f32 {
pub fn pixels_per_point(egui_ctx: &egui::Context, window: &dyn Window) -> f32 {
let native_pixels_per_point = window.scale_factor() as f32;
let egui_zoom_factor = egui_ctx.zoom_factor();
egui_zoom_factor * native_pixels_per_point
@@ -166,9 +168,9 @@ impl State {
#[cfg(feature = "accesskit")]
pub fn init_accesskit<T: From<accesskit_winit::Event> + Send>(
&mut self,
event_loop: &ActiveEventLoop,
window: &Window,
event_loop_proxy: winit::event_loop::EventLoopProxy<T>,
event_loop: &dyn ActiveEventLoop,
window: &dyn Window,
event_loop_proxy: winit::event_loop::EventLoopProxy,
) {
profiling::function_scope!();
@@ -231,7 +233,7 @@ impl State {
/// You need to set [`egui::RawInput::viewports`] yourself though.
/// Use [`update_viewport_info`] to update the info for each
/// viewport.
pub fn take_egui_input(&mut self, window: &Window) -> egui::RawInput {
pub fn take_egui_input(&mut self, window: &dyn Window) -> egui::RawInput {
profiling::function_scope!();
self.egui_input.time = Some(self.start_time.elapsed().as_secs_f64());
@@ -264,7 +266,7 @@ impl State {
/// The result can be found in [`Self::egui_input`] and be extracted with [`Self::take_egui_input`].
pub fn on_window_event(
&mut self,
window: &Window,
window: &dyn Window,
event: &winit::event::WindowEvent,
) -> EventResponse {
profiling::function_scope!(short_window_event_description(event));
@@ -305,13 +307,13 @@ impl State {
consumed: false,
}
}
WindowEvent::MouseInput { state, button, .. } => {
self.on_mouse_button_input(*state, *button);
EventResponse {
repaint: true,
consumed: self.egui_ctx.wants_pointer_input(),
}
}
// WindowEvent::MouseInput { state, button, .. } => {
// self.on_mouse_button_input(*state, *button);
// EventResponse {
// repaint: true,
// consumed: self.egui_ctx.wants_pointer_input(),
// }
// }
WindowEvent::MouseWheel { delta, phase, .. } => {
self.on_mouse_wheel(window, *delta, *phase);
EventResponse {
@@ -319,35 +321,35 @@ impl State {
consumed: self.egui_ctx.wants_pointer_input(),
}
}
WindowEvent::CursorMoved { position, .. } => {
self.on_cursor_moved(window, *position);
EventResponse {
repaint: true,
consumed: self.egui_ctx.is_using_pointer(),
}
}
WindowEvent::CursorLeft { .. } => {
self.pointer_pos_in_points = None;
self.egui_input.events.push(egui::Event::PointerGone);
EventResponse {
repaint: true,
consumed: false,
}
}
// WindowEvent::TouchpadPressure {device_id, pressure, stage, .. } => {} // TODO(emilk)
WindowEvent::Touch(touch) => {
self.on_touch(window, touch);
let consumed = match touch.phase {
winit::event::TouchPhase::Started
| winit::event::TouchPhase::Ended
| winit::event::TouchPhase::Cancelled => self.egui_ctx.wants_pointer_input(),
winit::event::TouchPhase::Moved => self.egui_ctx.is_using_pointer(),
};
EventResponse {
repaint: true,
consumed,
}
}
// WindowEvent::CursorMoved { position, .. } => {
// self.on_cursor_moved(window, *position);
// EventResponse {
// repaint: true,
// consumed: self.egui_ctx.is_using_pointer(),
// }
// }
// WindowEvent::CursorLeft { .. } => {
// self.pointer_pos_in_points = None;
// self.egui_input.events.push(egui::Event::PointerGone);
// EventResponse {
// repaint: true,
// consumed: false,
// }
// }
// // WindowEvent::TouchpadPressure {device_id, pressure, stage, .. } => {} // TODO(emilk)
// WindowEvent::PointerButton(touch) => {
// self.on_touch(window, touch);
// let consumed = match touch.phase {
// winit::event::TouchPhase::Started
// | winit::event::TouchPhase::Ended
// | winit::event::TouchPhase::Cancelled => self.egui_ctx.wants_pointer_input(),
// winit::event::TouchPhase::Moved => self.egui_ctx.is_using_pointer(),
// };
// EventResponse {
// repaint: true,
// consumed,
// }
// }
WindowEvent::Ime(ime) => {
// on Mac even Cmd-C is pressed during ime, a `c` is pushed to Preedit.
@@ -388,6 +390,9 @@ impl State {
winit::event::Ime::Disabled | winit::event::Ime::Preedit(_, None) => {
self.ime_event_disable();
}
Ime::DeleteSurrounding { .. } => {
todo!()
}
}
EventResponse {
@@ -448,41 +453,41 @@ impl State {
consumed: false,
}
}
WindowEvent::HoveredFile(path) => {
self.egui_input.hovered_files.push(egui::HoveredFile {
path: Some(path.clone()),
..Default::default()
});
EventResponse {
repaint: true,
consumed: false,
}
}
WindowEvent::HoveredFileCancelled => {
self.egui_input.hovered_files.clear();
EventResponse {
repaint: true,
consumed: false,
}
}
WindowEvent::DroppedFile(path) => {
self.egui_input.hovered_files.clear();
self.egui_input.dropped_files.push(egui::DroppedFile {
path: Some(path.clone()),
..Default::default()
});
EventResponse {
repaint: true,
consumed: false,
}
}
// WindowEvent::HoveredFile(path) => {
// self.egui_input.hovered_files.push(egui::HoveredFile {
// path: Some(path.clone()),
// ..Default::default()
// });
// EventResponse {
// repaint: true,
// consumed: false,
// }
// }
// WindowEvent::HoveredFileCancelled => {
// self.egui_input.hovered_files.clear();
// EventResponse {
// repaint: true,
// consumed: false,
// }
// }
// WindowEvent::DroppedFile(path) => {
// self.egui_input.hovered_files.clear();
// self.egui_input.dropped_files.push(egui::DroppedFile {
// path: Some(path.clone()),
// ..Default::default()
// });
// EventResponse {
// repaint: true,
// consumed: false,
// }
// }
WindowEvent::ModifiersChanged(state) => {
let state = state.state();
let alt = state.alt_key();
let ctrl = state.control_key();
let shift = state.shift_key();
let super_ = state.super_key();
let super_ = state.meta_key();
self.egui_input.modifiers.alt = alt;
self.egui_input.modifiers.ctrl = ctrl;
@@ -502,10 +507,10 @@ impl State {
// Things that may require repaint:
WindowEvent::RedrawRequested
| WindowEvent::CursorEntered { .. }
// | WindowEvent::CursorEntered { .. }
| WindowEvent::Destroyed
| WindowEvent::Occluded(_)
| WindowEvent::Resized(_)
// | WindowEvent::Resized(_)
| WindowEvent::Moved(_)
| WindowEvent::TouchpadPressure { .. }
| WindowEvent::CloseRequested => EventResponse {
@@ -515,7 +520,7 @@ impl State {
// Things we completely ignore:
WindowEvent::ActivationTokenDone { .. }
| WindowEvent::AxisMotion { .. }
// | WindowEvent::AxisMotion { .. }
| WindowEvent::DoubleTapGesture { .. } => EventResponse {
repaint: false,
consumed: false,
@@ -559,6 +564,20 @@ impl State {
consumed: self.egui_ctx.wants_pointer_input(),
}
}
// WindowEvent::SurfaceResized(_) => {}
// WindowEvent::DragEntered { .. } => {}
// WindowEvent::DragMoved { .. } => {}
// WindowEvent::DragDropped { .. } => {}
// WindowEvent::DragLeft { .. } => {}
// WindowEvent::PointerMoved { .. } => {}
// WindowEvent::PointerEntered { .. } => {}
// WindowEvent::PointerLeft { .. } => {}
// WindowEvent::PointerButton { .. } => {}
// TODO: Handle these
_ => EventResponse {
repaint: false,
consumed: false,
},
}
}
@@ -642,7 +661,7 @@ impl State {
fn on_cursor_moved(
&mut self,
window: &Window,
window: &dyn Window,
pos_in_pixels: winit::dpi::PhysicalPosition<f64>,
) {
let pixels_per_point = pixels_per_point(&self.egui_ctx, window);
@@ -674,69 +693,69 @@ impl State {
}
}
fn on_touch(&mut self, window: &Window, touch: &winit::event::Touch) {
let pixels_per_point = pixels_per_point(&self.egui_ctx, window);
// Emit touch event
self.egui_input.events.push(egui::Event::Touch {
device_id: egui::TouchDeviceId(egui::epaint::util::hash(touch.device_id)),
id: egui::TouchId::from(touch.id),
phase: to_egui_touch_phase(touch.phase),
pos: egui::pos2(
touch.location.x as f32 / pixels_per_point,
touch.location.y as f32 / pixels_per_point,
),
force: match touch.force {
Some(winit::event::Force::Normalized(force)) => Some(force as f32),
Some(winit::event::Force::Calibrated {
force,
max_possible_force,
..
}) => Some((force / max_possible_force) as f32),
None => None,
},
});
// If we're not yet translating a touch or we're translating this very
// touch …
if self.pointer_touch_id.is_none() || self.pointer_touch_id.unwrap_or_default() == touch.id
{
// … emit PointerButton resp. PointerMoved events to emulate mouse
match touch.phase {
winit::event::TouchPhase::Started => {
self.pointer_touch_id = Some(touch.id);
// First move the pointer to the right location
self.on_cursor_moved(window, touch.location);
self.on_mouse_button_input(
winit::event::ElementState::Pressed,
winit::event::MouseButton::Left,
);
}
winit::event::TouchPhase::Moved => {
self.on_cursor_moved(window, touch.location);
}
winit::event::TouchPhase::Ended => {
self.pointer_touch_id = None;
self.on_mouse_button_input(
winit::event::ElementState::Released,
winit::event::MouseButton::Left,
);
// The pointer should vanish completely to not get any
// hover effects
self.pointer_pos_in_points = None;
self.egui_input.events.push(egui::Event::PointerGone);
}
winit::event::TouchPhase::Cancelled => {
self.pointer_touch_id = None;
self.pointer_pos_in_points = None;
self.egui_input.events.push(egui::Event::PointerGone);
}
}
}
}
// fn on_touch(&mut self, window: &Window, touch: &winit::event::Touch) {
// let pixels_per_point = pixels_per_point(&self.egui_ctx, window);
//
// // Emit touch event
// self.egui_input.events.push(egui::Event::Touch {
// device_id: egui::TouchDeviceId(egui::epaint::util::hash(touch.device_id)),
// id: egui::TouchId::from(touch.id),
// phase: to_egui_touch_phase(touch.phase),
// pos: egui::pos2(
// touch.location.x as f32 / pixels_per_point,
// touch.location.y as f32 / pixels_per_point,
// ),
// force: match touch.force {
// Some(winit::event::Force::Normalized(force)) => Some(force as f32),
// Some(winit::event::Force::Calibrated {
// force,
// max_possible_force,
// ..
// }) => Some((force / max_possible_force) as f32),
// None => None,
// },
// });
// // If we're not yet translating a touch or we're translating this very
// // touch …
// if self.pointer_touch_id.is_none() || self.pointer_touch_id.unwrap_or_default() == touch.id
// {
// // … emit PointerButton resp. PointerMoved events to emulate mouse
// match touch.phase {
// winit::event::TouchPhase::Started => {
// self.pointer_touch_id = Some(touch.id);
// // First move the pointer to the right location
// self.on_cursor_moved(window, touch.location);
// self.on_mouse_button_input(
// winit::event::ElementState::Pressed,
// winit::event::MouseButton::Left,
// );
// }
// winit::event::TouchPhase::Moved => {
// self.on_cursor_moved(window, touch.location);
// }
// winit::event::TouchPhase::Ended => {
// self.pointer_touch_id = None;
// self.on_mouse_button_input(
// winit::event::ElementState::Released,
// winit::event::MouseButton::Left,
// );
// // The pointer should vanish completely to not get any
// // hover effects
// self.pointer_pos_in_points = None;
// self.egui_input.events.push(egui::Event::PointerGone);
// }
// winit::event::TouchPhase::Cancelled => {
// self.pointer_touch_id = None;
// self.pointer_pos_in_points = None;
// self.egui_input.events.push(egui::Event::PointerGone);
// }
// }
// }
// }
fn on_mouse_wheel(
&mut self,
window: &Window,
window: &dyn Window,
delta: winit::event::MouseScrollDelta,
phase: winit::event::TouchPhase,
) {
@@ -877,7 +896,7 @@ impl State {
/// *
pub fn handle_platform_output(
&mut self,
window: &Window,
window: &dyn Window,
platform_output: egui::PlatformOutput,
) {
profiling::function_scope!();
@@ -929,11 +948,13 @@ impl State {
winit::dpi::PhysicalPosition {
x: ime_rect_px.min.x,
y: ime_rect_px.min.y,
},
}
.into(),
winit::dpi::PhysicalSize {
width: ime_rect_px.width(),
height: ime_rect_px.height(),
},
}
.into(),
);
}
} else {
@@ -949,7 +970,7 @@ impl State {
}
}
fn set_cursor_icon(&mut self, window: &Window, cursor_icon: egui::CursorIcon) {
fn set_cursor_icon(&mut self, window: &dyn Window, cursor_icon: egui::CursorIcon) {
if self.current_cursor_icon == Some(cursor_icon) {
// Prevent flickering near frame boundary when Windows OS tries to control cursor icon for window resizing.
// On other platforms: just early-out to save CPU.
@@ -960,12 +981,7 @@ impl State {
if is_pointer_in_window {
self.current_cursor_icon = Some(cursor_icon);
if let Some(winit_cursor_icon) = translate_cursor(cursor_icon) {
window.set_cursor_visible(true);
window.set_cursor(winit_cursor_icon);
} else {
window.set_cursor_visible(false);
}
window.set_cursor_visible(true);
} else {
// Remember to set the cursor again once the cursor returns to the screen:
self.current_cursor_icon = None;
@@ -989,11 +1005,11 @@ fn to_egui_theme(theme: winit::window::Theme) -> Theme {
}
}
pub fn inner_rect_in_points(window: &Window, pixels_per_point: f32) -> Option<Rect> {
let inner_pos_px = window.inner_position().ok()?;
pub fn inner_rect_in_points(window: &dyn Window, pixels_per_point: f32) -> Option<Rect> {
let inner_pos_px = window.surface_position();
let inner_pos_px = egui::pos2(inner_pos_px.x as f32, inner_pos_px.y as f32);
let inner_size_px = window.inner_size();
let inner_size_px = window.surface_size();
let inner_size_px = egui::vec2(inner_size_px.width as f32, inner_size_px.height as f32);
let inner_rect_px = egui::Rect::from_min_size(inner_pos_px, inner_size_px);
@@ -1001,7 +1017,7 @@ pub fn inner_rect_in_points(window: &Window, pixels_per_point: f32) -> Option<Re
Some(inner_rect_px / pixels_per_point)
}
pub fn outer_rect_in_points(window: &Window, pixels_per_point: f32) -> Option<Rect> {
pub fn outer_rect_in_points(window: &dyn Window, pixels_per_point: f32) -> Option<Rect> {
let outer_pos_px = window.outer_position().ok()?;
let outer_pos_px = egui::pos2(outer_pos_px.x as f32, outer_pos_px.y as f32);
@@ -1021,7 +1037,7 @@ pub fn outer_rect_in_points(window: &Window, pixels_per_point: f32) -> Option<Re
pub fn update_viewport_info(
viewport_info: &mut ViewportInfo,
egui_ctx: &egui::Context,
window: &Window,
window: &dyn Window,
is_init: bool,
) {
profiling::function_scope!();
@@ -1047,8 +1063,9 @@ pub fn update_viewport_info(
let monitor_size = {
profiling::scope!("monitor_size");
if let Some(monitor) = window.current_monitor() {
let size = monitor.size().to_logical::<f32>(pixels_per_point.into());
Some(egui::vec2(size.width, size.height))
// let size = monitor.size().to_logical::<f32>(pixels_per_point.into());
// Some(egui::vec2(size.width, size.height))
None // TODO
} else {
None
}
@@ -1122,7 +1139,8 @@ fn translate_mouse_button(button: winit::event::MouseButton) -> Option<egui::Poi
winit::event::MouseButton::Middle => Some(egui::PointerButton::Middle),
winit::event::MouseButton::Back => Some(egui::PointerButton::Extra1),
winit::event::MouseButton::Forward => Some(egui::PointerButton::Extra2),
winit::event::MouseButton::Other(_) => None,
_ => None
// winit::event::MouseButton::Other(_) => None,
}
}
@@ -1157,7 +1175,7 @@ fn key_from_named_key(named_key: winit::keyboard::NamedKey) -> Option<egui::Key>
NamedKey::Copy => Key::Copy,
NamedKey::Paste => Key::Paste,
NamedKey::Space => Key::Space,
// NamedKey::SpaSpace => Key::Space, TODO: ??
NamedKey::F1 => Key::F1,
NamedKey::F2 => Key::F2,
@@ -1325,50 +1343,6 @@ fn key_from_key_code(key: winit::keyboard::KeyCode) -> Option<egui::Key> {
})
}
fn translate_cursor(cursor_icon: egui::CursorIcon) -> Option<winit::window::CursorIcon> {
match cursor_icon {
egui::CursorIcon::None => None,
egui::CursorIcon::Alias => Some(winit::window::CursorIcon::Alias),
egui::CursorIcon::AllScroll => Some(winit::window::CursorIcon::AllScroll),
egui::CursorIcon::Cell => Some(winit::window::CursorIcon::Cell),
egui::CursorIcon::ContextMenu => Some(winit::window::CursorIcon::ContextMenu),
egui::CursorIcon::Copy => Some(winit::window::CursorIcon::Copy),
egui::CursorIcon::Crosshair => Some(winit::window::CursorIcon::Crosshair),
egui::CursorIcon::Default => Some(winit::window::CursorIcon::Default),
egui::CursorIcon::Grab => Some(winit::window::CursorIcon::Grab),
egui::CursorIcon::Grabbing => Some(winit::window::CursorIcon::Grabbing),
egui::CursorIcon::Help => Some(winit::window::CursorIcon::Help),
egui::CursorIcon::Move => Some(winit::window::CursorIcon::Move),
egui::CursorIcon::NoDrop => Some(winit::window::CursorIcon::NoDrop),
egui::CursorIcon::NotAllowed => Some(winit::window::CursorIcon::NotAllowed),
egui::CursorIcon::PointingHand => Some(winit::window::CursorIcon::Pointer),
egui::CursorIcon::Progress => Some(winit::window::CursorIcon::Progress),
egui::CursorIcon::ResizeHorizontal => Some(winit::window::CursorIcon::EwResize),
egui::CursorIcon::ResizeNeSw => Some(winit::window::CursorIcon::NeswResize),
egui::CursorIcon::ResizeNwSe => Some(winit::window::CursorIcon::NwseResize),
egui::CursorIcon::ResizeVertical => Some(winit::window::CursorIcon::NsResize),
egui::CursorIcon::ResizeEast => Some(winit::window::CursorIcon::EResize),
egui::CursorIcon::ResizeSouthEast => Some(winit::window::CursorIcon::SeResize),
egui::CursorIcon::ResizeSouth => Some(winit::window::CursorIcon::SResize),
egui::CursorIcon::ResizeSouthWest => Some(winit::window::CursorIcon::SwResize),
egui::CursorIcon::ResizeWest => Some(winit::window::CursorIcon::WResize),
egui::CursorIcon::ResizeNorthWest => Some(winit::window::CursorIcon::NwResize),
egui::CursorIcon::ResizeNorth => Some(winit::window::CursorIcon::NResize),
egui::CursorIcon::ResizeNorthEast => Some(winit::window::CursorIcon::NeResize),
egui::CursorIcon::ResizeColumn => Some(winit::window::CursorIcon::ColResize),
egui::CursorIcon::ResizeRow => Some(winit::window::CursorIcon::RowResize),
egui::CursorIcon::Text => Some(winit::window::CursorIcon::Text),
egui::CursorIcon::VerticalText => Some(winit::window::CursorIcon::VerticalText),
egui::CursorIcon::Wait => Some(winit::window::CursorIcon::Wait),
egui::CursorIcon::ZoomIn => Some(winit::window::CursorIcon::ZoomIn),
egui::CursorIcon::ZoomOut => Some(winit::window::CursorIcon::ZoomOut),
}
}
// Helpers for egui Viewports
// ---------------------------------------------------------------------------
#[derive(PartialEq, Eq, Hash, Debug)]
@@ -1383,7 +1357,7 @@ pub fn process_viewport_commands(
egui_ctx: &egui::Context,
info: &mut ViewportInfo,
commands: impl IntoIterator<Item = ViewportCommand>,
window: &Window,
window: &dyn Window,
actions_requested: &mut Vec<ActionRequested>,
) {
for command in commands {
@@ -1393,7 +1367,7 @@ pub fn process_viewport_commands(
fn process_viewport_command(
egui_ctx: &egui::Context,
window: &Window,
window: &dyn Window,
command: ViewportCommand,
info: &mut ViewportInfo,
actions_requested: &mut Vec<ActionRequested>,
@@ -1425,7 +1399,7 @@ fn process_viewport_command(
let width_px = pixels_per_point * size.x.max(1.0);
let height_px = pixels_per_point * size.y.max(1.0);
let requested_size = PhysicalSize::new(width_px, height_px);
if let Some(_returned_inner_size) = window.request_inner_size(requested_size) {
if let Some(_returned_inner_size) = window.request_surface_size(requested_size.into()) {
// On platforms where the size is entirely controlled by the user the
// applied size will be returned immediately, resize event in such case
// may not be generated.
@@ -1470,21 +1444,21 @@ fn process_viewport_command(
window.set_outer_position(PhysicalPosition::new(
pixels_per_point * pos.x,
pixels_per_point * pos.y,
));
).into());
}
ViewportCommand::MinInnerSize(s) => {
window.set_min_inner_size((s.is_finite() && s != Vec2::ZERO).then_some(
PhysicalSize::new(pixels_per_point * s.x, pixels_per_point * s.y),
window.set_min_surface_size((s.is_finite() && s != Vec2::ZERO).then_some(
PhysicalSize::new(pixels_per_point * s.x, pixels_per_point * s.y).into(),
));
}
ViewportCommand::MaxInnerSize(s) => {
window.set_max_inner_size((s.is_finite() && s != Vec2::INFINITY).then_some(
PhysicalSize::new(pixels_per_point * s.x, pixels_per_point * s.y),
window.set_max_surface_size((s.is_finite() && s != Vec2::INFINITY).then_some(
PhysicalSize::new(pixels_per_point * s.x, pixels_per_point * s.y).into(),
));
}
ViewportCommand::ResizeIncrements(s) => {
window.set_resize_increments(
s.map(|s| PhysicalSize::new(pixels_per_point * s.x, pixels_per_point * s.y)),
window.set_surface_resize_increments(
s.map(|s| PhysicalSize::new(pixels_per_point * s.x, pixels_per_point * s.y).into()),
);
}
ViewportCommand::Resizable(v) => window.set_resizable(v),
@@ -1516,7 +1490,7 @@ fn process_viewport_command(
info.maximized = Some(v);
}
ViewportCommand::Fullscreen(v) => {
window.set_fullscreen(v.then_some(winit::window::Fullscreen::Borderless(None)));
window.set_fullscreen(v.then_some(winit_core::monitor::Fullscreen::Borderless(None)));
}
ViewportCommand::Decorations(v) => window.set_decorations(v),
ViewportCommand::WindowLevel(l) => window.set_window_level(match l {
@@ -1530,11 +1504,11 @@ fn process_viewport_command(
}
ViewportCommand::IMERect(rect) => {
window.set_ime_cursor_area(
PhysicalPosition::new(pixels_per_point * rect.min.x, pixels_per_point * rect.min.y),
PhysicalPosition::new(pixels_per_point * rect.min.x, pixels_per_point * rect.min.y).into(),
PhysicalSize::new(
pixels_per_point * rect.size().x,
pixels_per_point * rect.size().y,
),
).into(),
);
}
ViewportCommand::IMEAllowed(v) => window.set_ime_allowed(v),
@@ -1569,7 +1543,7 @@ fn process_viewport_command(
if let Err(err) = window.set_cursor_position(PhysicalPosition::new(
pixels_per_point * pos.x,
pixels_per_point * pos.y,
)) {
).into()) {
log::warn!("{command:?}: {err}");
}
}
@@ -1611,14 +1585,14 @@ fn process_viewport_command(
/// Possible causes of error include denied permission, incompatible system, and lack of memory.
pub fn create_window(
egui_ctx: &egui::Context,
event_loop: &ActiveEventLoop,
event_loop: &dyn ActiveEventLoop,
viewport_builder: &ViewportBuilder,
) -> Result<Window, winit::error::OsError> {
) -> Result<Box<dyn Window>, winit::error::RequestError> {
profiling::function_scope!();
let window_attributes = create_winit_window_attributes(egui_ctx, viewport_builder.clone());
let window = event_loop.create_window(window_attributes)?;
apply_viewport_builder_to_window(egui_ctx, &window, viewport_builder);
apply_viewport_builder_to_window(egui_ctx, window.deref(), viewport_builder);
Ok(window)
}
@@ -1686,7 +1660,7 @@ pub fn create_winit_window_attributes(
egui::viewport::WindowLevel::Normal => WindowLevel::Normal,
})
.with_fullscreen(
fullscreen.and_then(|e| e.then_some(winit::window::Fullscreen::Borderless(None))),
fullscreen.and_then(|e| e.then_some(winit_core::monitor::Fullscreen::Borderless(None))),
)
.with_enabled_buttons({
let mut buttons = WindowButtons::empty();
@@ -1719,17 +1693,17 @@ pub fn create_winit_window_attributes(
if let Some(size) = inner_size {
window_attributes = window_attributes
.with_inner_size(LogicalSize::new(zoom_factor * size.x, zoom_factor * size.y));
.with_surface_size(LogicalSize::new(zoom_factor * size.x, zoom_factor * size.y));
}
if let Some(size) = min_inner_size {
window_attributes = window_attributes
.with_min_inner_size(LogicalSize::new(zoom_factor * size.x, zoom_factor * size.y));
.with_min_surface_size(LogicalSize::new(zoom_factor * size.x, zoom_factor * size.y));
}
if let Some(size) = max_inner_size {
window_attributes = window_attributes
.with_max_inner_size(LogicalSize::new(zoom_factor * size.x, zoom_factor * size.y));
.with_max_surface_size(LogicalSize::new(zoom_factor * size.x, zoom_factor * size.y));
}
if let Some(pos) = position {
@@ -1798,26 +1772,27 @@ pub fn create_winit_window_attributes(
#[cfg(target_os = "macos")]
{
use winit::platform::macos::WindowAttributesExtMacOS as _;
window_attributes = window_attributes
let mac_window_attributes = winit::platform::macos::WindowAttributesMacOS::default()
.with_title_hidden(!_title_shown.unwrap_or(true))
.with_titlebar_buttons_hidden(!_titlebar_buttons_shown.unwrap_or(true))
.with_titlebar_transparent(!_titlebar_shown.unwrap_or(true))
.with_fullsize_content_view(_fullsize_content_view.unwrap_or(false))
.with_movable_by_window_background(_movable_by_window_background.unwrap_or(false))
.with_has_shadow(_has_shadow.unwrap_or(true));
window_attributes =
window_attributes.with_platform_attributes(Box::new(mac_window_attributes));
}
window_attributes
}
fn to_winit_icon(icon: &egui::IconData) -> Option<winit::window::Icon> {
fn to_winit_icon(icon: &egui::IconData) -> Option<winit_core::icon::Icon> {
if icon.is_empty() {
None
} else {
profiling::function_scope!();
match winit::window::Icon::from_rgba(icon.rgba.clone(), icon.width, icon.height) {
Ok(winit_icon) => Some(winit_icon),
match winit_core::icon::RgbaIcon::new(icon.rgba.clone(), icon.width, icon.height) {
Ok(winit_icon) => Some(winit_icon.into()),
Err(err) => {
log::warn!("Invalid IconData: {err}");
None
@@ -1829,7 +1804,7 @@ fn to_winit_icon(icon: &egui::IconData) -> Option<winit::window::Icon> {
/// Applies what `create_winit_window_builder` couldn't
pub fn apply_viewport_builder_to_window(
egui_ctx: &egui::Context,
window: &Window,
window: &dyn Window,
builder: &ViewportBuilder,
) {
if let Some(mouse_passthrough) = builder.mouse_passthrough
@@ -1848,29 +1823,29 @@ pub fn apply_viewport_builder_to_window(
if let Some(size) = builder.inner_size
&& window
.request_inner_size(PhysicalSize::new(
.request_surface_size(PhysicalSize::new(
pixels_per_point * size.x,
pixels_per_point * size.y,
))
).into())
.is_some()
{
log::debug!("Failed to set window size");
}
if let Some(size) = builder.min_inner_size {
window.set_min_inner_size(Some(PhysicalSize::new(
window.set_min_surface_size(Some(PhysicalSize::new(
pixels_per_point * size.x,
pixels_per_point * size.y,
)));
).into()));
}
if let Some(size) = builder.max_inner_size {
window.set_max_inner_size(Some(PhysicalSize::new(
window.set_max_surface_size(Some(PhysicalSize::new(
pixels_per_point * size.x,
pixels_per_point * size.y,
)));
).into()));
}
if let Some(pos) = builder.position {
let pos = PhysicalPosition::new(pixels_per_point * pos.x, pixels_per_point * pos.y);
window.set_outer_position(pos);
window.set_outer_position(pos.into());
}
if let Some(maximized) = builder.maximized {
window.set_maximized(maximized);
@@ -1886,13 +1861,10 @@ pub fn short_device_event_description(event: &winit::event::DeviceEvent) -> &'st
use winit::event::DeviceEvent;
match event {
DeviceEvent::Added => "DeviceEvent::Added",
DeviceEvent::Removed => "DeviceEvent::Removed",
DeviceEvent::MouseMotion { .. } => "DeviceEvent::MouseMotion",
DeviceEvent::MouseWheel { .. } => "DeviceEvent::MouseWheel",
DeviceEvent::Motion { .. } => "DeviceEvent::Motion",
DeviceEvent::Button { .. } => "DeviceEvent::Button",
DeviceEvent::Key { .. } => "DeviceEvent::Key",
DeviceEvent::PointerMotion { .. } => "DeviceEvent::PointerMotion",
}
}
@@ -1903,32 +1875,31 @@ pub fn short_window_event_description(event: &winit::event::WindowEvent) -> &'st
match event {
WindowEvent::ActivationTokenDone { .. } => "WindowEvent::ActivationTokenDone",
WindowEvent::Resized { .. } => "WindowEvent::Resized",
WindowEvent::Moved { .. } => "WindowEvent::Moved",
WindowEvent::CloseRequested => "WindowEvent::CloseRequested",
WindowEvent::Destroyed => "WindowEvent::Destroyed",
WindowEvent::DroppedFile { .. } => "WindowEvent::DroppedFile",
WindowEvent::HoveredFile { .. } => "WindowEvent::HoveredFile",
WindowEvent::HoveredFileCancelled => "WindowEvent::HoveredFileCancelled",
WindowEvent::Focused { .. } => "WindowEvent::Focused",
WindowEvent::KeyboardInput { .. } => "WindowEvent::KeyboardInput",
WindowEvent::ModifiersChanged { .. } => "WindowEvent::ModifiersChanged",
WindowEvent::Ime { .. } => "WindowEvent::Ime",
WindowEvent::CursorMoved { .. } => "WindowEvent::CursorMoved",
WindowEvent::CursorEntered { .. } => "WindowEvent::CursorEntered",
WindowEvent::CursorLeft { .. } => "WindowEvent::CursorLeft",
WindowEvent::MouseWheel { .. } => "WindowEvent::MouseWheel",
WindowEvent::MouseInput { .. } => "WindowEvent::MouseInput",
WindowEvent::PinchGesture { .. } => "WindowEvent::PinchGesture",
WindowEvent::RedrawRequested => "WindowEvent::RedrawRequested",
WindowEvent::DoubleTapGesture { .. } => "WindowEvent::DoubleTapGesture",
WindowEvent::RotationGesture { .. } => "WindowEvent::RotationGesture",
WindowEvent::TouchpadPressure { .. } => "WindowEvent::TouchpadPressure",
WindowEvent::AxisMotion { .. } => "WindowEvent::AxisMotion",
WindowEvent::Touch { .. } => "WindowEvent::Touch",
WindowEvent::ScaleFactorChanged { .. } => "WindowEvent::ScaleFactorChanged",
WindowEvent::ThemeChanged { .. } => "WindowEvent::ThemeChanged",
WindowEvent::Occluded { .. } => "WindowEvent::Occluded",
WindowEvent::PanGesture { .. } => "WindowEvent::PanGesture",
WindowEvent::SurfaceResized(_) => "WindowEvent::SurfaceResized",
WindowEvent::DragEntered { .. } => "WindowEvent::DragEntered",
WindowEvent::DragMoved { .. } => "WindowEvent::DragMoved",
WindowEvent::DragDropped { .. } => "WindowEvent::DragDropped",
WindowEvent::DragLeft { .. } => "WindowEvent::DragLeft",
WindowEvent::PointerMoved { .. } => "WindowEvent::PointerMoved",
WindowEvent::PointerEntered { .. } => "WindowEvent::PointerEntered",
WindowEvent::PointerLeft { .. } => "WindowEvent::PointerLeft",
WindowEvent::PointerButton { .. } => "WindowEvent::PointerButton",
}
}

View File

@@ -6,7 +6,7 @@ use egui::ViewportBuilder;
#[cfg_attr(feature = "serde", serde(default))]
pub struct WindowSettings {
/// Position of window content in physical pixels.
inner_position_pixels: Option<egui::Pos2>,
inner_position_pixels: egui::Pos2,
/// Position of window frame/titlebar in physical pixels.
outer_position_pixels: Option<egui::Pos2>,
@@ -20,15 +20,13 @@ pub struct WindowSettings {
}
impl WindowSettings {
pub fn from_window(egui_zoom_factor: f32, window: &winit::window::Window) -> Self {
pub fn from_window(egui_zoom_factor: f32, window: &dyn winit::window::Window) -> Self {
let inner_size_points = window
.inner_size()
.surface_size()
.to_logical::<f32>(egui_zoom_factor as f64 * window.scale_factor());
let inner_position_pixels = window
.inner_position()
.ok()
.map(|p| egui::pos2(p.x as f32, p.y as f32));
let inner_position = window.surface_position();
let inner_position_pixels = egui::pos2(inner_position.x as f32, inner_position.y as f32);
let outer_position_pixels = window
.outer_position()
@@ -56,7 +54,7 @@ impl WindowSettings {
pub fn initialize_viewport_builder(
&self,
egui_zoom_factor: f32,
event_loop: &winit::event_loop::ActiveEventLoop,
event_loop: &dyn winit::event_loop::ActiveEventLoop,
mut viewport_builder: ViewportBuilder,
) -> ViewportBuilder {
profiling::function_scope!();
@@ -64,7 +62,7 @@ impl WindowSettings {
// `WindowBuilder::with_position` expects inner position in Macos, and outer position elsewhere
// See [`winit::window::WindowBuilder::with_position`] for details.
let pos_px = if cfg!(target_os = "macos") {
self.inner_position_pixels
Some(self.inner_position_pixels)
} else {
self.outer_position_pixels
};
@@ -90,12 +88,12 @@ impl WindowSettings {
viewport_builder
}
pub fn initialize_window(&self, window: &winit::window::Window) {
pub fn initialize_window(&self, window: &dyn winit::window::Window) {
if cfg!(target_os = "macos") {
// Mac sometimes has problems restoring the window to secondary monitors
// using only `WindowBuilder::with_position`, so we need this extra step:
if let Some(pos) = self.outer_position_pixels {
window.set_outer_position(winit::dpi::PhysicalPosition { x: pos.x, y: pos.y });
window.set_outer_position(dpi::PhysicalPosition { x: pos.x, y: pos.y }.into());
}
}
}
@@ -117,7 +115,7 @@ impl WindowSettings {
pub fn clamp_position_to_monitors(
&mut self,
egui_zoom_factor: f32,
event_loop: &winit::event_loop::ActiveEventLoop,
event_loop: &dyn winit::event_loop::ActiveEventLoop,
) {
// If the app last ran on two monitors and only one is now connected, then
// the given position is invalid.
@@ -132,9 +130,12 @@ impl WindowSettings {
return;
};
if let Some(pos_px) = &mut self.inner_position_pixels {
clamp_pos_to_monitors(egui_zoom_factor, event_loop, inner_size_points, pos_px);
}
clamp_pos_to_monitors(
egui_zoom_factor,
event_loop,
inner_size_points,
&mut self.inner_position_pixels,
);
if let Some(pos_px) = &mut self.outer_position_pixels {
clamp_pos_to_monitors(egui_zoom_factor, event_loop, inner_size_points, pos_px);
}
@@ -143,74 +144,75 @@ impl WindowSettings {
fn find_active_monitor(
egui_zoom_factor: f32,
event_loop: &winit::event_loop::ActiveEventLoop,
event_loop: &dyn winit::event_loop::ActiveEventLoop,
window_size_pts: egui::Vec2,
position_px: &egui::Pos2,
) -> Option<winit::monitor::MonitorHandle> {
profiling::function_scope!();
let monitors = event_loop.available_monitors();
// default to primary monitor, in case the correct monitor was disconnected.
let Some(mut active_monitor) = event_loop
.primary_monitor()
.or_else(|| event_loop.available_monitors().next())
else {
return None; // no monitors 🤷
};
for monitor in monitors {
let window_size_px = window_size_pts * (egui_zoom_factor * monitor.scale_factor() as f32);
let monitor_x_range = (monitor.position().x - window_size_px.x as i32)
..(monitor.position().x + monitor.size().width as i32);
let monitor_y_range = (monitor.position().y - window_size_px.y as i32)
..(monitor.position().y + monitor.size().height as i32);
if monitor_x_range.contains(&(position_px.x as i32))
&& monitor_y_range.contains(&(position_px.y as i32))
{
active_monitor = monitor;
}
}
Some(active_monitor)
None // TODO
// profiling::function_scope!();
// let monitors = event_loop.available_monitors();
//
// // default to primary monitor, in case the correct monitor was disconnected.
// let Some(mut active_monitor) = event_loop
// .primary_monitor()
// .or_else(|| event_loop.available_monitors().next())
// else {
// return None; // no monitors 🤷
// };
//
// for monitor in monitors {
// let window_size_px = window_size_pts * (egui_zoom_factor * monitor.scale_factor() as f32);
// let monitor_x_range = (monitor.position().x - window_size_px.x as i32)
// ..(monitor.position().x + monitor.size().width as i32);
// let monitor_y_range = (monitor.position().y - window_size_px.y as i32)
// ..(monitor.position().y + monitor.size().height as i32);
//
// if monitor_x_range.contains(&(position_px.x as i32))
// && monitor_y_range.contains(&(position_px.y as i32))
// {
// active_monitor = monitor;
// }
// }
//
// Some(active_monitor)
}
fn clamp_pos_to_monitors(
egui_zoom_factor: f32,
event_loop: &winit::event_loop::ActiveEventLoop,
event_loop: &dyn winit::event_loop::ActiveEventLoop,
window_size_pts: egui::Vec2,
position_px: &mut egui::Pos2,
) {
profiling::function_scope!();
let Some(active_monitor) =
find_active_monitor(egui_zoom_factor, event_loop, window_size_pts, position_px)
else {
return; // no monitors 🤷
};
let mut window_size_px =
window_size_pts * (egui_zoom_factor * active_monitor.scale_factor() as f32);
// Add size of title bar. This is 32 px by default in Win 10/11.
if cfg!(target_os = "windows") {
window_size_px += egui::Vec2::new(
0.0,
32.0 * egui_zoom_factor * active_monitor.scale_factor() as f32,
);
}
let monitor_position = egui::Pos2::new(
active_monitor.position().x as f32,
active_monitor.position().y as f32,
);
let monitor_size_px = egui::Vec2::new(
active_monitor.size().width as f32,
active_monitor.size().height as f32,
);
// Window size cannot be negative or the subsequent `clamp` will panic.
let window_size = (monitor_size_px - window_size_px).max(egui::Vec2::ZERO);
// To get the maximum position, we get the rightmost corner of the display, then
// subtract the size of the window to get the bottom right most value window.position
// can have.
*position_px = position_px.clamp(monitor_position, monitor_position + window_size);
// profiling::function_scope!();
//
// let Some(active_monitor) =
// find_active_monitor(egui_zoom_factor, event_loop, window_size_pts, position_px)
// else {
// return; // no monitors 🤷
// };
//
// let mut window_size_px =
// window_size_pts * (egui_zoom_factor * active_monitor.scale_factor() as f32);
// // Add size of title bar. This is 32 px by default in Win 10/11.
// if cfg!(target_os = "windows") {
// window_size_px += egui::Vec2::new(
// 0.0,
// 32.0 * egui_zoom_factor * active_monitor.scale_factor() as f32,
// );
// }
// let monitor_position = egui::Pos2::new(
// active_monitor.position().x as f32,
// active_monitor.position().y as f32,
// );
// let monitor_size_px = egui::Vec2::new(
// active_monitor.size().width as f32,
// active_monitor.size().height as f32,
// );
//
// // Window size cannot be negative or the subsequent `clamp` will panic.
// let window_size = (monitor_size_px - window_size_px).max(egui::Vec2::ZERO);
// // To get the maximum position, we get the rightmost corner of the display, then
// // subtract the size of the window to get the bottom right most value window.position
// // can have.
// *position_px = position_px.clamp(monitor_position, monitor_position + window_size);
}