Implement reactive-rendering for canvas
This commit is contained in:
parent
a84b328dcc
commit
920596ed6f
9 changed files with 243 additions and 141 deletions
|
|
@ -57,8 +57,9 @@ impl Example {
|
||||||
|
|
||||||
mod bezier {
|
mod bezier {
|
||||||
use iced::mouse;
|
use iced::mouse;
|
||||||
use iced::widget::canvas::event::{self, Event};
|
use iced::widget::canvas::{
|
||||||
use iced::widget::canvas::{self, Canvas, Frame, Geometry, Path, Stroke};
|
self, Canvas, Event, Frame, Geometry, Path, Stroke,
|
||||||
|
};
|
||||||
use iced::{Element, Fill, Point, Rectangle, Renderer, Theme};
|
use iced::{Element, Fill, Point, Rectangle, Renderer, Theme};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
@ -96,48 +97,47 @@ mod bezier {
|
||||||
event: Event,
|
event: Event,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
cursor: mouse::Cursor,
|
cursor: mouse::Cursor,
|
||||||
) -> (event::Status, Option<Curve>) {
|
) -> Option<canvas::Action<Curve>> {
|
||||||
let Some(cursor_position) = cursor.position_in(bounds) else {
|
let cursor_position = cursor.position_in(bounds)?;
|
||||||
return (event::Status::Ignored, None);
|
|
||||||
};
|
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::Mouse(mouse_event) => {
|
Event::Mouse(mouse::Event::ButtonPressed(
|
||||||
let message = match mouse_event {
|
mouse::Button::Left,
|
||||||
mouse::Event::ButtonPressed(mouse::Button::Left) => {
|
)) => Some(
|
||||||
match *state {
|
match *state {
|
||||||
None => {
|
None => {
|
||||||
*state = Some(Pending::One {
|
*state = Some(Pending::One {
|
||||||
from: cursor_position,
|
from: cursor_position,
|
||||||
});
|
});
|
||||||
|
|
||||||
None
|
canvas::Action::request_redraw()
|
||||||
}
|
|
||||||
Some(Pending::One { from }) => {
|
|
||||||
*state = Some(Pending::Two {
|
|
||||||
from,
|
|
||||||
to: cursor_position,
|
|
||||||
});
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Some(Pending::Two { from, to }) => {
|
|
||||||
*state = None;
|
|
||||||
|
|
||||||
Some(Curve {
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
control: cursor_position,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => None,
|
Some(Pending::One { from }) => {
|
||||||
};
|
*state = Some(Pending::Two {
|
||||||
|
from,
|
||||||
|
to: cursor_position,
|
||||||
|
});
|
||||||
|
|
||||||
(event::Status::Captured, message)
|
canvas::Action::request_redraw()
|
||||||
|
}
|
||||||
|
Some(Pending::Two { from, to }) => {
|
||||||
|
*state = None;
|
||||||
|
|
||||||
|
canvas::Action::publish(Curve {
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
control: cursor_position,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.and_capture(),
|
||||||
|
),
|
||||||
|
Event::Mouse(mouse::Event::CursorMoved { .. })
|
||||||
|
if state.is_some() =>
|
||||||
|
{
|
||||||
|
Some(canvas::Action::request_redraw())
|
||||||
}
|
}
|
||||||
_ => (event::Status::Ignored, None),
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -193,8 +193,9 @@ mod grid {
|
||||||
use iced::mouse;
|
use iced::mouse;
|
||||||
use iced::touch;
|
use iced::touch;
|
||||||
use iced::widget::canvas;
|
use iced::widget::canvas;
|
||||||
use iced::widget::canvas::event::{self, Event};
|
use iced::widget::canvas::{
|
||||||
use iced::widget::canvas::{Cache, Canvas, Frame, Geometry, Path, Text};
|
Cache, Canvas, Event, Frame, Geometry, Path, Text,
|
||||||
|
};
|
||||||
use iced::{
|
use iced::{
|
||||||
Color, Element, Fill, Point, Rectangle, Renderer, Size, Theme, Vector,
|
Color, Element, Fill, Point, Rectangle, Renderer, Size, Theme, Vector,
|
||||||
};
|
};
|
||||||
|
|
@ -383,14 +384,12 @@ mod grid {
|
||||||
event: Event,
|
event: Event,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
cursor: mouse::Cursor,
|
cursor: mouse::Cursor,
|
||||||
) -> (event::Status, Option<Message>) {
|
) -> Option<canvas::Action<Message>> {
|
||||||
if let Event::Mouse(mouse::Event::ButtonReleased(_)) = event {
|
if let Event::Mouse(mouse::Event::ButtonReleased(_)) = event {
|
||||||
*interaction = Interaction::None;
|
*interaction = Interaction::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(cursor_position) = cursor.position_in(bounds) else {
|
let cursor_position = cursor.position_in(bounds)?;
|
||||||
return (event::Status::Ignored, None);
|
|
||||||
};
|
|
||||||
|
|
||||||
let cell = Cell::at(self.project(cursor_position, bounds.size()));
|
let cell = Cell::at(self.project(cursor_position, bounds.size()));
|
||||||
let is_populated = self.state.contains(&cell);
|
let is_populated = self.state.contains(&cell);
|
||||||
|
|
@ -413,7 +412,12 @@ mod grid {
|
||||||
populate.or(unpopulate)
|
populate.or(unpopulate)
|
||||||
};
|
};
|
||||||
|
|
||||||
(event::Status::Captured, message)
|
Some(
|
||||||
|
message
|
||||||
|
.map(canvas::Action::publish)
|
||||||
|
.unwrap_or(canvas::Action::request_redraw())
|
||||||
|
.and_capture(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Event::Mouse(mouse_event) => match mouse_event {
|
Event::Mouse(mouse_event) => match mouse_event {
|
||||||
mouse::Event::ButtonPressed(button) => {
|
mouse::Event::ButtonPressed(button) => {
|
||||||
|
|
@ -438,7 +442,12 @@ mod grid {
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
(event::Status::Captured, message)
|
Some(
|
||||||
|
message
|
||||||
|
.map(canvas::Action::publish)
|
||||||
|
.unwrap_or(canvas::Action::request_redraw())
|
||||||
|
.and_capture(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
mouse::Event::CursorMoved { .. } => {
|
mouse::Event::CursorMoved { .. } => {
|
||||||
let message = match *interaction {
|
let message = match *interaction {
|
||||||
|
|
@ -454,12 +463,14 @@ mod grid {
|
||||||
Interaction::None => None,
|
Interaction::None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let event_status = match interaction {
|
let action = message
|
||||||
Interaction::None => event::Status::Ignored,
|
.map(canvas::Action::publish)
|
||||||
_ => event::Status::Captured,
|
.unwrap_or(canvas::Action::request_redraw());
|
||||||
};
|
|
||||||
|
|
||||||
(event_status, message)
|
Some(match interaction {
|
||||||
|
Interaction::None => action,
|
||||||
|
_ => action.and_capture(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
mouse::Event::WheelScrolled { delta } => match delta {
|
mouse::Event::WheelScrolled { delta } => match delta {
|
||||||
mouse::ScrollDelta::Lines { y, .. }
|
mouse::ScrollDelta::Lines { y, .. }
|
||||||
|
|
@ -496,18 +507,21 @@ mod grid {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
Some(
|
||||||
event::Status::Captured,
|
canvas::Action::publish(Message::Scaled(
|
||||||
Some(Message::Scaled(scaling, translation)),
|
scaling,
|
||||||
|
translation,
|
||||||
|
))
|
||||||
|
.and_capture(),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
(event::Status::Captured, None)
|
Some(canvas::Action::capture())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => (event::Status::Ignored, None),
|
_ => None,
|
||||||
},
|
},
|
||||||
_ => (event::Status::Ignored, None),
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,8 @@
|
||||||
//! computers like Microsoft Surface.
|
//! computers like Microsoft Surface.
|
||||||
use iced::mouse;
|
use iced::mouse;
|
||||||
use iced::touch;
|
use iced::touch;
|
||||||
use iced::widget::canvas::event;
|
|
||||||
use iced::widget::canvas::stroke::{self, Stroke};
|
use iced::widget::canvas::stroke::{self, Stroke};
|
||||||
use iced::widget::canvas::{self, Canvas, Geometry};
|
use iced::widget::canvas::{self, Canvas, Event, Geometry};
|
||||||
use iced::{Color, Element, Fill, Point, Rectangle, Renderer, Theme};
|
use iced::{Color, Element, Fill, Point, Rectangle, Renderer, Theme};
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
@ -56,25 +55,25 @@ impl canvas::Program<Message> for Multitouch {
|
||||||
fn update(
|
fn update(
|
||||||
&self,
|
&self,
|
||||||
_state: &mut Self::State,
|
_state: &mut Self::State,
|
||||||
event: event::Event,
|
event: Event,
|
||||||
_bounds: Rectangle,
|
_bounds: Rectangle,
|
||||||
_cursor: mouse::Cursor,
|
_cursor: mouse::Cursor,
|
||||||
) -> (event::Status, Option<Message>) {
|
) -> Option<canvas::Action<Message>> {
|
||||||
match event {
|
let message = match event {
|
||||||
event::Event::Touch(touch_event) => match touch_event {
|
Event::Touch(
|
||||||
touch::Event::FingerPressed { id, position }
|
touch::Event::FingerPressed { id, position }
|
||||||
| touch::Event::FingerMoved { id, position } => (
|
| touch::Event::FingerMoved { id, position },
|
||||||
event::Status::Captured,
|
) => Some(Message::FingerPressed { id, position }),
|
||||||
Some(Message::FingerPressed { id, position }),
|
Event::Touch(
|
||||||
),
|
|
||||||
touch::Event::FingerLifted { id, .. }
|
touch::Event::FingerLifted { id, .. }
|
||||||
| touch::Event::FingerLost { id, .. } => (
|
| touch::Event::FingerLost { id, .. },
|
||||||
event::Status::Captured,
|
) => Some(Message::FingerLifted { id }),
|
||||||
Some(Message::FingerLifted { id }),
|
_ => None,
|
||||||
),
|
};
|
||||||
},
|
|
||||||
_ => (event::Status::Ignored, None),
|
message
|
||||||
}
|
.map(canvas::Action::publish)
|
||||||
|
.map(canvas::Action::and_capture)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(
|
fn draw(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
use iced::mouse;
|
use iced::mouse;
|
||||||
use iced::widget::canvas::event::{self, Event};
|
use iced::widget::canvas::{self, Canvas, Event, Geometry};
|
||||||
use iced::widget::canvas::{self, Canvas, Geometry};
|
|
||||||
use iced::widget::{column, row, slider, text};
|
use iced::widget::{column, row, slider, text};
|
||||||
use iced::{Center, Color, Fill, Point, Rectangle, Renderer, Size, Theme};
|
use iced::{Center, Color, Fill, Point, Rectangle, Renderer, Size, Theme};
|
||||||
|
|
||||||
|
|
@ -80,26 +79,22 @@ impl canvas::Program<Message> for SierpinskiGraph {
|
||||||
event: Event,
|
event: Event,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
cursor: mouse::Cursor,
|
cursor: mouse::Cursor,
|
||||||
) -> (event::Status, Option<Message>) {
|
) -> Option<canvas::Action<Message>> {
|
||||||
let Some(cursor_position) = cursor.position_in(bounds) else {
|
let cursor_position = cursor.position_in(bounds)?;
|
||||||
return (event::Status::Ignored, None);
|
|
||||||
};
|
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::Mouse(mouse_event) => {
|
Event::Mouse(mouse::Event::ButtonPressed(button)) => match button {
|
||||||
let message = match mouse_event {
|
mouse::Button::Left => Some(canvas::Action::publish(
|
||||||
iced::mouse::Event::ButtonPressed(
|
Message::PointAdded(cursor_position),
|
||||||
iced::mouse::Button::Left,
|
)),
|
||||||
) => Some(Message::PointAdded(cursor_position)),
|
mouse::Button::Right => {
|
||||||
iced::mouse::Event::ButtonPressed(
|
Some(canvas::Action::publish(Message::PointRemoved))
|
||||||
iced::mouse::Button::Right,
|
}
|
||||||
) => Some(Message::PointRemoved),
|
_ => None,
|
||||||
_ => None,
|
},
|
||||||
};
|
_ => None,
|
||||||
(event::Status::Captured, message)
|
|
||||||
}
|
|
||||||
_ => (event::Status::Ignored, None),
|
|
||||||
}
|
}
|
||||||
|
.map(canvas::Action::and_capture)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(
|
fn draw(
|
||||||
|
|
|
||||||
89
widget/src/action.rs
Normal file
89
widget/src/action.rs
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
use crate::core::event;
|
||||||
|
use crate::core::time::Instant;
|
||||||
|
use crate::core::window;
|
||||||
|
|
||||||
|
/// A runtime action that can be performed by some widgets.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Action<Message> {
|
||||||
|
message_to_publish: Option<Message>,
|
||||||
|
redraw_request: Option<window::RedrawRequest>,
|
||||||
|
event_status: event::Status,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Message> Action<Message> {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
message_to_publish: None,
|
||||||
|
redraw_request: None,
|
||||||
|
event_status: event::Status::Ignored,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new "capturing" [`Action`]. A capturing [`Action`]
|
||||||
|
/// will make other widgets consider it final and prevent further
|
||||||
|
/// processing.
|
||||||
|
///
|
||||||
|
/// Prevents "event bubbling".
|
||||||
|
pub fn capture() -> Self {
|
||||||
|
Self {
|
||||||
|
event_status: event::Status::Captured,
|
||||||
|
..Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new [`Action`] that publishes the given `Message` for
|
||||||
|
/// the application to handle.
|
||||||
|
///
|
||||||
|
/// Publishing a `Message` always produces a redraw.
|
||||||
|
pub fn publish(message: Message) -> Self {
|
||||||
|
Self {
|
||||||
|
message_to_publish: Some(message),
|
||||||
|
..Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new [`Action`] that requests a redraw to happen as
|
||||||
|
/// soon as possible; without publishing any `Message`.
|
||||||
|
pub fn request_redraw() -> Self {
|
||||||
|
Self {
|
||||||
|
redraw_request: Some(window::RedrawRequest::NextFrame),
|
||||||
|
..Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new [`Action`] that requests a redraw to happen at
|
||||||
|
/// the given [`Instant`]; without publishing any `Message`.
|
||||||
|
///
|
||||||
|
/// This can be useful to efficiently animate content, like a
|
||||||
|
/// blinking caret on a text input.
|
||||||
|
pub fn request_redraw_at(at: Instant) -> Self {
|
||||||
|
Self {
|
||||||
|
redraw_request: Some(window::RedrawRequest::At(at)),
|
||||||
|
..Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Marks the [`Action`] as "capturing". See [`Self::capture`].
|
||||||
|
pub fn and_capture(mut self) -> Self {
|
||||||
|
self.event_status = event::Status::Captured;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts the [`Action`] into its internal parts.
|
||||||
|
///
|
||||||
|
/// This method is meant to be used by runtimes, libraries, or internal
|
||||||
|
/// widget implementations.
|
||||||
|
pub fn into_inner(
|
||||||
|
self,
|
||||||
|
) -> (
|
||||||
|
Option<Message>,
|
||||||
|
Option<window::RedrawRequest>,
|
||||||
|
event::Status,
|
||||||
|
) {
|
||||||
|
(
|
||||||
|
self.message_to_publish,
|
||||||
|
self.redraw_request,
|
||||||
|
self.event_status,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -48,24 +48,24 @@
|
||||||
//! canvas(Circle { radius: 50.0 }).into()
|
//! canvas(Circle { radius: 50.0 }).into()
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
pub mod event;
|
|
||||||
|
|
||||||
mod program;
|
mod program;
|
||||||
|
|
||||||
pub use event::Event;
|
|
||||||
pub use program::Program;
|
pub use program::Program;
|
||||||
|
|
||||||
|
pub use crate::core::event::Event;
|
||||||
pub use crate::graphics::cache::Group;
|
pub use crate::graphics::cache::Group;
|
||||||
pub use crate::graphics::geometry::{
|
pub use crate::graphics::geometry::{
|
||||||
fill, gradient, path, stroke, Fill, Gradient, Image, LineCap, LineDash,
|
fill, gradient, path, stroke, Fill, Gradient, Image, LineCap, LineDash,
|
||||||
LineJoin, Path, Stroke, Style, Text,
|
LineJoin, Path, Stroke, Style, Text,
|
||||||
};
|
};
|
||||||
|
pub use crate::Action;
|
||||||
|
|
||||||
use crate::core;
|
use crate::core::event;
|
||||||
use crate::core::layout::{self, Layout};
|
use crate::core::layout::{self, Layout};
|
||||||
use crate::core::mouse;
|
use crate::core::mouse;
|
||||||
use crate::core::renderer;
|
use crate::core::renderer;
|
||||||
use crate::core::widget::tree::{self, Tree};
|
use crate::core::widget::tree::{self, Tree};
|
||||||
|
use crate::core::window;
|
||||||
use crate::core::{
|
use crate::core::{
|
||||||
Clipboard, Element, Length, Rectangle, Shell, Size, Vector, Widget,
|
Clipboard, Element, Length, Rectangle, Shell, Size, Vector, Widget,
|
||||||
};
|
};
|
||||||
|
|
@ -148,6 +148,7 @@ where
|
||||||
message_: PhantomData<Message>,
|
message_: PhantomData<Message>,
|
||||||
theme_: PhantomData<Theme>,
|
theme_: PhantomData<Theme>,
|
||||||
renderer_: PhantomData<Renderer>,
|
renderer_: PhantomData<Renderer>,
|
||||||
|
last_mouse_interaction: Option<mouse::Interaction>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P, Message, Theme, Renderer> Canvas<P, Message, Theme, Renderer>
|
impl<P, Message, Theme, Renderer> Canvas<P, Message, Theme, Renderer>
|
||||||
|
|
@ -166,6 +167,7 @@ where
|
||||||
message_: PhantomData,
|
message_: PhantomData,
|
||||||
theme_: PhantomData,
|
theme_: PhantomData,
|
||||||
renderer_: PhantomData,
|
renderer_: PhantomData,
|
||||||
|
last_mouse_interaction: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -216,39 +218,60 @@ where
|
||||||
fn update(
|
fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
tree: &mut Tree,
|
tree: &mut Tree,
|
||||||
event: core::Event,
|
event: Event,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor: mouse::Cursor,
|
cursor: mouse::Cursor,
|
||||||
_renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
_clipboard: &mut dyn Clipboard,
|
_clipboard: &mut dyn Clipboard,
|
||||||
shell: &mut Shell<'_, Message>,
|
shell: &mut Shell<'_, Message>,
|
||||||
_viewport: &Rectangle,
|
viewport: &Rectangle,
|
||||||
) {
|
) {
|
||||||
let bounds = layout.bounds();
|
let bounds = layout.bounds();
|
||||||
|
|
||||||
let canvas_event = match event {
|
let state = tree.state.downcast_mut::<P::State>();
|
||||||
core::Event::Mouse(mouse_event) => Some(Event::Mouse(mouse_event)),
|
let is_redraw_request = matches!(
|
||||||
core::Event::Touch(touch_event) => Some(Event::Touch(touch_event)),
|
event,
|
||||||
core::Event::Keyboard(keyboard_event) => {
|
Event::Window(window::Event::RedrawRequested(_now)),
|
||||||
Some(Event::Keyboard(keyboard_event))
|
);
|
||||||
}
|
|
||||||
core::Event::Window(_) => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(canvas_event) = canvas_event {
|
if let Some(action) = self.program.update(state, event, bounds, cursor)
|
||||||
let state = tree.state.downcast_mut::<P::State>();
|
{
|
||||||
|
let (message, redraw_request, event_status) = action.into_inner();
|
||||||
let (event_status, message) =
|
|
||||||
self.program.update(state, canvas_event, bounds, cursor);
|
|
||||||
|
|
||||||
if let Some(message) = message {
|
if let Some(message) = message {
|
||||||
shell.publish(message);
|
shell.publish(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(redraw_request) = redraw_request {
|
||||||
|
match redraw_request {
|
||||||
|
window::RedrawRequest::NextFrame => {
|
||||||
|
shell.request_redraw();
|
||||||
|
}
|
||||||
|
window::RedrawRequest::At(at) => {
|
||||||
|
shell.request_redraw_at(at);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if event_status == event::Status::Captured {
|
if event_status == event::Status::Captured {
|
||||||
shell.capture_event();
|
shell.capture_event();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if shell.redraw_request() != Some(window::RedrawRequest::NextFrame) {
|
||||||
|
let mouse_interaction = self
|
||||||
|
.mouse_interaction(tree, layout, cursor, viewport, renderer);
|
||||||
|
|
||||||
|
if is_redraw_request {
|
||||||
|
self.last_mouse_interaction = Some(mouse_interaction);
|
||||||
|
} else if self.last_mouse_interaction.is_some_and(
|
||||||
|
|last_mouse_interaction| {
|
||||||
|
last_mouse_interaction != mouse_interaction
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
shell.request_redraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mouse_interaction(
|
fn mouse_interaction(
|
||||||
|
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
//! Handle events of a canvas.
|
|
||||||
use crate::core::keyboard;
|
|
||||||
use crate::core::mouse;
|
|
||||||
use crate::core::touch;
|
|
||||||
|
|
||||||
pub use crate::core::event::Status;
|
|
||||||
|
|
||||||
/// A [`Canvas`] event.
|
|
||||||
///
|
|
||||||
/// [`Canvas`]: crate::Canvas
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub enum Event {
|
|
||||||
/// A mouse event.
|
|
||||||
Mouse(mouse::Event),
|
|
||||||
|
|
||||||
/// A touch event.
|
|
||||||
Touch(touch::Event),
|
|
||||||
|
|
||||||
/// A keyboard event.
|
|
||||||
Keyboard(keyboard::Event),
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::canvas::event::{self, Event};
|
|
||||||
use crate::canvas::mouse;
|
use crate::canvas::mouse;
|
||||||
use crate::canvas::Geometry;
|
use crate::canvas::{Event, Geometry};
|
||||||
use crate::core::Rectangle;
|
use crate::core::Rectangle;
|
||||||
use crate::graphics::geometry;
|
use crate::graphics::geometry;
|
||||||
|
use crate::Action;
|
||||||
|
|
||||||
/// The state and logic of a [`Canvas`].
|
/// The state and logic of a [`Canvas`].
|
||||||
///
|
///
|
||||||
|
|
@ -22,8 +22,9 @@ where
|
||||||
/// When a [`Program`] is used in a [`Canvas`], the runtime will call this
|
/// When a [`Program`] is used in a [`Canvas`], the runtime will call this
|
||||||
/// method for each [`Event`].
|
/// method for each [`Event`].
|
||||||
///
|
///
|
||||||
/// This method can optionally return a `Message` to notify an application
|
/// This method can optionally return an [`Action`] to either notify an
|
||||||
/// of any meaningful interactions.
|
/// application of any meaningful interactions, capture the event, or
|
||||||
|
/// request a redraw.
|
||||||
///
|
///
|
||||||
/// By default, this method does and returns nothing.
|
/// By default, this method does and returns nothing.
|
||||||
///
|
///
|
||||||
|
|
@ -34,8 +35,8 @@ where
|
||||||
_event: Event,
|
_event: Event,
|
||||||
_bounds: Rectangle,
|
_bounds: Rectangle,
|
||||||
_cursor: mouse::Cursor,
|
_cursor: mouse::Cursor,
|
||||||
) -> (event::Status, Option<Message>) {
|
) -> Option<Action<Message>> {
|
||||||
(event::Status::Ignored, None)
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draws the state of the [`Program`], producing a bunch of [`Geometry`].
|
/// Draws the state of the [`Program`], producing a bunch of [`Geometry`].
|
||||||
|
|
@ -84,7 +85,7 @@ where
|
||||||
event: Event,
|
event: Event,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
cursor: mouse::Cursor,
|
cursor: mouse::Cursor,
|
||||||
) -> (event::Status, Option<Message>) {
|
) -> Option<Action<Message>> {
|
||||||
T::update(self, state, event, bounds, cursor)
|
T::update(self, state, event, bounds, cursor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ pub use iced_renderer::graphics;
|
||||||
pub use iced_runtime as runtime;
|
pub use iced_runtime as runtime;
|
||||||
pub use iced_runtime::core;
|
pub use iced_runtime::core;
|
||||||
|
|
||||||
|
mod action;
|
||||||
mod column;
|
mod column;
|
||||||
mod mouse_area;
|
mod mouse_area;
|
||||||
mod row;
|
mod row;
|
||||||
|
|
@ -131,4 +132,5 @@ pub use qr_code::QRCode;
|
||||||
pub mod markdown;
|
pub mod markdown;
|
||||||
|
|
||||||
pub use crate::core::theme::{self, Theme};
|
pub use crate::core::theme::{self, Theme};
|
||||||
|
pub use action::Action;
|
||||||
pub use renderer::Renderer;
|
pub use renderer::Renderer;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue