Decouple `cursor_position` from `Cache`

Instead, we ask explicitly for it in the different `update` and `draw` methods.
This way, the runtime can derive the logical position of the cursor from
the source of truth.
This commit is contained in:
Héctor Ramón Jiménez 2020-06-23 06:44:34 +02:00
parent bbdf558bd7
commit f30a666dc8
6 changed files with 90 additions and 36 deletions

View File

@ -5,9 +5,10 @@ use controls::Controls;
use scene::Scene; use scene::Scene;
use iced_wgpu::{wgpu, Backend, Renderer, Settings, Viewport}; use iced_wgpu::{wgpu, Backend, Renderer, Settings, Viewport};
use iced_winit::{futures, program, winit, Debug, Size}; use iced_winit::{conversion, futures, program, winit, Debug, Size};
use winit::{ use winit::{
dpi::PhysicalPosition,
event::{Event, ModifiersState, WindowEvent}, event::{Event, ModifiersState, WindowEvent},
event_loop::{ControlFlow, EventLoop}, event_loop::{ControlFlow, EventLoop},
}; };
@ -24,6 +25,7 @@ pub fn main() {
Size::new(physical_size.width, physical_size.height), Size::new(physical_size.width, physical_size.height),
window.scale_factor(), window.scale_factor(),
); );
let mut cursor_position = PhysicalPosition::new(-1.0, -1.0);
let mut modifiers = ModifiersState::default(); let mut modifiers = ModifiersState::default();
// Initialize wgpu // Initialize wgpu
@ -79,6 +81,7 @@ pub fn main() {
let mut state = program::State::new( let mut state = program::State::new(
controls, controls,
viewport.logical_size(), viewport.logical_size(),
conversion::cursor_position(cursor_position, viewport.scale_factor()),
&mut renderer, &mut renderer,
&mut debug, &mut debug,
); );
@ -91,6 +94,9 @@ pub fn main() {
match event { match event {
Event::WindowEvent { event, .. } => { Event::WindowEvent { event, .. } => {
match event { match event {
WindowEvent::CursorMoved { position, .. } => {
cursor_position = position;
}
WindowEvent::ModifiersChanged(new_modifiers) => { WindowEvent::ModifiersChanged(new_modifiers) => {
modifiers = new_modifiers; modifiers = new_modifiers;
} }
@ -105,7 +111,6 @@ pub fn main() {
WindowEvent::CloseRequested => { WindowEvent::CloseRequested => {
*control_flow = ControlFlow::Exit; *control_flow = ControlFlow::Exit;
} }
_ => {} _ => {}
} }
@ -123,8 +128,12 @@ pub fn main() {
if !state.is_queue_empty() { if !state.is_queue_empty() {
// We update iced // We update iced
let _ = state.update( let _ = state.update(
None,
viewport.logical_size(), viewport.logical_size(),
conversion::cursor_position(
cursor_position,
viewport.scale_factor(),
),
None,
&mut renderer, &mut renderer,
&mut debug, &mut debug,
); );

View File

@ -70,6 +70,7 @@ pub fn run<A, E, C>(
}; };
let clipboard = Clipboard::new(&context.window()); let clipboard = Clipboard::new(&context.window());
let mut cursor_position = glutin::dpi::PhysicalPosition::new(-1.0, -1.0);
let mut mouse_interaction = mouse::Interaction::default(); let mut mouse_interaction = mouse::Interaction::default();
let mut modifiers = glutin::event::ModifiersState::default(); let mut modifiers = glutin::event::ModifiersState::default();
@ -90,6 +91,7 @@ pub fn run<A, E, C>(
let mut state = program::State::new( let mut state = program::State::new(
application, application,
viewport.logical_size(), viewport.logical_size(),
conversion::cursor_position(cursor_position, viewport.scale_factor()),
&mut renderer, &mut renderer,
&mut debug, &mut debug,
); );
@ -103,8 +105,12 @@ pub fn run<A, E, C>(
let command = runtime.enter(|| { let command = runtime.enter(|| {
state.update( state.update(
clipboard.as_ref().map(|c| c as _),
viewport.logical_size(), viewport.logical_size(),
conversion::cursor_position(
cursor_position,
viewport.scale_factor(),
),
clipboard.as_ref().map(|c| c as _),
&mut renderer, &mut renderer,
&mut debug, &mut debug,
) )
@ -159,11 +165,14 @@ pub fn run<A, E, C>(
// The queue is empty, therefore this will never produce // The queue is empty, therefore this will never produce
// a `Command`. // a `Command`.
// //
// TODO: Properly queue `WindowResized` and `CursorMoved` // TODO: Properly queue `WindowResized`
// events.
let _ = state.update( let _ = state.update(
clipboard.as_ref().map(|c| c as _),
viewport.logical_size(), viewport.logical_size(),
conversion::cursor_position(
cursor_position,
viewport.scale_factor(),
),
clipboard.as_ref().map(|c| c as _),
&mut renderer, &mut renderer,
&mut debug, &mut debug,
); );
@ -225,6 +234,7 @@ pub fn run<A, E, C>(
context.window(), context.window(),
scale_factor, scale_factor,
control_flow, control_flow,
&mut cursor_position,
&mut modifiers, &mut modifiers,
&mut viewport, &mut viewport,
&mut resized, &mut resized,

View File

@ -1,5 +1,5 @@
use crate::{ use crate::{
Cache, Clipboard, Command, Debug, Event, Program, Renderer, Size, Cache, Clipboard, Command, Debug, Event, Point, Program, Renderer, Size,
UserInterface, UserInterface,
}; };
@ -31,6 +31,7 @@ where
pub fn new( pub fn new(
mut program: P, mut program: P,
bounds: Size, bounds: Size,
cursor_position: Point,
renderer: &mut P::Renderer, renderer: &mut P::Renderer,
debug: &mut Debug, debug: &mut Debug,
) -> Self { ) -> Self {
@ -43,7 +44,7 @@ where
); );
debug.draw_started(); debug.draw_started();
let primitive = user_interface.draw(renderer); let primitive = user_interface.draw(renderer, cursor_position);
debug.draw_finished(); debug.draw_finished();
let cache = Some(user_interface.into_cache()); let cache = Some(user_interface.into_cache());
@ -104,8 +105,9 @@ where
/// [`Program`]: trait.Program.html /// [`Program`]: trait.Program.html
pub fn update( pub fn update(
&mut self, &mut self,
clipboard: Option<&dyn Clipboard>,
bounds: Size, bounds: Size,
cursor_position: Point,
clipboard: Option<&dyn Clipboard>,
renderer: &mut P::Renderer, renderer: &mut P::Renderer,
debug: &mut Debug, debug: &mut Debug,
) -> Option<Command<P::Message>> { ) -> Option<Command<P::Message>> {
@ -120,6 +122,7 @@ where
debug.event_processing_started(); debug.event_processing_started();
let mut messages = user_interface.update( let mut messages = user_interface.update(
self.queued_events.drain(..), self.queued_events.drain(..),
cursor_position,
clipboard, clipboard,
renderer, renderer,
); );
@ -128,7 +131,7 @@ where
if messages.is_empty() { if messages.is_empty() {
debug.draw_started(); debug.draw_started();
self.primitive = user_interface.draw(renderer); self.primitive = user_interface.draw(renderer, cursor_position);
debug.draw_finished(); debug.draw_finished();
self.cache = Some(user_interface.into_cache()); self.cache = Some(user_interface.into_cache());
@ -159,7 +162,7 @@ where
); );
debug.draw_started(); debug.draw_started();
self.primitive = user_interface.draw(renderer); self.primitive = user_interface.draw(renderer, cursor_position);
debug.draw_finished(); debug.draw_finished();
self.cache = Some(user_interface.into_cache()); self.cache = Some(user_interface.into_cache());

View File

@ -1,4 +1,4 @@
use crate::{layout, mouse, Clipboard, Element, Event, Layout, Point, Size}; use crate::{layout, Clipboard, Element, Event, Layout, Point, Size};
use std::hash::Hasher; use std::hash::Hasher;
@ -23,7 +23,6 @@ pub struct UserInterface<'a, Message, Renderer> {
root: Element<'a, Message, Renderer>, root: Element<'a, Message, Renderer>,
layout: layout::Node, layout: layout::Node,
bounds: Size, bounds: Size,
cursor_position: Point,
} }
impl<'a, Message, Renderer> UserInterface<'a, Message, Renderer> impl<'a, Message, Renderer> UserInterface<'a, Message, Renderer>
@ -115,7 +114,6 @@ where
root, root,
layout, layout,
bounds, bounds,
cursor_position: cache.cursor_position,
} }
} }
@ -132,7 +130,7 @@ where
/// completing [the previous example](#example): /// completing [the previous example](#example):
/// ///
/// ```no_run /// ```no_run
/// use iced_native::{UserInterface, Cache, Size}; /// use iced_native::{UserInterface, Cache, Size, Point};
/// use iced_wgpu::Renderer; /// use iced_wgpu::Renderer;
/// ///
/// # mod iced_wgpu { /// # mod iced_wgpu {
@ -154,6 +152,7 @@ where
/// let mut cache = Cache::new(); /// let mut cache = Cache::new();
/// let mut renderer = Renderer::new(); /// let mut renderer = Renderer::new();
/// let mut window_size = Size::new(1024.0, 768.0); /// let mut window_size = Size::new(1024.0, 768.0);
/// let mut cursor_position = Point::default();
/// ///
/// // Initialize our event storage /// // Initialize our event storage
/// let mut events = Vec::new(); /// let mut events = Vec::new();
@ -169,7 +168,12 @@ where
/// ); /// );
/// ///
/// // Update the user interface /// // Update the user interface
/// let messages = user_interface.update(events.drain(..), None, &renderer); /// let messages = user_interface.update(
/// events.drain(..),
/// cursor_position,
/// None,
/// &renderer,
/// );
/// ///
/// cache = user_interface.into_cache(); /// cache = user_interface.into_cache();
/// ///
@ -182,20 +186,17 @@ where
pub fn update( pub fn update(
&mut self, &mut self,
events: impl IntoIterator<Item = Event>, events: impl IntoIterator<Item = Event>,
cursor_position: Point,
clipboard: Option<&dyn Clipboard>, clipboard: Option<&dyn Clipboard>,
renderer: &Renderer, renderer: &Renderer,
) -> Vec<Message> { ) -> Vec<Message> {
let mut messages = Vec::new(); let mut messages = Vec::new();
for event in events { for event in events {
if let Event::Mouse(mouse::Event::CursorMoved { x, y }) = event {
self.cursor_position = Point::new(x, y);
}
self.root.widget.on_event( self.root.widget.on_event(
event, event,
Layout::new(&self.layout), Layout::new(&self.layout),
self.cursor_position, cursor_position,
&mut messages, &mut messages,
renderer, renderer,
clipboard, clipboard,
@ -219,7 +220,7 @@ where
/// [completing the last example](#example-1): /// [completing the last example](#example-1):
/// ///
/// ```no_run /// ```no_run
/// use iced_native::{UserInterface, Cache, Size}; /// use iced_native::{UserInterface, Cache, Size, Point};
/// use iced_wgpu::Renderer; /// use iced_wgpu::Renderer;
/// ///
/// # mod iced_wgpu { /// # mod iced_wgpu {
@ -241,6 +242,7 @@ where
/// let mut cache = Cache::new(); /// let mut cache = Cache::new();
/// let mut renderer = Renderer::new(); /// let mut renderer = Renderer::new();
/// let mut window_size = Size::new(1024.0, 768.0); /// let mut window_size = Size::new(1024.0, 768.0);
/// let mut cursor_position = Point::default();
/// let mut events = Vec::new(); /// let mut events = Vec::new();
/// ///
/// loop { /// loop {
@ -253,10 +255,15 @@ where
/// &mut renderer, /// &mut renderer,
/// ); /// );
/// ///
/// let messages = user_interface.update(events.drain(..), None, &renderer); /// let messages = user_interface.update(
/// events.drain(..),
/// cursor_position,
/// None,
/// &renderer,
/// );
/// ///
/// // Draw the user interface /// // Draw the user interface
/// let mouse_cursor = user_interface.draw(&mut renderer); /// let mouse_cursor = user_interface.draw(&mut renderer, cursor_position);
/// ///
/// cache = user_interface.into_cache(); /// cache = user_interface.into_cache();
/// ///
@ -268,12 +275,16 @@ where
/// // Flush rendering operations... /// // Flush rendering operations...
/// } /// }
/// ``` /// ```
pub fn draw(&self, renderer: &mut Renderer) -> Renderer::Output { pub fn draw(
&self,
renderer: &mut Renderer,
cursor_position: Point,
) -> Renderer::Output {
self.root.widget.draw( self.root.widget.draw(
renderer, renderer,
&Renderer::Defaults::default(), &Renderer::Defaults::default(),
Layout::new(&self.layout), Layout::new(&self.layout),
self.cursor_position, cursor_position,
) )
} }
@ -287,7 +298,6 @@ where
hash: self.hash, hash: self.hash,
layout: self.layout, layout: self.layout,
bounds: self.bounds, bounds: self.bounds,
cursor_position: self.cursor_position,
} }
} }
} }
@ -300,7 +310,6 @@ pub struct Cache {
hash: u64, hash: u64,
layout: layout::Node, layout: layout::Node,
bounds: Size, bounds: Size,
cursor_position: Point,
} }
impl Cache { impl Cache {
@ -316,7 +325,6 @@ impl Cache {
hash: 0, hash: 0,
layout: layout::Node::new(Size::new(0.0, 0.0)), layout: layout::Node::new(Size::new(0.0, 0.0)),
bounds: Size::ZERO, bounds: Size::ZERO,
cursor_position: Point::new(-1.0, -1.0),
} }
} }
} }
@ -329,7 +337,7 @@ impl Default for Cache {
impl PartialEq for Cache { impl PartialEq for Cache {
fn eq(&self, other: &Cache) -> bool { fn eq(&self, other: &Cache) -> bool {
self.hash == other.hash && self.cursor_position == other.cursor_position self.hash == other.hash
} }
} }

View File

@ -148,6 +148,7 @@ pub fn run<A, E, C>(
.expect("Open window"); .expect("Open window");
let clipboard = Clipboard::new(&window); let clipboard = Clipboard::new(&window);
let mut cursor_position = winit::dpi::PhysicalPosition::new(-1.0, -1.0);
let mut mouse_interaction = mouse::Interaction::default(); let mut mouse_interaction = mouse::Interaction::default();
let mut modifiers = winit::event::ModifiersState::default(); let mut modifiers = winit::event::ModifiersState::default();
@ -171,6 +172,7 @@ pub fn run<A, E, C>(
let mut state = program::State::new( let mut state = program::State::new(
application, application,
viewport.logical_size(), viewport.logical_size(),
conversion::cursor_position(cursor_position, viewport.scale_factor()),
&mut renderer, &mut renderer,
&mut debug, &mut debug,
); );
@ -184,8 +186,12 @@ pub fn run<A, E, C>(
let command = runtime.enter(|| { let command = runtime.enter(|| {
state.update( state.update(
clipboard.as_ref().map(|c| c as _),
viewport.logical_size(), viewport.logical_size(),
conversion::cursor_position(
cursor_position,
viewport.scale_factor(),
),
clipboard.as_ref().map(|c| c as _),
&mut renderer, &mut renderer,
&mut debug, &mut debug,
) )
@ -240,11 +246,14 @@ pub fn run<A, E, C>(
// The queue is empty, therefore this will never produce // The queue is empty, therefore this will never produce
// a `Command`. // a `Command`.
// //
// TODO: Properly queue `WindowResized` and `CursorMoved` // TODO: Properly queue `WindowResized`
// events.
let _ = state.update( let _ = state.update(
clipboard.as_ref().map(|c| c as _),
viewport.logical_size(), viewport.logical_size(),
conversion::cursor_position(
cursor_position,
viewport.scale_factor(),
),
clipboard.as_ref().map(|c| c as _),
&mut renderer, &mut renderer,
&mut debug, &mut debug,
); );
@ -304,6 +313,7 @@ pub fn run<A, E, C>(
&window, &window,
scale_factor, scale_factor,
control_flow, control_flow,
&mut cursor_position,
&mut modifiers, &mut modifiers,
&mut viewport, &mut viewport,
&mut resized, &mut resized,
@ -332,6 +342,7 @@ pub fn handle_window_event(
window: &winit::window::Window, window: &winit::window::Window,
scale_factor: f64, scale_factor: f64,
control_flow: &mut winit::event_loop::ControlFlow, control_flow: &mut winit::event_loop::ControlFlow,
cursor_position: &mut winit::dpi::PhysicalPosition<f64>,
modifiers: &mut winit::event::ModifiersState, modifiers: &mut winit::event::ModifiersState,
viewport: &mut Viewport, viewport: &mut Viewport,
resized: &mut bool, resized: &mut bool,
@ -352,6 +363,9 @@ pub fn handle_window_event(
WindowEvent::CloseRequested => { WindowEvent::CloseRequested => {
*control_flow = ControlFlow::Exit; *control_flow = ControlFlow::Exit;
} }
WindowEvent::CursorMoved { position, .. } => {
*cursor_position = *position;
}
WindowEvent::ModifiersChanged(new_modifiers) => { WindowEvent::ModifiersChanged(new_modifiers) => {
*modifiers = *new_modifiers; *modifiers = *new_modifiers;
} }

View File

@ -4,7 +4,7 @@
//! [`iced_native`]: https://github.com/hecrj/iced/tree/master/native //! [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
use crate::{ use crate::{
keyboard::{self, KeyCode, ModifiersState}, keyboard::{self, KeyCode, ModifiersState},
mouse, window, Event, Mode, mouse, window, Event, Mode, Point,
}; };
/// Converts a winit window event into an iced event. /// Converts a winit window event into an iced event.
@ -174,6 +174,16 @@ pub fn modifiers_state(
} }
} }
/// Converts a physical cursor position to a logical `Point`.
pub fn cursor_position(
position: winit::dpi::PhysicalPosition<f64>,
scale_factor: f64,
) -> Point {
let logical_position = position.to_logical(scale_factor);
Point::new(logical_position.x, logical_position.y)
}
/// Converts a `VirtualKeyCode` from [`winit`] to an [`iced_native`] key code. /// Converts a `VirtualKeyCode` from [`winit`] to an [`iced_native`] key code.
/// ///
/// [`winit`]: https://github.com/rust-windowing/winit /// [`winit`]: https://github.com/rust-windowing/winit