mirror of https://github.com/linebender/xilem
Wire up scale factor (#245)
Generally prefer use of LogicalPosition to PhysicalPosition for layout, events, etc. Use scale factor to convert to logical position. Apply scale factor as final transform before Vello rendering. This PR also makes physical_position available in PointerState. There is a TODO for handling WindowEvent::Rescale, which remains and is not addressed. It should be at some future point.
This commit is contained in:
parent
3c371b7a84
commit
69b995b271
|
@ -8,7 +8,7 @@ use std::time::Duration;
|
|||
|
||||
use parley::FontContext;
|
||||
use tracing::{trace, warn};
|
||||
use winit::dpi::PhysicalPosition;
|
||||
use winit::dpi::LogicalPosition;
|
||||
use winit::window::CursorIcon;
|
||||
|
||||
use crate::action::Action;
|
||||
|
@ -630,9 +630,7 @@ impl LayoutCtx<'_> {
|
|||
self.widget_state.local_paint_rect =
|
||||
self.widget_state.local_paint_rect.union(child.paint_rect());
|
||||
|
||||
let mouse_pos = self
|
||||
.mouse_pos
|
||||
.map(|pos| PhysicalPosition::new(pos.x, pos.y));
|
||||
let mouse_pos = self.mouse_pos.map(|pos| LogicalPosition::new(pos.x, pos.y));
|
||||
// if the widget has moved, it may have moved under the mouse, in which
|
||||
// case we need to handle that.
|
||||
if WidgetPod::update_hot_state(
|
||||
|
|
|
@ -9,7 +9,7 @@ use crate::WidgetId;
|
|||
|
||||
use std::{collections::HashSet, path::PathBuf};
|
||||
|
||||
use winit::dpi::{PhysicalPosition, PhysicalSize};
|
||||
use winit::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize};
|
||||
use winit::event::{Ime, KeyEvent, Modifiers, MouseButton};
|
||||
use winit::keyboard::ModifiersState;
|
||||
|
||||
|
@ -39,7 +39,7 @@ pub enum PointerEvent {
|
|||
PointerMove(PointerState),
|
||||
PointerEnter(PointerState),
|
||||
PointerLeave(PointerState),
|
||||
MouseWheel(PhysicalPosition<f64>, PointerState),
|
||||
MouseWheel(LogicalPosition<f64>, PointerState),
|
||||
HoverFile(PathBuf, PointerState),
|
||||
DropFile(PathBuf, PointerState),
|
||||
HoverFileCancel(PointerState),
|
||||
|
@ -60,7 +60,8 @@ pub enum TextEvent {
|
|||
pub struct PointerState {
|
||||
// TODO
|
||||
// pub device_id: DeviceId,
|
||||
pub position: PhysicalPosition<f64>,
|
||||
pub physical_position: PhysicalPosition<f64>,
|
||||
pub position: LogicalPosition<f64>,
|
||||
pub buttons: HashSet<MouseButton>,
|
||||
pub mods: Modifiers,
|
||||
pub count: u8,
|
||||
|
@ -172,7 +173,7 @@ pub enum InternalLifeCycle {
|
|||
|
||||
/// The parents widget origin in window coordinate space has changed.
|
||||
ParentWindowOrigin {
|
||||
mouse_pos: Option<PhysicalPosition<f64>>,
|
||||
mouse_pos: Option<LogicalPosition<f64>>,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -255,7 +256,8 @@ impl PointerState {
|
|||
let device_id = unsafe { DeviceId::dummy() };
|
||||
|
||||
PointerState {
|
||||
position: PhysicalPosition::new(0.0, 0.0),
|
||||
physical_position: PhysicalPosition::new(0.0, 0.0),
|
||||
position: LogicalPosition::new(0.0, 0.0),
|
||||
buttons: Default::default(),
|
||||
mods: Default::default(),
|
||||
count: 0,
|
||||
|
|
|
@ -5,11 +5,12 @@ use std::num::NonZeroUsize;
|
|||
use std::sync::Arc;
|
||||
|
||||
use tracing::warn;
|
||||
use vello::kurbo::Affine;
|
||||
use vello::util::{RenderContext, RenderSurface};
|
||||
use vello::{peniko::Color, AaSupport, RenderParams, Renderer, RendererOptions, Scene};
|
||||
use wgpu::PresentMode;
|
||||
use winit::application::ApplicationHandler;
|
||||
use winit::dpi::PhysicalPosition;
|
||||
use winit::dpi::LogicalPosition;
|
||||
use winit::event::WindowEvent as WinitWindowEvent;
|
||||
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
||||
use winit::window::{Window, WindowId};
|
||||
|
@ -45,11 +46,12 @@ pub fn run(
|
|||
PresentMode::AutoVsync,
|
||||
))
|
||||
.unwrap();
|
||||
let scale_factor = window.scale_factor();
|
||||
let mut main_state = MainState {
|
||||
window,
|
||||
render_cx,
|
||||
surface,
|
||||
render_root: RenderRoot::new(root_widget, WindowSizePolicy::User),
|
||||
render_root: RenderRoot::new(root_widget, WindowSizePolicy::User, scale_factor),
|
||||
renderer: None,
|
||||
pointer_state: PointerState::empty(),
|
||||
app_driver: Box::new(app_driver),
|
||||
|
@ -78,7 +80,8 @@ impl ApplicationHandler for MainState<'_> {
|
|||
.handle_text_event(TextEvent::ModifierChange(modifiers.state()));
|
||||
}
|
||||
WinitWindowEvent::CursorMoved { position, .. } => {
|
||||
self.pointer_state.position = position;
|
||||
self.pointer_state.physical_position = position;
|
||||
self.pointer_state.position = position.to_logical(self.window.scale_factor());
|
||||
self.render_root
|
||||
.handle_pointer_event(PointerEvent::PointerMove(self.pointer_state.clone()));
|
||||
}
|
||||
|
@ -104,10 +107,13 @@ impl ApplicationHandler for MainState<'_> {
|
|||
},
|
||||
WinitWindowEvent::MouseWheel { delta, .. } => {
|
||||
let delta = match delta {
|
||||
winit::event::MouseScrollDelta::LineDelta(x, y) => (x as f64, y as f64),
|
||||
winit::event::MouseScrollDelta::PixelDelta(delta) => (delta.x, delta.y),
|
||||
winit::event::MouseScrollDelta::LineDelta(x, y) => {
|
||||
LogicalPosition::new(x as f64, y as f64)
|
||||
}
|
||||
winit::event::MouseScrollDelta::PixelDelta(delta) => {
|
||||
delta.to_logical(self.window.scale_factor())
|
||||
}
|
||||
};
|
||||
let delta = PhysicalPosition::new(delta.0, delta.1);
|
||||
self.render_root
|
||||
.handle_pointer_event(PointerEvent::MouseWheel(
|
||||
delta,
|
||||
|
@ -175,7 +181,7 @@ impl ApplicationHandler for MainState<'_> {
|
|||
|
||||
impl MainState<'_> {
|
||||
fn render(&mut self, scene: Scene) {
|
||||
//let scale = self.window.scale_factor();
|
||||
let scale = self.window.scale_factor();
|
||||
let size = self.window.inner_size();
|
||||
let width = size.width;
|
||||
let height = size.height;
|
||||
|
@ -185,12 +191,14 @@ impl MainState<'_> {
|
|||
.resize_surface(&mut self.surface, width, height);
|
||||
}
|
||||
|
||||
#[cfg(FALSE)]
|
||||
let transform = if scale != 1.0 {
|
||||
Some(Affine::scale(scale))
|
||||
} else {
|
||||
let transformed_scene = if scale == 1.0 {
|
||||
None
|
||||
} else {
|
||||
let mut new_scene = Scene::new();
|
||||
new_scene.append(&scene, Some(Affine::scale(scale)));
|
||||
Some(new_scene)
|
||||
};
|
||||
let scene_ref = transformed_scene.as_ref().unwrap_or(&scene);
|
||||
|
||||
let Ok(surface_texture) = self.surface.surface.get_current_texture() else {
|
||||
warn!("failed to acquire next swapchain texture");
|
||||
|
@ -217,7 +225,7 @@ impl MainState<'_> {
|
|||
};
|
||||
self.renderer
|
||||
.get_or_insert_with(|| Renderer::new(device, renderer_options).unwrap())
|
||||
.render_to_surface(device, queue, &scene, &surface_texture, &render_params)
|
||||
.render_to_surface(device, queue, scene_ref, &surface_texture, &render_params)
|
||||
.expect("failed to render to surface");
|
||||
surface_texture.present();
|
||||
device.poll(wgpu::Maintain::Wait);
|
||||
|
|
|
@ -10,7 +10,7 @@ use parley::FontContext;
|
|||
use tracing::{info_span, warn};
|
||||
use vello::peniko::{Color, Fill};
|
||||
use vello::Scene;
|
||||
use winit::dpi::{LogicalSize, PhysicalPosition, PhysicalSize};
|
||||
use winit::dpi::{LogicalPosition, LogicalSize, PhysicalSize};
|
||||
use winit::keyboard::{KeyCode, PhysicalKey};
|
||||
use winit::window::CursorIcon;
|
||||
|
||||
|
@ -33,7 +33,7 @@ pub struct RenderRoot {
|
|||
pub(crate) scale_factor: f64,
|
||||
/// Is `Some` if the most recently displayed frame was an animation frame.
|
||||
pub(crate) last_anim: Option<Instant>,
|
||||
pub(crate) last_mouse_pos: Option<PhysicalPosition<f64>>,
|
||||
pub(crate) last_mouse_pos: Option<LogicalPosition<f64>>,
|
||||
pub(crate) cursor_icon: CursorIcon,
|
||||
pub(crate) state: RenderRootState,
|
||||
}
|
||||
|
@ -80,12 +80,12 @@ pub enum RenderRootSignal {
|
|||
}
|
||||
|
||||
impl RenderRoot {
|
||||
pub fn new(root_widget: impl Widget, size_policy: WindowSizePolicy) -> Self {
|
||||
pub fn new(root_widget: impl Widget, size_policy: WindowSizePolicy, scale_factor: f64) -> Self {
|
||||
let mut root = RenderRoot {
|
||||
root: WidgetPod::new(root_widget).boxed(),
|
||||
size_policy,
|
||||
size: PhysicalSize::new(0, 0),
|
||||
scale_factor: 1.0,
|
||||
scale_factor,
|
||||
last_anim: None,
|
||||
last_mouse_pos: None,
|
||||
cursor_icon: CursorIcon::Default,
|
||||
|
|
|
@ -13,7 +13,7 @@ use wgpu::{
|
|||
BufferDescriptor, BufferUsages, CommandEncoderDescriptor, Extent3d, ImageCopyBuffer,
|
||||
TextureDescriptor, TextureFormat, TextureUsages,
|
||||
};
|
||||
use winit::dpi::{PhysicalPosition, PhysicalSize};
|
||||
use winit::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize};
|
||||
use winit::event::{Ime, MouseButton};
|
||||
|
||||
use super::screenshots::get_image_diff;
|
||||
|
@ -174,7 +174,7 @@ impl TestHarness {
|
|||
let window_size = PhysicalSize::new(window_size.width as _, window_size.height as _);
|
||||
|
||||
let mut harness = TestHarness {
|
||||
render_root: RenderRoot::new(root_widget, WindowSizePolicy::User),
|
||||
render_root: RenderRoot::new(root_widget, WindowSizePolicy::User, 1.0),
|
||||
mouse_state,
|
||||
window_size,
|
||||
background_color,
|
||||
|
@ -332,7 +332,10 @@ impl TestHarness {
|
|||
// FIXME - Account for scaling
|
||||
let pos = pos.into();
|
||||
let pos = PhysicalPosition::new(pos.x, pos.y);
|
||||
self.mouse_state.position = dbg!(pos);
|
||||
self.mouse_state.physical_position = dbg!(pos);
|
||||
// TODO: may want to support testing with non-unity scale factors.
|
||||
let scale_factor = 1.0;
|
||||
self.mouse_state.position = pos.to_logical(scale_factor);
|
||||
|
||||
self.process_pointer_event(PointerEvent::PointerMove(self.mouse_state.clone()));
|
||||
}
|
||||
|
@ -351,7 +354,7 @@ impl TestHarness {
|
|||
|
||||
/// Send a Wheel event to the window
|
||||
pub fn mouse_wheel(&mut self, wheel_delta: Vec2) {
|
||||
let pixel_delta = PhysicalPosition::new(wheel_delta.x, wheel_delta.y);
|
||||
let pixel_delta = LogicalPosition::new(wheel_delta.x, wheel_delta.y);
|
||||
self.process_pointer_event(PointerEvent::MouseWheel(
|
||||
pixel_delta,
|
||||
self.mouse_state.clone(),
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
use smallvec::{smallvec, SmallVec};
|
||||
use tracing::{trace, trace_span, warn, Span};
|
||||
use vello::Scene;
|
||||
use winit::dpi::PhysicalPosition;
|
||||
use winit::dpi::LogicalPosition;
|
||||
use winit::event::MouseButton;
|
||||
use winit::window::CursorIcon;
|
||||
|
||||
|
@ -195,7 +195,7 @@ impl Split {
|
|||
}
|
||||
|
||||
/// Returns true if the provided mouse position is inside the splitter bar area.
|
||||
fn bar_hit_test(&self, size: Size, mouse_pos: PhysicalPosition<f64>) -> bool {
|
||||
fn bar_hit_test(&self, size: Size, mouse_pos: LogicalPosition<f64>) -> bool {
|
||||
let (edge1, edge2) = self.bar_edges(size);
|
||||
match self.split_axis {
|
||||
Axis::Horizontal => mouse_pos.x >= edge1 && mouse_pos.x <= edge2,
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
use tracing::{info_span, trace, warn};
|
||||
use vello::Scene;
|
||||
use winit::dpi::PhysicalPosition;
|
||||
use winit::dpi::LogicalPosition;
|
||||
|
||||
use crate::event::{PointerEvent, TextEvent};
|
||||
use crate::kurbo::{Affine, Insets, Point, Rect, Shape, Size};
|
||||
|
@ -231,7 +231,7 @@ impl<W: Widget> WidgetPod<W> {
|
|||
inner: &mut W,
|
||||
inner_state: &mut WidgetState,
|
||||
global_state: &mut RenderRootState,
|
||||
mouse_pos: Option<PhysicalPosition<f64>>,
|
||||
mouse_pos: Option<LogicalPosition<f64>>,
|
||||
) -> bool {
|
||||
let rect = inner_state.layout_rect() + inner_state.parent_window_origin.to_vec2();
|
||||
let had_hot = inner_state.is_hot;
|
||||
|
@ -607,7 +607,7 @@ impl<W: Widget> WidgetPod<W> {
|
|||
InternalLifeCycle::ParentWindowOrigin { mouse_pos } => {
|
||||
self.state.parent_window_origin = parent_ctx.widget_state.window_origin();
|
||||
self.state.needs_window_origin = false;
|
||||
let mouse_pos = mouse_pos.map(|pos| PhysicalPosition::new(pos.x, pos.y));
|
||||
let mouse_pos = mouse_pos.map(|pos| LogicalPosition::new(pos.x, pos.y));
|
||||
WidgetPod::update_hot_state(
|
||||
&mut self.inner,
|
||||
&mut self.state,
|
||||
|
|
|
@ -12,7 +12,6 @@ use vello::{
|
|||
use wgpu::PresentMode;
|
||||
use winit::{
|
||||
application::ApplicationHandler,
|
||||
dpi::PhysicalPosition,
|
||||
event::{ElementState, Modifiers, MouseButton, MouseScrollDelta, WindowEvent},
|
||||
event_loop::{ActiveEventLoop, ControlFlow, EventLoop},
|
||||
window::{Window, WindowId},
|
||||
|
@ -170,8 +169,9 @@ impl<'a, T: Send + 'static, V: View<T> + 'static> MainState<'a, T, V> {
|
|||
MouseScrollDelta::LineDelta(x, y) => {
|
||||
ScrollDelta::Lines(x.trunc() as isize, y.trunc() as isize)
|
||||
}
|
||||
MouseScrollDelta::PixelDelta(PhysicalPosition { x, y }) => {
|
||||
ScrollDelta::Precise(Vec2::new(x, y) * (1.0 / self.window.scale_factor()))
|
||||
MouseScrollDelta::PixelDelta(position) => {
|
||||
let logical_pos = position.to_logical(self.window.scale_factor());
|
||||
ScrollDelta::Precise(Vec2::new(logical_pos.x, logical_pos.y))
|
||||
}
|
||||
})));
|
||||
self.window.request_redraw();
|
||||
|
|
|
@ -38,7 +38,7 @@ pub struct MouseEvent {
|
|||
/// > Positive values indicate that the content that is being scrolled should move
|
||||
/// > right and down (revealing more content left and up).
|
||||
///
|
||||
/// The choice to follow this has not been reasoned, but is based on expediance
|
||||
/// The choice to follow this has not been reasoned, but is based on expedience.
|
||||
pub enum ScrollDelta {
|
||||
Precise(Vec2),
|
||||
Lines(isize, isize),
|
||||
|
|
Loading…
Reference in New Issue