summaryrefslogtreecommitdiffstats
path: root/widget/src/mouse_area.rs
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2023-04-17 23:41:12 +0200
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2023-04-17 23:41:12 +0200
commit4bae457c37b499f3cfddbdac9ff37a34cbce61d5 (patch)
tree79af93b2f7fabca1687900b48b165c5c74dcd26f /widget/src/mouse_area.rs
parentc0431aedd3bbef4161456f2fa5f29866e8f17fc5 (diff)
parent4b05f42fd6d18bf572b772dd60d6a4309ea5f343 (diff)
downloadiced-4bae457c37b499f3cfddbdac9ff37a34cbce61d5.tar.gz
iced-4bae457c37b499f3cfddbdac9ff37a34cbce61d5.tar.bz2
iced-4bae457c37b499f3cfddbdac9ff37a34cbce61d5.zip
Merge branch 'master' into advanced-text
Diffstat (limited to 'widget/src/mouse_area.rs')
-rw-r--r--widget/src/mouse_area.rs311
1 files changed, 311 insertions, 0 deletions
diff --git a/widget/src/mouse_area.rs b/widget/src/mouse_area.rs
new file mode 100644
index 00000000..0232c494
--- /dev/null
+++ b/widget/src/mouse_area.rs
@@ -0,0 +1,311 @@
+//! A container for capturing mouse events.
+
+use crate::core::event::{self, Event};
+use crate::core::layout;
+use crate::core::mouse;
+use crate::core::overlay;
+use crate::core::renderer;
+use crate::core::touch;
+use crate::core::widget::{tree, Operation, Tree};
+use crate::core::{
+ Clipboard, Element, Layout, Length, Point, Rectangle, Shell, Widget,
+};
+
+/// Emit messages on mouse events.
+#[allow(missing_debug_implementations)]
+pub struct MouseArea<'a, Message, Renderer> {
+ content: Element<'a, Message, Renderer>,
+ on_press: Option<Message>,
+ on_release: Option<Message>,
+ on_right_press: Option<Message>,
+ on_right_release: Option<Message>,
+ on_middle_press: Option<Message>,
+ on_middle_release: Option<Message>,
+}
+
+impl<'a, Message, Renderer> MouseArea<'a, Message, Renderer> {
+ /// The message to emit on a left button press.
+ #[must_use]
+ pub fn on_press(mut self, message: Message) -> Self {
+ self.on_press = Some(message);
+ self
+ }
+
+ /// The message to emit on a left button release.
+ #[must_use]
+ pub fn on_release(mut self, message: Message) -> Self {
+ self.on_release = Some(message);
+ self
+ }
+
+ /// The message to emit on a right button press.
+ #[must_use]
+ pub fn on_right_press(mut self, message: Message) -> Self {
+ self.on_right_press = Some(message);
+ self
+ }
+
+ /// The message to emit on a right button release.
+ #[must_use]
+ pub fn on_right_release(mut self, message: Message) -> Self {
+ self.on_right_release = Some(message);
+ self
+ }
+
+ /// The message to emit on a middle button press.
+ #[must_use]
+ pub fn on_middle_press(mut self, message: Message) -> Self {
+ self.on_middle_press = Some(message);
+ self
+ }
+
+ /// The message to emit on a middle button release.
+ #[must_use]
+ pub fn on_middle_release(mut self, message: Message) -> Self {
+ self.on_middle_release = Some(message);
+ self
+ }
+}
+
+/// Local state of the [`MouseArea`].
+#[derive(Default)]
+struct State {
+ // TODO: Support on_mouse_enter and on_mouse_exit
+}
+
+impl<'a, Message, Renderer> MouseArea<'a, Message, Renderer> {
+ /// Creates a [`MouseArea`] with the given content.
+ pub fn new(content: impl Into<Element<'a, Message, Renderer>>) -> Self {
+ MouseArea {
+ content: content.into(),
+ on_press: None,
+ on_release: None,
+ on_right_press: None,
+ on_right_release: None,
+ on_middle_press: None,
+ on_middle_release: None,
+ }
+ }
+}
+
+impl<'a, Message, Renderer> Widget<Message, Renderer>
+ for MouseArea<'a, Message, Renderer>
+where
+ Renderer: renderer::Renderer,
+ Message: Clone,
+{
+ fn tag(&self) -> tree::Tag {
+ tree::Tag::of::<State>()
+ }
+
+ fn state(&self) -> tree::State {
+ tree::State::new(State::default())
+ }
+
+ fn children(&self) -> Vec<Tree> {
+ vec![Tree::new(&self.content)]
+ }
+
+ fn diff(&self, tree: &mut Tree) {
+ tree.diff_children(std::slice::from_ref(&self.content));
+ }
+
+ fn width(&self) -> Length {
+ self.content.as_widget().width()
+ }
+
+ fn height(&self) -> Length {
+ self.content.as_widget().height()
+ }
+
+ fn layout(
+ &self,
+ renderer: &Renderer,
+ limits: &layout::Limits,
+ ) -> layout::Node {
+ self.content.as_widget().layout(renderer, limits)
+ }
+
+ fn operate(
+ &self,
+ tree: &mut Tree,
+ layout: Layout<'_>,
+ renderer: &Renderer,
+ operation: &mut dyn Operation<Message>,
+ ) {
+ self.content.as_widget().operate(
+ &mut tree.children[0],
+ layout,
+ renderer,
+ operation,
+ );
+ }
+
+ fn on_event(
+ &mut self,
+ tree: &mut Tree,
+ event: Event,
+ layout: Layout<'_>,
+ cursor_position: Point,
+ renderer: &Renderer,
+ clipboard: &mut dyn Clipboard,
+ shell: &mut Shell<'_, Message>,
+ ) -> event::Status {
+ if let event::Status::Captured = self.content.as_widget_mut().on_event(
+ &mut tree.children[0],
+ event.clone(),
+ layout,
+ cursor_position,
+ renderer,
+ clipboard,
+ shell,
+ ) {
+ return event::Status::Captured;
+ }
+
+ update(self, &event, layout, cursor_position, shell)
+ }
+
+ fn mouse_interaction(
+ &self,
+ tree: &Tree,
+ layout: Layout<'_>,
+ cursor_position: Point,
+ viewport: &Rectangle,
+ renderer: &Renderer,
+ ) -> mouse::Interaction {
+ self.content.as_widget().mouse_interaction(
+ &tree.children[0],
+ layout,
+ cursor_position,
+ viewport,
+ renderer,
+ )
+ }
+
+ fn draw(
+ &self,
+ tree: &Tree,
+ renderer: &mut Renderer,
+ theme: &Renderer::Theme,
+ renderer_style: &renderer::Style,
+ layout: Layout<'_>,
+ cursor_position: Point,
+ viewport: &Rectangle,
+ ) {
+ self.content.as_widget().draw(
+ &tree.children[0],
+ renderer,
+ theme,
+ renderer_style,
+ layout,
+ cursor_position,
+ viewport,
+ );
+ }
+
+ fn overlay<'b>(
+ &'b mut self,
+ tree: &'b mut Tree,
+ layout: Layout<'_>,
+ renderer: &Renderer,
+ ) -> Option<overlay::Element<'b, Message, Renderer>> {
+ self.content.as_widget_mut().overlay(
+ &mut tree.children[0],
+ layout,
+ renderer,
+ )
+ }
+}
+
+impl<'a, Message, Renderer> From<MouseArea<'a, Message, Renderer>>
+ for Element<'a, Message, Renderer>
+where
+ Message: 'a + Clone,
+ Renderer: 'a + renderer::Renderer,
+{
+ fn from(
+ area: MouseArea<'a, Message, Renderer>,
+ ) -> Element<'a, Message, Renderer> {
+ Element::new(area)
+ }
+}
+
+/// Processes the given [`Event`] and updates the [`State`] of an [`MouseArea`]
+/// accordingly.
+fn update<Message: Clone, Renderer>(
+ widget: &mut MouseArea<'_, Message, Renderer>,
+ event: &Event,
+ layout: Layout<'_>,
+ cursor_position: Point,
+ shell: &mut Shell<'_, Message>,
+) -> event::Status {
+ if !layout.bounds().contains(cursor_position) {
+ return event::Status::Ignored;
+ }
+
+ if let Some(message) = widget.on_press.as_ref() {
+ if let Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))
+ | Event::Touch(touch::Event::FingerPressed { .. }) = event
+ {
+ shell.publish(message.clone());
+
+ return event::Status::Captured;
+ }
+ }
+
+ if let Some(message) = widget.on_release.as_ref() {
+ if let Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left))
+ | Event::Touch(touch::Event::FingerLifted { .. }) = event
+ {
+ shell.publish(message.clone());
+
+ return event::Status::Captured;
+ }
+ }
+
+ if let Some(message) = widget.on_right_press.as_ref() {
+ if let Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Right)) =
+ event
+ {
+ shell.publish(message.clone());
+
+ return event::Status::Captured;
+ }
+ }
+
+ if let Some(message) = widget.on_right_release.as_ref() {
+ if let Event::Mouse(mouse::Event::ButtonReleased(
+ mouse::Button::Right,
+ )) = event
+ {
+ shell.publish(message.clone());
+
+ return event::Status::Captured;
+ }
+ }
+
+ if let Some(message) = widget.on_middle_press.as_ref() {
+ if let Event::Mouse(mouse::Event::ButtonPressed(
+ mouse::Button::Middle,
+ )) = event
+ {
+ shell.publish(message.clone());
+
+ return event::Status::Captured;
+ }
+ }
+
+ if let Some(message) = widget.on_middle_release.as_ref() {
+ if let Event::Mouse(mouse::Event::ButtonReleased(
+ mouse::Button::Middle,
+ )) = event
+ {
+ shell.publish(message.clone());
+
+ return event::Status::Captured;
+ }
+ }
+
+ event::Status::Ignored
+}