Improve multi-viewports across monitors with different scales (#3663)
It required some ugly code in `egui-winit` in order to fix this without breaking sem-ver (I want this to land in a 0.24.1 patch release). I'll clean up in time for 0.25. There is still a font rendering bug when using immediate viewports across multiple viewports, but that's harder to fix.
This commit is contained in:
parent
37244e3632
commit
61a7b90d5b
|
|
@ -229,8 +229,9 @@ impl EpiIntegration {
|
|||
|
||||
pub fn on_window_event(
|
||||
&mut self,
|
||||
event: &winit::event::WindowEvent<'_>,
|
||||
window: &winit::window::Window,
|
||||
egui_winit: &mut egui_winit::State,
|
||||
event: &winit::event::WindowEvent<'_>,
|
||||
) -> EventResponse {
|
||||
crate::profile_function!(egui_winit::short_window_event_description(event));
|
||||
|
||||
|
|
@ -254,6 +255,7 @@ impl EpiIntegration {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
egui_winit.update_pixels_per_point(&self.egui_ctx, window);
|
||||
egui_winit.on_window_event(&self.egui_ctx, event)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,10 +18,6 @@ use egui::{
|
|||
};
|
||||
#[cfg(feature = "accesskit")]
|
||||
use egui_winit::accesskit_winit;
|
||||
use egui_winit::{
|
||||
apply_viewport_builder_to_new_window, create_winit_window_builder, process_viewport_commands,
|
||||
EventResponse,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
native::{epi_integration::EpiIntegration, winit_integration::create_egui_context},
|
||||
|
|
@ -513,11 +509,13 @@ impl GlowWinitRunning {
|
|||
|
||||
let (raw_input, viewport_ui_cb) = {
|
||||
let mut glutin = self.glutin.borrow_mut();
|
||||
let egui_ctx = glutin.egui_ctx.clone();
|
||||
let viewport = glutin.viewports.get_mut(&viewport_id).unwrap();
|
||||
viewport.update_viewport_info();
|
||||
let window = viewport.window.as_ref().unwrap();
|
||||
egui_winit::update_viewport_info(&mut viewport.info, &egui_ctx, window);
|
||||
|
||||
let egui_winit = viewport.egui_winit.as_mut().unwrap();
|
||||
egui_winit.update_pixels_per_point(&egui_ctx, window);
|
||||
let mut raw_input = egui_winit.take_egui_input(window);
|
||||
let viewport_ui_cb = viewport.viewport_ui_cb.clone();
|
||||
|
||||
|
|
@ -744,15 +742,17 @@ impl GlowWinitRunning {
|
|||
return EventResult::Exit;
|
||||
}
|
||||
|
||||
let mut event_response = EventResponse {
|
||||
let mut event_response = egui_winit::EventResponse {
|
||||
consumed: false,
|
||||
repaint: false,
|
||||
};
|
||||
if let Some(viewport_id) = viewport_id {
|
||||
if let Some(viewport) = glutin.viewports.get_mut(&viewport_id) {
|
||||
event_response = self
|
||||
.integration
|
||||
.on_window_event(event, viewport.egui_winit.as_mut().unwrap());
|
||||
if let (Some(window), Some(egui_winit)) =
|
||||
(&viewport.window, &mut viewport.egui_winit)
|
||||
{
|
||||
event_response = self.integration.on_window_event(window, egui_winit, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -823,7 +823,7 @@ impl GlutinWindowContext {
|
|||
let display_builder = glutin_winit::DisplayBuilder::new()
|
||||
// we might want to expose this option to users in the future. maybe using an env var or using native_options.
|
||||
.with_preference(glutin_winit::ApiPrefence::FallbackEgl) // https://github.com/emilk/egui/issues/2520#issuecomment-1367841150
|
||||
.with_window_builder(Some(create_winit_window_builder(
|
||||
.with_window_builder(Some(egui_winit::create_winit_window_builder(
|
||||
egui_ctx,
|
||||
event_loop,
|
||||
viewport_builder.clone(),
|
||||
|
|
@ -849,7 +849,7 @@ impl GlutinWindowContext {
|
|||
.map_err(|e| crate::Error::NoGlutinConfigs(config_template_builder.build(), e))?
|
||||
};
|
||||
if let Some(window) = &window {
|
||||
apply_viewport_builder_to_new_window(window, &viewport_builder);
|
||||
egui_winit::apply_viewport_builder_to_window(egui_ctx, window, &viewport_builder);
|
||||
}
|
||||
|
||||
let gl_display = gl_config.display();
|
||||
|
|
@ -981,12 +981,18 @@ impl GlutinWindowContext {
|
|||
window
|
||||
} else {
|
||||
log::trace!("Window doesn't exist yet. Creating one now with finalize_window");
|
||||
let window = glutin_winit::finalize_window(
|
||||
let window_builder = egui_winit::create_winit_window_builder(
|
||||
&self.egui_ctx,
|
||||
event_loop,
|
||||
create_winit_window_builder(&self.egui_ctx, event_loop, viewport.builder.clone()),
|
||||
&self.gl_config,
|
||||
)?;
|
||||
apply_viewport_builder_to_new_window(&window, &viewport.builder);
|
||||
viewport.builder.clone(),
|
||||
);
|
||||
let window =
|
||||
glutin_winit::finalize_window(event_loop, window_builder, &self.gl_config)?;
|
||||
egui_winit::apply_viewport_builder_to_window(
|
||||
&self.egui_ctx,
|
||||
&window,
|
||||
&viewport.builder,
|
||||
);
|
||||
viewport.info.minimized = window.is_minimized();
|
||||
viewport.info.maximized = Some(window.is_maximized());
|
||||
viewport.window.insert(Rc::new(window))
|
||||
|
|
@ -1167,19 +1173,6 @@ impl GlutinWindowContext {
|
|||
}
|
||||
}
|
||||
|
||||
impl Viewport {
|
||||
/// Update the stored `ViewportInfo`.
|
||||
fn update_viewport_info(&mut self) {
|
||||
let Some(window) = &self.window else {
|
||||
return;
|
||||
};
|
||||
let Some(egui_winit) = &self.egui_winit else {
|
||||
return;
|
||||
};
|
||||
egui_winit.update_viewport_info(&mut self.info, window);
|
||||
}
|
||||
}
|
||||
|
||||
fn initialize_or_update_viewport<'vp>(
|
||||
egu_ctx: &'_ egui::Context,
|
||||
viewports: &'vp mut ViewportIdMap<Viewport>,
|
||||
|
|
@ -1235,7 +1228,7 @@ fn initialize_or_update_viewport<'vp>(
|
|||
viewport.egui_winit = None;
|
||||
} else if let Some(window) = &viewport.window {
|
||||
let is_viewport_focused = focused_viewport == Some(ids.this);
|
||||
process_viewport_commands(
|
||||
egui_winit::process_viewport_commands(
|
||||
egu_ctx,
|
||||
&mut viewport.info,
|
||||
delta_commands,
|
||||
|
|
@ -1294,15 +1287,16 @@ fn render_immediate_viewport(
|
|||
let Some(viewport) = glutin.viewports.get_mut(&ids.this) else {
|
||||
return;
|
||||
};
|
||||
viewport.update_viewport_info();
|
||||
let Some(winit_state) = &mut viewport.egui_winit else {
|
||||
let Some(egui_winit) = &mut viewport.egui_winit else {
|
||||
return;
|
||||
};
|
||||
let Some(window) = &viewport.window else {
|
||||
return;
|
||||
};
|
||||
egui_winit::update_viewport_info(&mut viewport.info, egui_ctx, window);
|
||||
|
||||
let mut raw_input = winit_state.take_egui_input(window);
|
||||
egui_winit.update_pixels_per_point(egui_ctx, window);
|
||||
let mut raw_input = egui_winit.take_egui_input(window);
|
||||
raw_input.viewports = glutin
|
||||
.viewports
|
||||
.iter()
|
||||
|
|
|
|||
|
|
@ -14,9 +14,6 @@ use egui::{
|
|||
};
|
||||
#[cfg(feature = "accesskit")]
|
||||
use egui_winit::accesskit_winit;
|
||||
use egui_winit::{
|
||||
apply_viewport_builder_to_new_window, create_winit_window_builder, process_viewport_commands,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
native::{epi_integration::EpiIntegration, winit_integration::EventResult},
|
||||
|
|
@ -485,7 +482,10 @@ impl WgpuWinitRunning {
|
|||
let mut shared_lock = shared.borrow_mut();
|
||||
|
||||
let SharedState {
|
||||
viewports, painter, ..
|
||||
egui_ctx,
|
||||
viewports,
|
||||
painter,
|
||||
..
|
||||
} = &mut *shared_lock;
|
||||
|
||||
if viewport_id != ViewportId::ROOT {
|
||||
|
|
@ -508,12 +508,12 @@ impl WgpuWinitRunning {
|
|||
let Some(viewport) = viewports.get_mut(&viewport_id) else {
|
||||
return EventResult::Wait;
|
||||
};
|
||||
viewport.update_viewport_info();
|
||||
|
||||
let Viewport {
|
||||
viewport_ui_cb,
|
||||
window,
|
||||
egui_winit,
|
||||
info,
|
||||
..
|
||||
} = viewport;
|
||||
|
||||
|
|
@ -522,6 +522,7 @@ impl WgpuWinitRunning {
|
|||
let Some(window) = window else {
|
||||
return EventResult::Wait;
|
||||
};
|
||||
egui_winit::update_viewport_info(info, &integration.egui_ctx, window);
|
||||
|
||||
{
|
||||
crate::profile_scope!("set_window");
|
||||
|
|
@ -531,7 +532,9 @@ impl WgpuWinitRunning {
|
|||
}
|
||||
}
|
||||
|
||||
let mut raw_input = egui_winit.as_mut().unwrap().take_egui_input(window);
|
||||
let egui_winit = egui_winit.as_mut().unwrap();
|
||||
egui_winit.update_pixels_per_point(egui_ctx, window);
|
||||
let mut raw_input = egui_winit.take_egui_input(window);
|
||||
|
||||
integration.pre_update();
|
||||
|
||||
|
|
@ -745,10 +748,11 @@ impl WgpuWinitRunning {
|
|||
let event_response = viewport_id
|
||||
.and_then(|viewport_id| {
|
||||
shared.viewports.get_mut(&viewport_id).and_then(|viewport| {
|
||||
viewport
|
||||
.egui_winit
|
||||
.as_mut()
|
||||
.map(|egui_winit| integration.on_window_event(event, egui_winit))
|
||||
Some(integration.on_window_event(
|
||||
viewport.window.as_deref()?,
|
||||
viewport.egui_winit.as_mut()?,
|
||||
event,
|
||||
))
|
||||
})
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
|
@ -779,12 +783,8 @@ impl Viewport {
|
|||
|
||||
let viewport_id = self.ids.this;
|
||||
|
||||
match create_winit_window_builder(egui_ctx, event_loop, self.builder.clone())
|
||||
.build(event_loop)
|
||||
{
|
||||
match egui_winit::create_window(egui_ctx, event_loop, &self.builder) {
|
||||
Ok(window) => {
|
||||
apply_viewport_builder_to_new_window(&window, &self.builder);
|
||||
|
||||
windows_id.insert(window.id(), viewport_id);
|
||||
|
||||
if let Err(err) = pollster::block_on(painter.set_window(viewport_id, Some(&window)))
|
||||
|
|
@ -809,18 +809,6 @@ impl Viewport {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Update the stored `ViewportInfo`.
|
||||
pub fn update_viewport_info(&mut self) {
|
||||
crate::profile_function!();
|
||||
let Some(window) = &self.window else {
|
||||
return;
|
||||
};
|
||||
let Some(egui_winit) = &self.egui_winit else {
|
||||
return;
|
||||
};
|
||||
egui_winit.update_viewport_info(&mut self.info, window);
|
||||
}
|
||||
}
|
||||
|
||||
fn create_window(
|
||||
|
|
@ -840,12 +828,7 @@ fn create_window(
|
|||
)
|
||||
.with_visible(false); // Start hidden until we render the first frame to fix white flash on startup (https://github.com/emilk/egui/pull/3631)
|
||||
|
||||
let window = {
|
||||
crate::profile_scope!("WindowBuilder::build");
|
||||
create_winit_window_builder(egui_ctx, event_loop, viewport_builder.clone())
|
||||
.build(event_loop)?
|
||||
};
|
||||
apply_viewport_builder_to_new_window(&window, &viewport_builder);
|
||||
let window = egui_winit::create_window(egui_ctx, event_loop, &viewport_builder)?;
|
||||
epi_integration::apply_window_settings(&window, window_settings);
|
||||
Ok((window, viewport_builder))
|
||||
}
|
||||
|
|
@ -885,12 +868,13 @@ fn render_immediate_viewport(
|
|||
if viewport.window.is_none() {
|
||||
viewport.init_window(egui_ctx, viewport_from_window, painter, event_loop);
|
||||
}
|
||||
viewport.update_viewport_info();
|
||||
|
||||
let (Some(window), Some(winit_state)) = (&viewport.window, &mut viewport.egui_winit) else {
|
||||
return;
|
||||
};
|
||||
egui_winit::update_viewport_info(&mut viewport.info, egui_ctx, window);
|
||||
|
||||
winit_state.update_pixels_per_point(egui_ctx, window);
|
||||
let mut input = winit_state.take_egui_input(window);
|
||||
input.viewports = viewports
|
||||
.iter()
|
||||
|
|
@ -1056,7 +1040,7 @@ fn initialize_or_update_viewport<'vp>(
|
|||
viewport.egui_winit = None;
|
||||
} else if let Some(window) = &viewport.window {
|
||||
let is_viewport_focused = focused_viewport == Some(ids.this);
|
||||
process_viewport_commands(
|
||||
egui_winit::process_viewport_commands(
|
||||
egui_ctx,
|
||||
&mut viewport.info,
|
||||
delta_commands,
|
||||
|
|
|
|||
|
|
@ -38,6 +38,13 @@ pub fn screen_size_in_pixels(window: &Window) -> egui::Vec2 {
|
|||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#[must_use]
|
||||
|
|
@ -70,7 +77,7 @@ pub struct State {
|
|||
current_cursor_icon: Option<egui::CursorIcon>,
|
||||
|
||||
/// What egui uses.
|
||||
current_pixels_per_point: f32,
|
||||
current_pixels_per_point: f32, // TODO: remove - calculate with [`pixels_per_point`] instead
|
||||
|
||||
clipboard: clipboard::Clipboard,
|
||||
|
||||
|
|
@ -164,9 +171,8 @@ impl State {
|
|||
self.egui_input.max_texture_side = Some(max_texture_side);
|
||||
}
|
||||
|
||||
/// The number of physical pixels per logical point,
|
||||
/// as configured on the current egui context (see [`egui::Context::pixels_per_point`]).
|
||||
#[inline]
|
||||
#[deprecated = "Use egui_winit::pixels_per_point instead"]
|
||||
pub fn pixels_per_point(&self) -> f32 {
|
||||
self.current_pixels_per_point
|
||||
}
|
||||
|
|
@ -186,10 +192,9 @@ impl State {
|
|||
}
|
||||
|
||||
/// Update the given viewport info with the current state of the window.
|
||||
///
|
||||
/// Call before [`Self::update_viewport_info`]
|
||||
#[deprecated = "Use egui_winit::update_viewport_info instead"]
|
||||
pub fn update_viewport_info(&self, info: &mut ViewportInfo, window: &Window) {
|
||||
update_viewport_info(info, window, self.current_pixels_per_point);
|
||||
update_viewport_info_impl(info, window, self.current_pixels_per_point);
|
||||
}
|
||||
|
||||
/// Prepare for a new frame by extracting the accumulated input,
|
||||
|
|
@ -226,6 +231,12 @@ impl State {
|
|||
self.egui_input.take()
|
||||
}
|
||||
|
||||
// TODO(emilk): remove asap.
|
||||
#[doc(hidden)]
|
||||
pub fn update_pixels_per_point(&mut self, egui_ctx: &egui::Context, window: &Window) {
|
||||
self.current_pixels_per_point = pixels_per_point(egui_ctx, window);
|
||||
}
|
||||
|
||||
/// Call this when there is a new event.
|
||||
///
|
||||
/// The result can be found in [`Self::egui_input`] and be extracted with [`Self::take_egui_input`].
|
||||
|
|
@ -511,8 +522,8 @@ impl State {
|
|||
|
||||
fn on_cursor_moved(&mut self, pos_in_pixels: winit::dpi::PhysicalPosition<f64>) {
|
||||
let pos_in_points = egui::pos2(
|
||||
pos_in_pixels.x as f32 / self.pixels_per_point(),
|
||||
pos_in_pixels.y as f32 / self.pixels_per_point(),
|
||||
pos_in_pixels.x as f32 / self.current_pixels_per_point,
|
||||
pos_in_pixels.y as f32 / self.current_pixels_per_point,
|
||||
);
|
||||
self.pointer_pos_in_points = Some(pos_in_points);
|
||||
|
||||
|
|
@ -549,8 +560,8 @@ impl State {
|
|||
winit::event::TouchPhase::Cancelled => egui::TouchPhase::Cancel,
|
||||
},
|
||||
pos: egui::pos2(
|
||||
touch.location.x as f32 / self.pixels_per_point(),
|
||||
touch.location.y as f32 / self.pixels_per_point(),
|
||||
touch.location.x as f32 / self.current_pixels_per_point,
|
||||
touch.location.y as f32 / self.current_pixels_per_point,
|
||||
),
|
||||
force: match touch.force {
|
||||
Some(winit::event::Force::Normalized(force)) => Some(force as f32),
|
||||
|
|
@ -610,7 +621,7 @@ impl State {
|
|||
y,
|
||||
}) => (
|
||||
egui::MouseWheelUnit::Point,
|
||||
egui::vec2(x as f32, y as f32) / self.pixels_per_point(),
|
||||
egui::vec2(x as f32, y as f32) / self.current_pixels_per_point,
|
||||
),
|
||||
};
|
||||
let modifiers = self.egui_input.modifiers;
|
||||
|
|
@ -626,7 +637,7 @@ impl State {
|
|||
egui::vec2(x, y) * points_per_scroll_line
|
||||
}
|
||||
winit::event::MouseScrollDelta::PixelDelta(delta) => {
|
||||
egui::vec2(delta.x as f32, delta.y as f32) / self.pixels_per_point()
|
||||
egui::vec2(delta.x as f32, delta.y as f32) / self.current_pixels_per_point
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -758,7 +769,18 @@ impl State {
|
|||
}
|
||||
}
|
||||
|
||||
fn update_viewport_info(viewport_info: &mut ViewportInfo, window: &Window, pixels_per_point: f32) {
|
||||
/// Update the given viewport info with the current state of the window.
|
||||
///
|
||||
/// Call before [`State::take_egui_input`].
|
||||
pub fn update_viewport_info(info: &mut ViewportInfo, egui_ctx: &egui::Context, window: &Window) {
|
||||
update_viewport_info_impl(info, window, pixels_per_point(egui_ctx, window));
|
||||
}
|
||||
|
||||
fn update_viewport_info_impl(
|
||||
viewport_info: &mut ViewportInfo,
|
||||
window: &Window,
|
||||
pixels_per_point: f32,
|
||||
) {
|
||||
crate::profile_function!();
|
||||
|
||||
let has_a_position = match window.is_minimized() {
|
||||
|
|
@ -1072,8 +1094,7 @@ fn process_viewport_command(
|
|||
|
||||
log::debug!("Processing ViewportCommand::{command:?}");
|
||||
|
||||
let egui_zoom_factor = egui_ctx.zoom_factor();
|
||||
let pixels_per_point = egui_zoom_factor * window.scale_factor() as f32;
|
||||
let pixels_per_point = pixels_per_point(egui_ctx, window);
|
||||
|
||||
match command {
|
||||
ViewportCommand::Close => {
|
||||
|
|
@ -1244,6 +1265,26 @@ fn process_viewport_command(
|
|||
}
|
||||
}
|
||||
|
||||
/// Build and intitlaize a window.
|
||||
///
|
||||
/// Wrapper around `create_winit_window_builder` and `apply_viewport_builder_to_window`.
|
||||
pub fn create_window<T>(
|
||||
egui_ctx: &egui::Context,
|
||||
event_loop: &EventLoopWindowTarget<T>,
|
||||
viewport_builder: &ViewportBuilder,
|
||||
) -> Result<Window, winit::error::OsError> {
|
||||
crate::profile_function!();
|
||||
|
||||
let window_builder =
|
||||
create_winit_window_builder(egui_ctx, event_loop, viewport_builder.clone());
|
||||
let window = {
|
||||
crate::profile_scope!("WindowBuilder::build");
|
||||
window_builder.build(event_loop)?
|
||||
};
|
||||
apply_viewport_builder_to_window(egui_ctx, &window, viewport_builder);
|
||||
Ok(window)
|
||||
}
|
||||
|
||||
pub fn create_winit_window_builder<T>(
|
||||
egui_ctx: &egui::Context,
|
||||
event_loop: &EventLoopWindowTarget<T>,
|
||||
|
|
@ -1253,6 +1294,8 @@ pub fn create_winit_window_builder<T>(
|
|||
|
||||
// We set sizes and positions in egui:s own ui points, which depends on the egui
|
||||
// zoom_factor and the native pixels per point, so we need to know that here.
|
||||
// We don't know what monitor the window will appear on though, but
|
||||
// we'll try to fix that after the window is created in the vall to `apply_viewport_builder_to_window`.
|
||||
let native_pixels_per_point = event_loop
|
||||
.primary_monitor()
|
||||
.or_else(|| event_loop.available_monitors().next())
|
||||
|
|
@ -1297,7 +1340,7 @@ pub fn create_winit_window_builder<T>(
|
|||
// wayland:
|
||||
app_id: _app_id,
|
||||
|
||||
mouse_passthrough: _, // handled in `apply_viewport_builder_to_new_window`
|
||||
mouse_passthrough: _, // handled in `apply_viewport_builder_to_window`
|
||||
} = viewport_builder;
|
||||
|
||||
let mut window_builder = winit::window::WindowBuilder::new()
|
||||
|
|
@ -1330,31 +1373,31 @@ pub fn create_winit_window_builder<T>(
|
|||
})
|
||||
.with_active(active.unwrap_or(true));
|
||||
|
||||
if let Some(inner_size) = inner_size {
|
||||
if let Some(size) = inner_size {
|
||||
window_builder = window_builder.with_inner_size(PhysicalSize::new(
|
||||
pixels_per_point * inner_size.x,
|
||||
pixels_per_point * inner_size.y,
|
||||
pixels_per_point * size.x,
|
||||
pixels_per_point * size.y,
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(min_inner_size) = min_inner_size {
|
||||
if let Some(size) = min_inner_size {
|
||||
window_builder = window_builder.with_min_inner_size(PhysicalSize::new(
|
||||
pixels_per_point * min_inner_size.x,
|
||||
pixels_per_point * min_inner_size.y,
|
||||
pixels_per_point * size.x,
|
||||
pixels_per_point * size.y,
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(max_inner_size) = max_inner_size {
|
||||
if let Some(size) = max_inner_size {
|
||||
window_builder = window_builder.with_max_inner_size(PhysicalSize::new(
|
||||
pixels_per_point * max_inner_size.x,
|
||||
pixels_per_point * max_inner_size.y,
|
||||
pixels_per_point * size.x,
|
||||
pixels_per_point * size.y,
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(position) = position {
|
||||
if let Some(pos) = position {
|
||||
window_builder = window_builder.with_position(PhysicalPosition::new(
|
||||
pixels_per_point * position.x,
|
||||
pixels_per_point * position.y,
|
||||
pixels_per_point * pos.x,
|
||||
pixels_per_point * pos.y,
|
||||
));
|
||||
}
|
||||
|
||||
|
|
@ -1391,6 +1434,7 @@ pub fn create_winit_window_builder<T>(
|
|||
}
|
||||
|
||||
/// Applies what `create_winit_window_builder` couldn't
|
||||
#[deprecated = "Use apply_viewport_builder_to_window instead"]
|
||||
pub fn apply_viewport_builder_to_new_window(window: &Window, builder: &ViewportBuilder) {
|
||||
if let Some(mouse_passthrough) = builder.mouse_passthrough {
|
||||
if let Err(err) = window.set_cursor_hittest(!mouse_passthrough) {
|
||||
|
|
@ -1399,6 +1443,51 @@ pub fn apply_viewport_builder_to_new_window(window: &Window, builder: &ViewportB
|
|||
}
|
||||
}
|
||||
|
||||
/// Applies what `create_winit_window_builder` couldn't
|
||||
pub fn apply_viewport_builder_to_window(
|
||||
egui_ctx: &egui::Context,
|
||||
window: &Window,
|
||||
builder: &ViewportBuilder,
|
||||
) {
|
||||
if let Some(mouse_passthrough) = builder.mouse_passthrough {
|
||||
if let Err(err) = window.set_cursor_hittest(!mouse_passthrough) {
|
||||
log::warn!("set_cursor_hittest failed: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// In `create_winit_window_builder` we didn't know
|
||||
// on what monitor the window would appear, so we didn't know
|
||||
// how to translate egui ui point to native physical pixels.
|
||||
// Now we do know:
|
||||
|
||||
let pixels_per_point = pixels_per_point(egui_ctx, window);
|
||||
|
||||
if let Some(size) = builder.inner_size {
|
||||
window.set_inner_size(PhysicalSize::new(
|
||||
pixels_per_point * size.x,
|
||||
pixels_per_point * size.y,
|
||||
));
|
||||
}
|
||||
if let Some(size) = builder.min_inner_size {
|
||||
window.set_min_inner_size(Some(PhysicalSize::new(
|
||||
pixels_per_point * size.x,
|
||||
pixels_per_point * size.y,
|
||||
)));
|
||||
}
|
||||
if let Some(size) = builder.max_inner_size {
|
||||
window.set_max_inner_size(Some(PhysicalSize::new(
|
||||
pixels_per_point * size.x,
|
||||
pixels_per_point * size.y,
|
||||
)));
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Short and fast description of an event.
|
||||
|
|
|
|||
|
|
@ -262,6 +262,7 @@ pub struct ViewportBuilder {
|
|||
/// This is wayland only. See [`Self::with_app_id`].
|
||||
pub app_id: Option<String>,
|
||||
|
||||
/// The desired outer position of the window.
|
||||
pub position: Option<Pos2>,
|
||||
pub inner_size: Option<Vec2>,
|
||||
pub min_inner_size: Option<Vec2>,
|
||||
|
|
@ -506,7 +507,8 @@ impl ViewportBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
/// This will probably not work as expected!
|
||||
/// The initial "outer" position of the window,
|
||||
/// i.e. where the top-left corner of the frame/chrome should be.
|
||||
#[inline]
|
||||
pub fn with_position(mut self, pos: impl Into<Pos2>) -> Self {
|
||||
self.position = Some(pos.into());
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ impl EguiGlow {
|
|||
native_pixels_per_point,
|
||||
Some(painter.max_texture_side()),
|
||||
);
|
||||
let pixels_per_point = egui_winit.pixels_per_point();
|
||||
|
||||
Self {
|
||||
egui_ctx: Default::default(),
|
||||
|
|
@ -48,7 +47,7 @@ impl EguiGlow {
|
|||
painter,
|
||||
viewport_info: Default::default(),
|
||||
shapes: Default::default(),
|
||||
pixels_per_point,
|
||||
pixels_per_point: native_pixels_per_point.unwrap_or(1.0),
|
||||
textures_delta: Default::default(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,13 @@ impl<T: Float> Hash for OrderedFloat<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for OrderedFloat<T> {
|
||||
#[inline]
|
||||
fn from(val: T) -> Self {
|
||||
OrderedFloat(val)
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// Extension trait to provide `ord()` method.
|
||||
|
|
|
|||
|
|
@ -68,11 +68,14 @@ impl ViewportState {
|
|||
|
||||
let viewport = ViewportBuilder::default()
|
||||
.with_title(&title)
|
||||
.with_inner_size([450.0, 400.0]);
|
||||
.with_inner_size([500.0, 500.0]);
|
||||
|
||||
if immediate {
|
||||
let mut vp_state = vp_state.write();
|
||||
ctx.show_viewport_immediate(vp_id, viewport, move |ctx, class| {
|
||||
if ctx.input(|i| i.viewport().close_requested()) {
|
||||
vp_state.visible = false;
|
||||
}
|
||||
show_as_popup(ctx, class, &title, vp_id.into(), |ui: &mut egui::Ui| {
|
||||
generic_child_ui(ui, &mut vp_state);
|
||||
});
|
||||
|
|
@ -81,6 +84,9 @@ impl ViewportState {
|
|||
let count = Arc::new(RwLock::new(0));
|
||||
ctx.show_viewport_deferred(vp_id, viewport, move |ctx, class| {
|
||||
let mut vp_state = vp_state.write();
|
||||
if ctx.input(|i| i.viewport().close_requested()) {
|
||||
vp_state.visible = false;
|
||||
}
|
||||
let count = count.clone();
|
||||
show_as_popup(
|
||||
ctx,
|
||||
|
|
@ -220,22 +226,36 @@ fn generic_ui(ui: &mut egui::Ui, children: &[Arc<RwLock<ViewportState>>]) {
|
|||
ctx.parent_viewport_id()
|
||||
));
|
||||
|
||||
ui.add_space(8.0);
|
||||
ui.collapsing("Info", |ui| {
|
||||
ui.label(format!("zoom_factor: {}", ctx.zoom_factor()));
|
||||
ui.label(format!("pixels_per_point: {}", ctx.pixels_per_point()));
|
||||
|
||||
if let Some(inner_rect) = ctx.input(|i| i.viewport().inner_rect) {
|
||||
ui.label(format!(
|
||||
"Inner Rect: Pos: {:?}, Size: {:?}",
|
||||
inner_rect.min,
|
||||
inner_rect.size()
|
||||
));
|
||||
}
|
||||
if let Some(outer_rect) = ctx.input(|i| i.viewport().outer_rect) {
|
||||
ui.label(format!(
|
||||
"Outer Rect: Pos: {:?}, Size: {:?}",
|
||||
outer_rect.min,
|
||||
outer_rect.size()
|
||||
));
|
||||
}
|
||||
if let Some(native_pixels_per_point) = ctx.input(|i| i.viewport().native_pixels_per_point) {
|
||||
ui.label(format!(
|
||||
"native_pixels_per_point: {native_pixels_per_point:?}"
|
||||
));
|
||||
}
|
||||
if let Some(monitor_size) = ctx.input(|i| i.viewport().monitor_size) {
|
||||
ui.label(format!("monitor_size: {monitor_size:?} (points)"));
|
||||
}
|
||||
if let Some(screen_rect) = ui.input(|i| i.raw.screen_rect) {
|
||||
ui.label(format!("Screen rect size: Pos: {:?}", screen_rect.size()));
|
||||
}
|
||||
if let Some(inner_rect) = ctx.input(|i| i.viewport().inner_rect) {
|
||||
ui.label(format!(
|
||||
"Inner Rect: Pos: {:?}, Size: {:?} (points)",
|
||||
inner_rect.min,
|
||||
inner_rect.size()
|
||||
));
|
||||
}
|
||||
if let Some(outer_rect) = ctx.input(|i| i.viewport().outer_rect) {
|
||||
ui.label(format!(
|
||||
"Outer Rect: Pos: {:?}, Size: {:?} (points)",
|
||||
outer_rect.min,
|
||||
outer_rect.size()
|
||||
));
|
||||
}
|
||||
});
|
||||
|
||||
if ctx.viewport_id() != ctx.parent_viewport_id() {
|
||||
let parent = ctx.parent_viewport_id();
|
||||
|
|
|
|||
Loading…
Reference in New Issue