Introduce mouse_interaction method to Widget trait

This commit is contained in:
Héctor Ramón Jiménez 2021-10-18 16:43:18 +07:00
parent 7a876c8b29
commit be97a5d502
No known key found for this signature in database
GPG key ID: 140CC052C94F138E
10 changed files with 152 additions and 21 deletions

View file

@ -68,7 +68,6 @@ 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,
); );

View file

@ -93,7 +93,6 @@ 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,
); );

View file

@ -1,4 +1,5 @@
//! Create interactive, native cross-platform applications. //! Create interactive, native cross-platform applications.
use crate::mouse;
use crate::{Error, Executor, Runtime}; use crate::{Error, Executor, Runtime};
pub use iced_winit::Application; pub use iced_winit::Application;
@ -179,9 +180,7 @@ async fn run_instance<A, E, C>(
&mut debug, &mut debug,
)); ));
// TODO let mut mouse_interaction = mouse::Interaction::default();
// let mut mouse_interaction = mouse::Interaction::default();
let mut events = Vec::new(); let mut events = Vec::new();
let mut messages = Vec::new(); let mut messages = Vec::new();
@ -245,9 +244,18 @@ async fn run_instance<A, E, C>(
} }
debug.draw_started(); debug.draw_started();
user_interface.draw(&mut renderer, state.cursor_position()); let new_mouse_interaction =
user_interface.draw(&mut renderer, state.cursor_position());
debug.draw_finished(); debug.draw_finished();
if new_mouse_interaction != mouse_interaction {
context.window().set_cursor_icon(
conversion::mouse_interaction(new_mouse_interaction),
);
mouse_interaction = new_mouse_interaction;
}
context.window().request_redraw(); context.window().request_redraw();
} }
event::Event::PlatformSpecific(event::PlatformSpecific::MacOS( event::Event::PlatformSpecific(event::PlatformSpecific::MacOS(
@ -289,9 +297,20 @@ async fn run_instance<A, E, C>(
debug.layout_finished(); debug.layout_finished();
debug.draw_started(); debug.draw_started();
user_interface.draw(&mut renderer, state.cursor_position()); let new_mouse_interaction = user_interface
.draw(&mut renderer, state.cursor_position());
debug.draw_finished(); debug.draw_finished();
if new_mouse_interaction != mouse_interaction {
context.window().set_cursor_icon(
conversion::mouse_interaction(
new_mouse_interaction,
),
);
mouse_interaction = new_mouse_interaction;
}
context.resize(glutin::dpi::PhysicalSize::new( context.resize(glutin::dpi::PhysicalSize::new(
physical_size.width, physical_size.width,
physical_size.height, physical_size.height,

View file

@ -1,5 +1,6 @@
use crate::event::{self, Event}; use crate::event::{self, Event};
use crate::layout; use crate::layout;
use crate::mouse;
use crate::overlay; use crate::overlay;
use crate::renderer; use crate::renderer;
use crate::{ use crate::{
@ -251,6 +252,16 @@ where
.draw(renderer, style, layout, cursor_position, viewport) .draw(renderer, style, layout, cursor_position, viewport)
} }
pub fn mouse_interaction(
&self,
layout: Layout<'_>,
viewport: &Rectangle,
cursor_position: Point,
) -> mouse::Interaction {
self.widget
.mouse_interaction(layout, viewport, cursor_position)
}
/// Computes the _layout_ hash of the [`Element`]. /// Computes the _layout_ hash of the [`Element`].
pub fn hash_layout(&self, state: &mut Hasher) { pub fn hash_layout(&self, state: &mut Hasher) {
self.widget.hash_layout(state); self.widget.hash_layout(state);
@ -346,6 +357,16 @@ where
.draw(renderer, style, layout, cursor_position, viewport) .draw(renderer, style, layout, cursor_position, viewport)
} }
fn mouse_interaction(
&self,
layout: Layout<'_>,
viewport: &Rectangle,
cursor_position: Point,
) -> mouse::Interaction {
self.widget
.mouse_interaction(layout, viewport, cursor_position)
}
fn hash_layout(&self, state: &mut Hasher) { fn hash_layout(&self, state: &mut Hasher) {
self.widget.hash_layout(state); self.widget.hash_layout(state);
} }
@ -426,6 +447,17 @@ where
) { ) {
} }
fn mouse_interaction(
&self,
layout: Layout<'_>,
viewport: &Rectangle,
cursor_position: Point,
) -> mouse::Interaction {
self.element
.widget
.mouse_interaction(layout, viewport, cursor_position)
}
fn hash_layout(&self, state: &mut Hasher) { fn hash_layout(&self, state: &mut Hasher) {
self.element.widget.hash_layout(state); self.element.widget.hash_layout(state);
} }

View file

@ -8,8 +8,9 @@ pub use menu::Menu;
use crate::event::{self, Event}; use crate::event::{self, Event};
use crate::layout; use crate::layout;
use crate::mouse;
use crate::renderer; use crate::renderer;
use crate::{Clipboard, Hasher, Layout, Point, Size}; use crate::{Clipboard, Hasher, Layout, Point, Rectangle, Size};
/// An interactive component that can be displayed on top of other widgets. /// An interactive component that can be displayed on top of other widgets.
pub trait Overlay<Message, Renderer> pub trait Overlay<Message, Renderer>
@ -74,4 +75,16 @@ where
) -> event::Status { ) -> event::Status {
event::Status::Ignored event::Status::Ignored
} }
/// Returns the current [`mouse::Interaction`] of the [`Widget`].
///
/// By default, it returns [`mouse::Interaction::Idle`].
fn mouse_interaction(
&self,
_layout: Layout<'_>,
_viewport: &Rectangle,
_cursor_position: Point,
) -> mouse::Interaction {
mouse::Interaction::Idle
}
} }

View file

@ -2,8 +2,9 @@ pub use crate::Overlay;
use crate::event::{self, Event}; use crate::event::{self, Event};
use crate::layout; use crate::layout;
use crate::mouse;
use crate::renderer; use crate::renderer;
use crate::{Clipboard, Hasher, Layout, Point, Size, Vector}; use crate::{Clipboard, Hasher, Layout, Point, Rectangle, Size, Vector};
/// A generic [`Overlay`]. /// A generic [`Overlay`].
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
@ -68,6 +69,16 @@ where
) )
} }
pub fn mouse_interaction(
&self,
layout: Layout<'_>,
viewport: &Rectangle,
cursor_position: Point,
) -> mouse::Interaction {
self.overlay
.mouse_interaction(layout, viewport, cursor_position)
}
/// Draws the [`Element`] and its children using the given [`Layout`]. /// Draws the [`Element`] and its children using the given [`Layout`].
pub fn draw( pub fn draw(
&self, &self,

View file

@ -1,3 +1,4 @@
use crate::mouse;
use crate::{ use crate::{
Cache, Clipboard, Command, Debug, Event, Point, Program, Size, Cache, Clipboard, Command, Debug, Event, Point, Program, Size,
UserInterface, UserInterface,
@ -14,6 +15,7 @@ where
cache: Option<Cache>, cache: Option<Cache>,
queued_events: Vec<Event>, queued_events: Vec<Event>,
queued_messages: Vec<P::Message>, queued_messages: Vec<P::Message>,
mouse_interaction: mouse::Interaction,
} }
impl<P> State<P> impl<P> State<P>
@ -25,11 +27,10 @@ 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 {
let mut user_interface = build_user_interface( let user_interface = build_user_interface(
&mut program, &mut program,
Cache::default(), Cache::default(),
renderer, renderer,
@ -44,6 +45,7 @@ where
cache, cache,
queued_events: Vec::new(), queued_events: Vec::new(),
queued_messages: Vec::new(), queued_messages: Vec::new(),
mouse_interaction: mouse::Interaction::Idle,
} }
} }
@ -71,6 +73,11 @@ where
self.queued_events.is_empty() && self.queued_messages.is_empty() self.queued_events.is_empty() && self.queued_messages.is_empty()
} }
/// Returns the current [`mouse::Interaction`] of the [`State`].
pub fn mouse_interaction(&self) -> mouse::Interaction {
self.mouse_interaction
}
/// Processes all the queued events and messages, rebuilding and redrawing /// Processes all the queued events and messages, rebuilding and redrawing
/// the widgets of the linked [`Program`] if necessary. /// the widgets of the linked [`Program`] if necessary.
/// ///
@ -109,7 +116,8 @@ where
if messages.is_empty() { if messages.is_empty() {
debug.draw_started(); debug.draw_started();
user_interface.draw(renderer, cursor_position); self.mouse_interaction =
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());
@ -140,7 +148,8 @@ where
); );
debug.draw_started(); debug.draw_started();
user_interface.draw(renderer, cursor_position); self.mouse_interaction =
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,5 +1,6 @@
use crate::event::{self, Event}; use crate::event::{self, Event};
use crate::layout; use crate::layout;
use crate::mouse;
use crate::overlay; use crate::overlay;
use crate::renderer; use crate::renderer;
use crate::{Clipboard, Element, Layout, Point, Rectangle, Size, Vector}; use crate::{Clipboard, Element, Layout, Point, Rectangle, Size, Vector};
@ -330,7 +331,11 @@ where
/// // Flush rendering operations... /// // Flush rendering operations...
/// } /// }
/// ``` /// ```
pub fn draw(&mut self, renderer: &mut Renderer, cursor_position: Point) { pub fn draw(
&mut self,
renderer: &mut Renderer,
cursor_position: Point,
) -> mouse::Interaction {
// TODO: Move to shell level (?) // TODO: Move to shell level (?)
renderer.clear(); renderer.clear();
@ -346,6 +351,12 @@ where
renderer, renderer,
); );
let mouse_interaction = overlay.mouse_interaction(
Layout::new(&layer.layout),
&viewport,
cursor_position,
);
let overlay_bounds = layer.layout.bounds(); let overlay_bounds = layer.layout.bounds();
renderer.with_layer( renderer.with_layer(
@ -363,12 +374,12 @@ where
self.overlay = Some(layer); self.overlay = Some(layer);
Some(overlay_bounds) Some((overlay_bounds, mouse_interaction))
} else { } else {
None None
}; };
if let Some(overlay_bounds) = overlay { if let Some((overlay_bounds, overlay_interaction)) = overlay {
let base_cursor = if overlay_bounds.contains(cursor_position) { let base_cursor = if overlay_bounds.contains(cursor_position) {
Point::new(-1.0, -1.0) Point::new(-1.0, -1.0)
} else { } else {
@ -382,6 +393,8 @@ where
base_cursor, base_cursor,
&viewport, &viewport,
); );
overlay_interaction
} else { } else {
self.root.widget.draw( self.root.widget.draw(
renderer, renderer,
@ -390,6 +403,12 @@ where
cursor_position, cursor_position,
&viewport, &viewport,
); );
self.root.widget.mouse_interaction(
Layout::new(&self.base.layout),
&viewport,
cursor_position,
)
} }
} }

