Simplify `egui_winit::State` (#3678)

By storing a clone of the egui context in it, we can be sure to always
use the correct `pixels_per_point`
This commit is contained in:
Emil Ernerfeldt 2023-12-05 11:45:25 +01:00 committed by GitHub
parent 80d7143b15
commit a4e389431d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 70 additions and 84 deletions

View File

@ -255,8 +255,7 @@ impl EpiIntegration {
_ => {} _ => {}
} }
egui_winit.update_pixels_per_point(&self.egui_ctx, window); egui_winit.on_window_event(window, event)
egui_winit.on_window_event(&self.egui_ctx, event)
} }
pub fn pre_update(&mut self) { pub fn pre_update(&mut self) {

View File

@ -517,7 +517,6 @@ impl GlowWinitRunning {
egui_winit::update_viewport_info(&mut viewport.info, &egui_ctx, window); egui_winit::update_viewport_info(&mut viewport.info, &egui_ctx, window);
let egui_winit = viewport.egui_winit.as_mut().unwrap(); 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 mut raw_input = egui_winit.take_egui_input(window);
let viewport_ui_cb = viewport.viewport_ui_cb.clone(); let viewport_ui_cb = viewport.viewport_ui_cb.clone();
@ -600,7 +599,7 @@ impl GlowWinitRunning {
let egui_winit = viewport.egui_winit.as_mut().unwrap(); let egui_winit = viewport.egui_winit.as_mut().unwrap();
integration.post_update(); integration.post_update();
egui_winit.handle_platform_output(window, &integration.egui_ctx, platform_output); egui_winit.handle_platform_output(window, platform_output);
let clipped_primitives = integration.egui_ctx.tessellate(shapes, pixels_per_point); let clipped_primitives = integration.egui_ctx.tessellate(shapes, pixels_per_point);
@ -1066,6 +1065,7 @@ impl GlutinWindowContext {
viewport.egui_winit.get_or_insert_with(|| { viewport.egui_winit.get_or_insert_with(|| {
egui_winit::State::new( egui_winit::State::new(
self.egui_ctx.clone(),
viewport_id, viewport_id,
event_loop, event_loop,
Some(window.scale_factor() as f32), Some(window.scale_factor() as f32),
@ -1318,7 +1318,6 @@ fn render_immediate_viewport(
}; };
egui_winit::update_viewport_info(&mut viewport.info, egui_ctx, window); egui_winit::update_viewport_info(&mut viewport.info, egui_ctx, window);
egui_winit.update_pixels_per_point(egui_ctx, window);
let mut raw_input = egui_winit.take_egui_input(window); let mut raw_input = egui_winit.take_egui_input(window);
raw_input.viewports = glutin raw_input.viewports = glutin
.viewports .viewports
@ -1414,7 +1413,7 @@ fn render_immediate_viewport(
} }
} }
egui_winit.handle_platform_output(window, egui_ctx, platform_output); egui_winit.handle_platform_output(window, platform_output);
glutin.handle_viewport_output(egui_ctx, viewport_output); glutin.handle_viewport_output(egui_ctx, viewport_output);
} }

View File

@ -205,6 +205,7 @@ impl WgpuWinitApp {
#[allow(unused_mut)] // used for accesskit #[allow(unused_mut)] // used for accesskit
let mut egui_winit = egui_winit::State::new( let mut egui_winit = egui_winit::State::new(
egui_ctx.clone(),
ViewportId::ROOT, ViewportId::ROOT,
event_loop, event_loop,
Some(window.scale_factor() as f32), Some(window.scale_factor() as f32),
@ -488,10 +489,7 @@ impl WgpuWinitRunning {
let mut shared_lock = shared.borrow_mut(); let mut shared_lock = shared.borrow_mut();
let SharedState { let SharedState {
egui_ctx, viewports, painter, ..
viewports,
painter,
..
} = &mut *shared_lock; } = &mut *shared_lock;
if viewport_id != ViewportId::ROOT { if viewport_id != ViewportId::ROOT {
@ -539,7 +537,6 @@ impl WgpuWinitRunning {
} }
let egui_winit = egui_winit.as_mut().unwrap(); 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); let mut raw_input = egui_winit.take_egui_input(window);
integration.pre_update(); integration.pre_update();
@ -596,7 +593,7 @@ impl WgpuWinitRunning {
viewport_output, viewport_output,
} = full_output; } = full_output;
egui_winit.handle_platform_output(window, egui_ctx, platform_output); egui_winit.handle_platform_output(window, platform_output);
{ {
let clipped_primitives = egui_ctx.tessellate(shapes, pixels_per_point); let clipped_primitives = egui_ctx.tessellate(shapes, pixels_per_point);
@ -799,6 +796,7 @@ impl Viewport {
} }
self.egui_winit = Some(egui_winit::State::new( self.egui_winit = Some(egui_winit::State::new(
egui_ctx.clone(),
viewport_id, viewport_id,
event_loop, event_loop,
Some(window.scale_factor() as f32), Some(window.scale_factor() as f32),
@ -880,7 +878,6 @@ fn render_immediate_viewport(
}; };
egui_winit::update_viewport_info(&mut viewport.info, egui_ctx, window); egui_winit::update_viewport_info(&mut viewport.info, egui_ctx, window);
egui_winit.update_pixels_per_point(egui_ctx, window);
let mut input = egui_winit.take_egui_input(window); let mut input = egui_winit.take_egui_input(window);
input.viewports = viewports input.viewports = viewports
.iter() .iter()
@ -944,7 +941,7 @@ fn render_immediate_viewport(
false, false,
); );
egui_winit.handle_platform_output(window, &egui_ctx, platform_output); egui_winit.handle_platform_output(window, platform_output);
handle_viewport_output(&egui_ctx, viewport_output, viewports, *focused_viewport); handle_viewport_output(&egui_ctx, viewport_output, viewports, *focused_viewport);
} }

View File

@ -69,6 +69,9 @@ pub struct EventResponse {
/// ///
/// Instantiate one of these per viewport/window. /// Instantiate one of these per viewport/window.
pub struct State { pub struct State {
/// Shared clone.
egui_ctx: egui::Context,
viewport_id: ViewportId, viewport_id: ViewportId,
start_time: web_time::Instant, start_time: web_time::Instant,
egui_input: egui::RawInput, egui_input: egui::RawInput,
@ -76,9 +79,6 @@ pub struct State {
any_pointer_button_down: bool, any_pointer_button_down: bool,
current_cursor_icon: Option<egui::CursorIcon>, current_cursor_icon: Option<egui::CursorIcon>,
/// What egui uses.
current_pixels_per_point: f32, // TODO: remove - calculate with [`pixels_per_point`] instead
clipboard: clipboard::Clipboard, clipboard: clipboard::Clipboard,
/// If `true`, mouse inputs will be treated as touches. /// If `true`, mouse inputs will be treated as touches.
@ -104,6 +104,7 @@ pub struct State {
impl State { impl State {
/// Construct a new instance /// Construct a new instance
pub fn new( pub fn new(
egui_ctx: egui::Context,
viewport_id: ViewportId, viewport_id: ViewportId,
display_target: &dyn HasRawDisplayHandle, display_target: &dyn HasRawDisplayHandle,
native_pixels_per_point: Option<f32>, native_pixels_per_point: Option<f32>,
@ -117,13 +118,13 @@ impl State {
}; };
let mut slf = Self { let mut slf = Self {
egui_ctx,
viewport_id, viewport_id,
start_time: web_time::Instant::now(), start_time: web_time::Instant::now(),
egui_input, egui_input,
pointer_pos_in_points: None, pointer_pos_in_points: None,
any_pointer_button_down: false, any_pointer_button_down: false,
current_cursor_icon: None, current_cursor_icon: None,
current_pixels_per_point: native_pixels_per_point.unwrap_or(1.0),
clipboard: clipboard::Clipboard::new(display_target), clipboard: clipboard::Clipboard::new(display_target),
@ -172,9 +173,8 @@ impl State {
} }
#[inline] #[inline]
#[deprecated = "Use egui_winit::pixels_per_point instead"] pub fn egui_ctx(&self) -> &egui::Context {
pub fn pixels_per_point(&self) -> f32 { &self.egui_ctx
self.current_pixels_per_point
} }
/// The current input state. /// The current input state.
@ -191,18 +191,12 @@ impl State {
&mut self.egui_input &mut self.egui_input
} }
/// Update the given viewport info with the current state of the window.
#[deprecated = "Use egui_winit::update_viewport_info instead"]
pub fn update_viewport_info(&self, info: &mut ViewportInfo, window: &Window) {
update_viewport_info_impl(info, window, self.current_pixels_per_point);
}
/// Prepare for a new frame by extracting the accumulated input, /// Prepare for a new frame by extracting the accumulated input,
/// ///
/// as well as setting [the time](egui::RawInput::time) and [screen rectangle](egui::RawInput::screen_rect). /// as well as setting [the time](egui::RawInput::time) and [screen rectangle](egui::RawInput::screen_rect).
/// ///
/// You need to set [`egui::RawInput::viewports`] yourself though. /// You need to set [`egui::RawInput::viewports`] yourself though.
/// Use [`Self::update_viewport_info`] to update the info for each /// Use [`update_viewport_info`] to update the info for each
/// viewport. /// viewport.
pub fn take_egui_input(&mut self, window: &Window) -> egui::RawInput { pub fn take_egui_input(&mut self, window: &Window) -> egui::RawInput {
crate::profile_function!(); crate::profile_function!();
@ -213,7 +207,8 @@ impl State {
// See: https://github.com/rust-windowing/winit/issues/208 // See: https://github.com/rust-windowing/winit/issues/208
// This solves an issue where egui window positions would be changed when minimizing on Windows. // This solves an issue where egui window positions would be changed when minimizing on Windows.
let screen_size_in_pixels = screen_size_in_pixels(window); let screen_size_in_pixels = screen_size_in_pixels(window);
let screen_size_in_points = screen_size_in_pixels / self.current_pixels_per_point; let screen_size_in_points =
screen_size_in_pixels / pixels_per_point(&self.egui_ctx, window);
self.egui_input.screen_rect = (screen_size_in_points.x > 0.0 self.egui_input.screen_rect = (screen_size_in_points.x > 0.0
&& screen_size_in_points.y > 0.0) && screen_size_in_points.y > 0.0)
@ -231,18 +226,12 @@ impl State {
self.egui_input.take() 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. /// 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`]. /// The result can be found in [`Self::egui_input`] and be extracted with [`Self::take_egui_input`].
pub fn on_window_event( pub fn on_window_event(
&mut self, &mut self,
egui_ctx: &egui::Context, window: &Window,
event: &winit::event::WindowEvent<'_>, event: &winit::event::WindowEvent<'_>,
) -> EventResponse { ) -> EventResponse {
crate::profile_function!(short_window_event_description(event)); crate::profile_function!(short_window_event_description(event));
@ -257,7 +246,7 @@ impl State {
.entry(self.viewport_id) .entry(self.viewport_id)
.or_default() .or_default()
.native_pixels_per_point = Some(native_pixels_per_point); .native_pixels_per_point = Some(native_pixels_per_point);
self.current_pixels_per_point = egui_ctx.zoom_factor() * native_pixels_per_point;
EventResponse { EventResponse {
repaint: true, repaint: true,
consumed: false, consumed: false,
@ -267,21 +256,21 @@ impl State {
self.on_mouse_button_input(*state, *button); self.on_mouse_button_input(*state, *button);
EventResponse { EventResponse {
repaint: true, repaint: true,
consumed: egui_ctx.wants_pointer_input(), consumed: self.egui_ctx.wants_pointer_input(),
} }
} }
WindowEvent::MouseWheel { delta, .. } => { WindowEvent::MouseWheel { delta, .. } => {
self.on_mouse_wheel(*delta); self.on_mouse_wheel(window, *delta);
EventResponse { EventResponse {
repaint: true, repaint: true,
consumed: egui_ctx.wants_pointer_input(), consumed: self.egui_ctx.wants_pointer_input(),
} }
} }
WindowEvent::CursorMoved { position, .. } => { WindowEvent::CursorMoved { position, .. } => {
self.on_cursor_moved(*position); self.on_cursor_moved(window, *position);
EventResponse { EventResponse {
repaint: true, repaint: true,
consumed: egui_ctx.is_using_pointer(), consumed: self.egui_ctx.is_using_pointer(),
} }
} }
WindowEvent::CursorLeft { .. } => { WindowEvent::CursorLeft { .. } => {
@ -294,12 +283,12 @@ impl State {
} }
// WindowEvent::TouchpadPressure {device_id, pressure, stage, .. } => {} // TODO // WindowEvent::TouchpadPressure {device_id, pressure, stage, .. } => {} // TODO
WindowEvent::Touch(touch) => { WindowEvent::Touch(touch) => {
self.on_touch(touch); self.on_touch(window, touch);
let consumed = match touch.phase { let consumed = match touch.phase {
winit::event::TouchPhase::Started winit::event::TouchPhase::Started
| winit::event::TouchPhase::Ended | winit::event::TouchPhase::Ended
| winit::event::TouchPhase::Cancelled => egui_ctx.wants_pointer_input(), | winit::event::TouchPhase::Cancelled => self.egui_ctx.wants_pointer_input(),
winit::event::TouchPhase::Moved => egui_ctx.is_using_pointer(), winit::event::TouchPhase::Moved => self.egui_ctx.is_using_pointer(),
}; };
EventResponse { EventResponse {
repaint: true, repaint: true,
@ -316,7 +305,7 @@ impl State {
self.egui_input self.egui_input
.events .events
.push(egui::Event::Text(ch.to_string())); .push(egui::Event::Text(ch.to_string()));
egui_ctx.wants_keyboard_input() self.egui_ctx.wants_keyboard_input()
} else { } else {
false false
}; };
@ -361,13 +350,13 @@ impl State {
EventResponse { EventResponse {
repaint: true, repaint: true,
consumed: egui_ctx.wants_keyboard_input(), consumed: self.egui_ctx.wants_keyboard_input(),
} }
} }
WindowEvent::KeyboardInput { input, .. } => { WindowEvent::KeyboardInput { input, .. } => {
self.on_keyboard_input(input); self.on_keyboard_input(input);
// When pressing the Tab key, egui focuses the first focusable element, hence Tab always consumes. // When pressing the Tab key, egui focuses the first focusable element, hence Tab always consumes.
let consumed = egui_ctx.wants_keyboard_input() let consumed = self.egui_ctx.wants_keyboard_input()
|| input.virtual_keycode == Some(winit::event::VirtualKeyCode::Tab); || input.virtual_keycode == Some(winit::event::VirtualKeyCode::Tab);
EventResponse { EventResponse {
repaint: true, repaint: true,
@ -459,7 +448,7 @@ impl State {
self.egui_input.events.push(egui::Event::Zoom(zoom_factor)); self.egui_input.events.push(egui::Event::Zoom(zoom_factor));
EventResponse { EventResponse {
repaint: true, repaint: true,
consumed: egui_ctx.wants_pointer_input(), consumed: self.egui_ctx.wants_pointer_input(),
} }
} }
} }
@ -520,10 +509,16 @@ impl State {
} }
} }
fn on_cursor_moved(&mut self, pos_in_pixels: winit::dpi::PhysicalPosition<f64>) { fn on_cursor_moved(
&mut self,
window: &Window,
pos_in_pixels: winit::dpi::PhysicalPosition<f64>,
) {
let pixels_per_point = pixels_per_point(&self.egui_ctx, window);
let pos_in_points = egui::pos2( let pos_in_points = egui::pos2(
pos_in_pixels.x as f32 / self.current_pixels_per_point, pos_in_pixels.x as f32 / pixels_per_point,
pos_in_pixels.y as f32 / self.current_pixels_per_point, pos_in_pixels.y as f32 / pixels_per_point,
); );
self.pointer_pos_in_points = Some(pos_in_points); self.pointer_pos_in_points = Some(pos_in_points);
@ -548,7 +543,9 @@ impl State {
} }
} }
fn on_touch(&mut self, touch: &winit::event::Touch) { 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 // Emit touch event
self.egui_input.events.push(egui::Event::Touch { self.egui_input.events.push(egui::Event::Touch {
device_id: egui::TouchDeviceId(egui::epaint::util::hash(touch.device_id)), device_id: egui::TouchDeviceId(egui::epaint::util::hash(touch.device_id)),
@ -560,8 +557,8 @@ impl State {
winit::event::TouchPhase::Cancelled => egui::TouchPhase::Cancel, winit::event::TouchPhase::Cancelled => egui::TouchPhase::Cancel,
}, },
pos: egui::pos2( pos: egui::pos2(
touch.location.x as f32 / self.current_pixels_per_point, touch.location.x as f32 / pixels_per_point,
touch.location.y as f32 / self.current_pixels_per_point, touch.location.y as f32 / pixels_per_point,
), ),
force: match touch.force { force: match touch.force {
Some(winit::event::Force::Normalized(force)) => Some(force as f32), Some(winit::event::Force::Normalized(force)) => Some(force as f32),
@ -581,14 +578,14 @@ impl State {
winit::event::TouchPhase::Started => { winit::event::TouchPhase::Started => {
self.pointer_touch_id = Some(touch.id); self.pointer_touch_id = Some(touch.id);
// First move the pointer to the right location // First move the pointer to the right location
self.on_cursor_moved(touch.location); self.on_cursor_moved(window, touch.location);
self.on_mouse_button_input( self.on_mouse_button_input(
winit::event::ElementState::Pressed, winit::event::ElementState::Pressed,
winit::event::MouseButton::Left, winit::event::MouseButton::Left,
); );
} }
winit::event::TouchPhase::Moved => { winit::event::TouchPhase::Moved => {
self.on_cursor_moved(touch.location); self.on_cursor_moved(window, touch.location);
} }
winit::event::TouchPhase::Ended => { winit::event::TouchPhase::Ended => {
self.pointer_touch_id = None; self.pointer_touch_id = None;
@ -610,7 +607,9 @@ impl State {
} }
} }
fn on_mouse_wheel(&mut self, delta: winit::event::MouseScrollDelta) { fn on_mouse_wheel(&mut self, window: &Window, delta: winit::event::MouseScrollDelta) {
let pixels_per_point = pixels_per_point(&self.egui_ctx, window);
{ {
let (unit, delta) = match delta { let (unit, delta) = match delta {
winit::event::MouseScrollDelta::LineDelta(x, y) => { winit::event::MouseScrollDelta::LineDelta(x, y) => {
@ -621,7 +620,7 @@ impl State {
y, y,
}) => ( }) => (
egui::MouseWheelUnit::Point, egui::MouseWheelUnit::Point,
egui::vec2(x as f32, y as f32) / self.current_pixels_per_point, egui::vec2(x as f32, y as f32) / pixels_per_point,
), ),
}; };
let modifiers = self.egui_input.modifiers; let modifiers = self.egui_input.modifiers;
@ -637,7 +636,7 @@ impl State {
egui::vec2(x, y) * points_per_scroll_line egui::vec2(x, y) * points_per_scroll_line
} }
winit::event::MouseScrollDelta::PixelDelta(delta) => { winit::event::MouseScrollDelta::PixelDelta(delta) => {
egui::vec2(delta.x as f32, delta.y as f32) / self.current_pixels_per_point egui::vec2(delta.x as f32, delta.y as f32) / pixels_per_point
} }
}; };
@ -699,7 +698,6 @@ impl State {
pub fn handle_platform_output( pub fn handle_platform_output(
&mut self, &mut self,
window: &Window, window: &Window,
egui_ctx: &egui::Context,
platform_output: egui::PlatformOutput, platform_output: egui::PlatformOutput,
) { ) {
crate::profile_function!(); crate::profile_function!();
@ -715,8 +713,6 @@ impl State {
accesskit_update, accesskit_update,
} = platform_output; } = platform_output;
self.current_pixels_per_point = egui_ctx.pixels_per_point(); // someone can have changed it to scale the UI
self.set_cursor_icon(window, cursor_icon); self.set_cursor_icon(window, cursor_icon);
if let Some(open_url) = open_url { if let Some(open_url) = open_url {
@ -772,17 +768,15 @@ impl State {
/// Update the given viewport info with the current state of the window. /// Update the given viewport info with the current state of the window.
/// ///
/// Call before [`State::take_egui_input`]. /// Call before [`State::take_egui_input`].
pub fn update_viewport_info(info: &mut ViewportInfo, egui_ctx: &egui::Context, window: &Window) { pub fn update_viewport_info(
update_viewport_info_impl(info, window, pixels_per_point(egui_ctx, window));
}
fn update_viewport_info_impl(
viewport_info: &mut ViewportInfo, viewport_info: &mut ViewportInfo,
egui_ctx: &egui::Context,
window: &Window, window: &Window,
pixels_per_point: f32,
) { ) {
crate::profile_function!(); crate::profile_function!();
let pixels_per_point = pixels_per_point(egui_ctx, window);
let has_a_position = match window.is_minimized() { let has_a_position = match window.is_minimized() {
None | Some(true) => false, None | Some(true) => false,
Some(false) => true, Some(false) => true,
@ -1433,16 +1427,6 @@ pub fn create_winit_window_builder<T>(
window_builder window_builder
} }
/// 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) {
log::warn!("set_cursor_hittest failed: {err}");
}
}
}
/// Applies what `create_winit_window_builder` couldn't /// Applies what `create_winit_window_builder` couldn't
pub fn apply_viewport_builder_to_window( pub fn apply_viewport_builder_to_window(
egui_ctx: &egui::Context, egui_ctx: &egui::Context,

View File

@ -235,7 +235,7 @@ fn main() {
gl_window.resize(**new_inner_size); gl_window.resize(**new_inner_size);
} }
let event_response = egui_glow.on_window_event(&event); let event_response = egui_glow.on_window_event(gl_window.window(), &event);
if event_response.repaint { if event_response.repaint {
gl_window.window().request_redraw(); gl_window.window().request_redraw();

View File

@ -34,7 +34,10 @@ impl EguiGlow {
}) })
.unwrap(); .unwrap();
let egui_ctx = egui::Context::default();
let egui_winit = egui_winit::State::new( let egui_winit = egui_winit::State::new(
egui_ctx.clone(),
ViewportId::ROOT, ViewportId::ROOT,
event_loop, event_loop,
native_pixels_per_point, native_pixels_per_point,
@ -42,7 +45,7 @@ impl EguiGlow {
); );
Self { Self {
egui_ctx: Default::default(), egui_ctx,
egui_winit, egui_winit,
painter, painter,
viewport_info: Default::default(), viewport_info: Default::default(),
@ -52,8 +55,12 @@ impl EguiGlow {
} }
} }
pub fn on_window_event(&mut self, event: &winit::event::WindowEvent<'_>) -> EventResponse { pub fn on_window_event(
self.egui_winit.on_window_event(&self.egui_ctx, event) &mut self,
window: &winit::window::Window,
event: &winit::event::WindowEvent<'_>,
) -> EventResponse {
self.egui_winit.on_window_event(window, event)
} }
/// Call [`Self::paint`] later to paint. /// Call [`Self::paint`] later to paint.
@ -87,7 +94,7 @@ impl EguiGlow {
} }
self.egui_winit self.egui_winit
.handle_platform_output(window, &self.egui_ctx, platform_output); .handle_platform_output(window, platform_output);
self.shapes = shapes; self.shapes = shapes;
self.pixels_per_point = pixels_per_point; self.pixels_per_point = pixels_per_point;