summaryrefslogtreecommitdiffstats
path: root/widget/src/canvas
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2023-03-04 05:37:11 +0100
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2023-03-04 05:37:11 +0100
commit3a0d34c0240f4421737a6a08761f99d6f8140d02 (patch)
treec9a4a6b8e9c1db1b8fcd05bc98e3f131d5ef4bd5 /widget/src/canvas
parentc54409d1711e1f615c7ea4b02c082954e340632a (diff)
downloadiced-3a0d34c0240f4421737a6a08761f99d6f8140d02.tar.gz
iced-3a0d34c0240f4421737a6a08761f99d6f8140d02.tar.bz2
iced-3a0d34c0240f4421737a6a08761f99d6f8140d02.zip
Create `iced_widget` subcrate and re-organize the whole codebase
Diffstat (limited to 'widget/src/canvas')
-rw-r--r--widget/src/canvas/cursor.rs64
-rw-r--r--widget/src/canvas/event.rs21
-rw-r--r--widget/src/canvas/program.rs109
3 files changed, 194 insertions, 0 deletions
diff --git a/widget/src/canvas/cursor.rs b/widget/src/canvas/cursor.rs
new file mode 100644
index 00000000..5a65e9a7
--- /dev/null
+++ b/widget/src/canvas/cursor.rs
@@ -0,0 +1,64 @@
+use crate::core::{Point, Rectangle};
+
+/// The mouse cursor state.
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum Cursor {
+ /// The cursor has a defined position.
+ Available(Point),
+
+ /// The cursor is currently unavailable (i.e. out of bounds or busy).
+ Unavailable,
+}
+
+impl Cursor {
+ // TODO: Remove this once this type is used in `iced_native` to encode
+ // proper cursor availability
+ pub(crate) fn from_window_position(position: Point) -> Self {
+ if position.x < 0.0 || position.y < 0.0 {
+ Cursor::Unavailable
+ } else {
+ Cursor::Available(position)
+ }
+ }
+
+ /// Returns the absolute position of the [`Cursor`], if available.
+ pub fn position(&self) -> Option<Point> {
+ match self {
+ Cursor::Available(position) => Some(*position),
+ Cursor::Unavailable => None,
+ }
+ }
+
+ /// Returns the relative position of the [`Cursor`] inside the given bounds,
+ /// if available.
+ ///
+ /// If the [`Cursor`] is not over the provided bounds, this method will
+ /// return `None`.
+ pub fn position_in(&self, bounds: &Rectangle) -> Option<Point> {
+ if self.is_over(bounds) {
+ self.position_from(bounds.position())
+ } else {
+ None
+ }
+ }
+
+ /// Returns the relative position of the [`Cursor`] from the given origin,
+ /// if available.
+ pub fn position_from(&self, origin: Point) -> Option<Point> {
+ match self {
+ Cursor::Available(position) => {
+ Some(Point::new(position.x - origin.x, position.y - origin.y))
+ }
+ Cursor::Unavailable => None,
+ }
+ }
+
+ /// Returns whether the [`Cursor`] is currently over the provided bounds
+ /// or not.
+ pub fn is_over(&self, bounds: &Rectangle) -> bool {
+ match self {
+ Cursor::Available(position) => bounds.contains(*position),
+ Cursor::Unavailable => false,
+ }
+ }
+}
diff --git a/widget/src/canvas/event.rs b/widget/src/canvas/event.rs
new file mode 100644
index 00000000..4508c184
--- /dev/null
+++ b/widget/src/canvas/event.rs
@@ -0,0 +1,21 @@
+//! 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::widget::Canvas
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum Event {
+ /// A mouse event.
+ Mouse(mouse::Event),
+
+ /// A touch event.
+ Touch(touch::Event),
+
+ /// A keyboard event.
+ Keyboard(keyboard::Event),
+}
diff --git a/widget/src/canvas/program.rs b/widget/src/canvas/program.rs
new file mode 100644
index 00000000..efb33c56
--- /dev/null
+++ b/widget/src/canvas/program.rs
@@ -0,0 +1,109 @@
+use crate::canvas::event::{self, Event};
+use crate::canvas::mouse;
+use crate::canvas::Cursor;
+use crate::core::Rectangle;
+use crate::graphics::geometry;
+
+/// The state and logic of a [`Canvas`].
+///
+/// A [`Program`] can mutate internal state and produce messages for an
+/// application.
+///
+/// [`Canvas`]: crate::widget::Canvas
+pub trait Program<Message, Renderer = crate::Renderer>
+where
+ Renderer: geometry::Renderer,
+{
+ /// The internal state mutated by the [`Program`].
+ type State: Default + 'static;
+
+ /// Updates the [`State`](Self::State) of the [`Program`].
+ ///
+ /// When a [`Program`] is used in a [`Canvas`], the runtime will call this
+ /// method for each [`Event`].
+ ///
+ /// This method can optionally return a `Message` to notify an application
+ /// of any meaningful interactions.
+ ///
+ /// By default, this method does and returns nothing.
+ ///
+ /// [`Canvas`]: crate::widget::Canvas
+ fn update(
+ &self,
+ _state: &mut Self::State,
+ _event: Event,
+ _bounds: Rectangle,
+ _cursor: Cursor,
+ ) -> (event::Status, Option<Message>) {
+ (event::Status::Ignored, None)
+ }
+
+ /// Draws the state of the [`Program`], producing a bunch of [`Geometry`].
+ ///
+ /// [`Geometry`] can be easily generated with a [`Frame`] or stored in a
+ /// [`Cache`].
+ ///
+ /// [`Frame`]: crate::widget::canvas::Frame
+ /// [`Cache`]: crate::widget::canvas::Cache
+ fn draw(
+ &self,
+ state: &Self::State,
+ renderer: &Renderer,
+ theme: &Renderer::Theme,
+ bounds: Rectangle,
+ cursor: Cursor,
+ ) -> Vec<Renderer::Geometry>;
+
+ /// Returns the current mouse interaction of the [`Program`].
+ ///
+ /// The interaction returned will be in effect even if the cursor position
+ /// is out of bounds of the program's [`Canvas`].
+ ///
+ /// [`Canvas`]: crate::widget::Canvas
+ fn mouse_interaction(
+ &self,
+ _state: &Self::State,
+ _bounds: Rectangle,
+ _cursor: Cursor,
+ ) -> mouse::Interaction {
+ mouse::Interaction::default()
+ }
+}
+
+impl<Message, Renderer, T> Program<Message, Renderer> for &T
+where
+ Renderer: geometry::Renderer,
+ T: Program<Message, Renderer>,
+{
+ type State = T::State;
+
+ fn update(
+ &self,
+ state: &mut Self::State,
+ event: Event,
+ bounds: Rectangle,
+ cursor: Cursor,
+ ) -> (event::Status, Option<Message>) {
+ T::update(self, state, event, bounds, cursor)
+ }
+
+ fn draw(
+ &self,
+ state: &Self::State,
+ renderer: &Renderer,
+ theme: &Renderer::Theme,
+ bounds: Rectangle,
+ cursor: Cursor,
+ ) -> Vec<Renderer::Geometry> {
+ T::draw(self, state, renderer, theme, bounds, cursor)
+ }
+
+ fn mouse_interaction(
+ &self,
+ state: &Self::State,
+ bounds: Rectangle,
+ cursor: Cursor,
+ ) -> mouse::Interaction {
+ T::mouse_interaction(self, state, bounds, cursor)
+ }
+}