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(
controls,
viewport.logical_size(),
conversion::cursor_position(cursor_position, viewport.scale_factor()),
&mut renderer,
&mut debug,
);

View file

@ -93,7 +93,6 @@ pub fn main() {
let mut state = program::State::new(
controls,
viewport.logical_size(),
conversion::cursor_position(cursor_position, viewport.scale_factor()),
&mut renderer,
&mut debug,
);

View file

@ -1,4 +1,5 @@
//! Create interactive, native cross-platform applications.
use crate::mouse;
use crate::{Error, Executor, Runtime};
pub use iced_winit::Application;
@ -179,9 +180,7 @@ async fn run_instance<A, E, C>(
&mut debug,
));
// TODO
// let mut mouse_interaction = mouse::Interaction::default();
let mut mouse_interaction = mouse::Interaction::default();
let mut events = Vec::new();
let mut messages = Vec::new();
@ -245,9 +244,18 @@ async fn run_instance<A, E, C>(
}
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();
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();
}
event::Event::PlatformSpecific(event::PlatformSpecific::MacOS(
@ -289,9 +297,20 @@ async fn run_instance<A, E, C>(
debug.layout_finished();
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();
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(
physical_size.width,
physical_size.height,

View file

@ -1,5 +1,6 @@
use crate::event::{self, Event};
use crate::layout;
use crate::mouse;
use crate::overlay;
use crate::renderer;
use crate::{
@ -251,6 +252,16 @@ where
.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`].
pub fn hash_layout(&self, state: &mut Hasher) {
self.widget.hash_layout(state);
@ -346,6 +357,16 @@ where
.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) {
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) {
self.element.widget.hash_layout(state);
}

View file

@ -8,8 +8,9 @@ pub use menu::Menu;
use crate::event::{self, Event};
use crate::layout;
use crate::mouse;
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.
pub trait Overlay<Message, Renderer>
@ -74,4 +75,16 @@ where
) -> event::Status {
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::layout;
use crate::mouse;
use crate::renderer;
use crate::{Clipboard, Hasher, Layout, Point, Size, Vector};
use crate::{Clipboard, Hasher, Layout, Point, Rectangle, Size, Vector};
/// A generic [`Overlay`].
#[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`].
pub fn draw(
&self,

View file

@ -1,3 +1,4 @@
use crate::mouse;
use crate::{
Cache, Clipboard, Command, Debug, Event, Point, Program, Size,
UserInterface,
@ -14,6 +15,7 @@ where
cache: Option<Cache>,
queued_events: Vec<Event>,
queued_messages: Vec<P::Message>,
mouse_interaction: mouse::Interaction,
}
impl<P> State<P>
@ -25,11 +27,10 @@ where
pub fn new(
mut program: P,
bounds: Size,
cursor_position: Point,
renderer: &mut P::Renderer,
debug: &mut Debug,
) -> Self {
let mut user_interface = build_user_interface(
let user_interface = build_user_interface(
&mut program,
Cache::default(),
renderer,
@ -44,6 +45,7 @@ where
cache,
queued_events: 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()
}
/// 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
/// the widgets of the linked [`Program`] if necessary.
///
@ -109,7 +116,8 @@ where
if messages.is_empty() {
debug.draw_started();
user_interface.draw(renderer, cursor_position);
self.mouse_interaction =
user_interface.draw(renderer, cursor_position);
debug.draw_finished();
self.cache = Some(user_interface.into_cache());
@ -140,7 +148,8 @@ where
);
debug.draw_started();
user_interface.draw(renderer, cursor_position);
self.mouse_interaction =
user_interface.draw(renderer, cursor_position);
debug.draw_finished();
self.cache = Some(user_interface.into_cache());

View file

@ -1,5 +1,6 @@
use crate::event::{self, Event};
use crate::layout;
use crate::mouse;
use crate::overlay;
use crate::renderer;
use crate::{Clipboard, Element, Layout, Point, Rectangle, Size, Vector};
@ -330,7 +331,11 @@ where
/// // 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 (?)
renderer.clear();
@ -346,6 +351,12 @@ where
renderer,
);
let mouse_interaction = overlay.mouse_interaction(
Layout::new(&layer.layout),
&viewport,
cursor_position,
);
let overlay_bounds = layer.layout.bounds();
renderer.with_layer(
@ -363,12 +374,12 @@ where
self.overlay = Some(layer);
Some(overlay_bounds)
Some((overlay_bounds, mouse_interaction))
} else {
None
};
if let Some(overlay_bounds) = overlay {
if let Some((overlay_bounds, overlay_interaction)) = overlay {
let base_cursor = if overlay_bounds.contains(cursor_position) {
Point::new(-1.0, -1.0)
} else {
@ -382,6 +393,8 @@ where
base_cursor,
&viewport,
);
overlay_interaction
} else {
self.root.widget.draw(
renderer,
@ -390,6 +403,12 @@ where
cursor_position,
&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::layout;
use crate::mouse;
use crate::overlay;
use crate::renderer;
use crate::{Clipboard, Hasher, Layout, Length, Point, Rectangle};
@ -175,6 +176,18 @@ where
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.
fn overlay(
&mut self,

View file

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