View file

@ -80,6 +80,7 @@ pub use tooltip::Tooltip;
use crate::event::{self, Event}; use crate::event::{self, Event};
use crate::layout; use crate::layout;
use crate::mouse;
use crate::overlay; use crate::overlay;
use crate::renderer; use crate::renderer;
use crate::{Clipboard, Hasher, Layout, Length, Point, Rectangle}; use crate::{Clipboard, Hasher, Layout, Length, Point, Rectangle};
@ -175,6 +176,18 @@ where
event::Status::Ignored event::Status::Ignored
} }
/// Returns the current [`mouse::Interaction`] of the [`Widget`].
///
/// By default, it returns [`mouse::Interaction::Idle`].
fn mouse_interaction(
&self,
_layout: Layout<'_>,
_viewport: &Rectangle,
_cursor_position: Point,
) -> mouse::Interaction {
mouse::Interaction::Idle
}
/// Returns the overlay of the [`Widget`], if there is any. /// Returns the overlay of the [`Widget`], if there is any.
fn overlay( fn overlay(
&mut self, &mut self,

View file

@ -5,6 +5,7 @@ pub use state::State;
use crate::clipboard::{self, Clipboard}; use crate::clipboard::{self, Clipboard};
use crate::conversion; use crate::conversion;
use crate::mouse;
use crate::{ use crate::{
Color, Command, Debug, Error, Executor, Mode, Proxy, Runtime, Settings, Color, Command, Debug, Error, Executor, Mode, Proxy, Runtime, Settings,
Size, Subscription, Size, Subscription,
@ -252,9 +253,7 @@ async fn run_instance<A, E, C>(
&mut debug, &mut debug,
)); ));
// TODO let mut mouse_interaction = mouse::Interaction::default();
// let mut mouse_interaction = mouse::Interaction::default();
let mut events = Vec::new(); let mut events = Vec::new();
let mut messages = Vec::new(); let mut messages = Vec::new();
@ -317,9 +316,18 @@ async fn run_instance<A, E, C>(
} }
debug.draw_started(); debug.draw_started();
user_interface.draw(&mut renderer, state.cursor_position()); let new_mouse_interaction =
user_interface.draw(&mut renderer, state.cursor_position());
debug.draw_finished(); debug.draw_finished();
if new_mouse_interaction != mouse_interaction {
window.set_cursor_icon(conversion::mouse_interaction(
new_mouse_interaction,
));
mouse_interaction = new_mouse_interaction;
}
window.request_redraw(); window.request_redraw();
} }
event::Event::PlatformSpecific(event::PlatformSpecific::MacOS( event::Event::PlatformSpecific(event::PlatformSpecific::MacOS(
@ -356,7 +364,16 @@ async fn run_instance<A, E, C>(
debug.layout_finished(); debug.layout_finished();
debug.draw_started(); debug.draw_started();
user_interface.draw(&mut renderer, state.cursor_position()); let new_mouse_interaction = user_interface
.draw(&mut renderer, state.cursor_position());
if new_mouse_interaction != mouse_interaction {
window.set_cursor_icon(conversion::mouse_interaction(
new_mouse_interaction,
));
mouse_interaction = new_mouse_interaction;
}
debug.draw_finished(); debug.draw_finished();
compositor.configure_surface( compositor.configure_surface(