From 9e453843b26f2f73228316334298a4c608b2f050 Mon Sep 17 00:00:00 2001
From: anunge <aymeric.nunge@gmail.com>
Date: Fri, 12 Feb 2021 21:52:20 +0200
Subject: Touch support for `PaneGrid` and `PickList` (#650)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* touch events properly parsed and converted to logical size, button working

* scrolling with a nice touch

* fixed application state level touch cursor. panel_grid is touchable now.

* format glicthes fixes

* format glitches

* tight format

* fixed pane grid

* fixing with upstream

* Remove unused `touch` module from `iced_core`

* Remove unused `crate::text` import in `iced_native`

* Remove redundant match branch in `iced_winit`

* Keep removed line break in `UserInterface::update`

* Compute `text_size` only when bounds contains cursor in `overlay::menu`

Co-authored-by: Héctor Ramón Jiménez <hector0193@gmail.com>
---
 native/src/overlay/menu.rs     |  26 +++++++-
 native/src/widget/pane_grid.rs | 131 ++++++++++++++++++++---------------------
 native/src/widget/pick_list.rs |   4 +-
 wgpu/src/text.rs               |   1 +
 4 files changed, 92 insertions(+), 70 deletions(-)

diff --git a/native/src/overlay/menu.rs b/native/src/overlay/menu.rs
index abac849f..5ad1391f 100644
--- a/native/src/overlay/menu.rs
+++ b/native/src/overlay/menu.rs
@@ -6,6 +6,7 @@ use crate::mouse;
 use crate::overlay;
 use crate::scrollable;
 use crate::text;
+use crate::touch;
 use crate::{
     Clipboard, Container, Element, Hasher, Layout, Length, Point, Rectangle,
     Scrollable, Size, Vector, Widget,
@@ -337,15 +338,36 @@ where
             }
             Event::Mouse(mouse::Event::CursorMoved { .. }) => {
                 let bounds = layout.bounds();
-                let text_size =
-                    self.text_size.unwrap_or(renderer.default_size());
 
                 if bounds.contains(cursor_position) {
+                    let text_size =
+                        self.text_size.unwrap_or(renderer.default_size());
+
+                    *self.hovered_option = Some(
+                        ((cursor_position.y - bounds.y)
+                            / f32::from(text_size + self.padding * 2))
+                            as usize,
+                    );
+                }
+            }
+            Event::Touch(touch::Event::FingerPressed { .. }) => {
+                let bounds = layout.bounds();
+
+                if bounds.contains(cursor_position) {
+                    let text_size =
+                        self.text_size.unwrap_or(renderer.default_size());
+
                     *self.hovered_option = Some(
                         ((cursor_position.y - bounds.y)
                             / f32::from(text_size + self.padding * 2))
                             as usize,
                     );
+
+                    if let Some(index) = *self.hovered_option {
+                        if let Some(option) = self.options.get(index) {
+                            *self.last_selection = Some(option.clone());
+                        }
+                    }
                 }
             }
             _ => {}
diff --git a/native/src/widget/pane_grid.rs b/native/src/widget/pane_grid.rs
index da3e25fd..c6fe4b60 100644
--- a/native/src/widget/pane_grid.rs
+++ b/native/src/widget/pane_grid.rs
@@ -33,6 +33,7 @@ use crate::layout;
 use crate::mouse;
 use crate::overlay;
 use crate::row;
+use crate::touch;
 use crate::{
     Clipboard, Element, Hasher, Layout, Length, Point, Rectangle, Size, Vector,
     Widget,
@@ -368,42 +369,34 @@ where
         let mut event_status = event::Status::Ignored;
 
         match event {
-            Event::Mouse(mouse_event) => match mouse_event {
-                mouse::Event::ButtonPressed(mouse::Button::Left) => {
-                    let bounds = layout.bounds();
-
-                    if bounds.contains(cursor_position) {
-                        event_status = event::Status::Captured;
-
-                        match self.on_resize {
-                            Some((leeway, _)) => {
-                                let relative_cursor = Point::new(
-                                    cursor_position.x - bounds.x,
-                                    cursor_position.y - bounds.y,
-                                );
-
-                                let splits = self.state.split_regions(
-                                    f32::from(self.spacing),
-                                    Size::new(bounds.width, bounds.height),
-                                );
-
-                                let clicked_split = hovered_split(
-                                    splits.iter(),
-                                    f32::from(self.spacing + leeway),
-                                    relative_cursor,
-                                );
+            Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))
+            | Event::Touch(touch::Event::FingerPressed { .. }) => {
+                let bounds = layout.bounds();
 
-                                if let Some((split, axis, _)) = clicked_split {
-                                    self.state.pick_split(&split, axis);
-                                } else {
-                                    self.click_pane(
-                                        layout,
-                                        cursor_position,
-                                        messages,
-                                    );
-                                }
-                            }
-                            None => {
+                if bounds.contains(cursor_position) {
+                    event_status = event::Status::Captured;
+
+                    match self.on_resize {
+                        Some((leeway, _)) => {
+                            let relative_cursor = Point::new(
+                                cursor_position.x - bounds.x,
+                                cursor_position.y - bounds.y,
+                            );
+
+                            let splits = self.state.split_regions(
+                                f32::from(self.spacing),
+                                Size::new(bounds.width, bounds.height),
+                            );
+
+                            let clicked_split = hovered_split(
+                                splits.iter(),
+                                f32::from(self.spacing + leeway),
+                                relative_cursor,
+                            );
+
+                            if let Some((split, axis, _)) = clicked_split {
+                                self.state.pick_split(&split, axis);
+                            } else {
                                 self.click_pane(
                                     layout,
                                     cursor_position,
@@ -411,47 +404,51 @@ where
                                 );
                             }
                         }
+                        None => {
+                            self.click_pane(layout, cursor_position, messages);
+                        }
                     }
                 }
-                mouse::Event::ButtonReleased(mouse::Button::Left) => {
-                    if let Some((pane, _)) = self.state.picked_pane() {
-                        if let Some(on_drag) = &self.on_drag {
-                            let mut dropped_region = self
-                                .elements
-                                .iter()
-                                .zip(layout.children())
-                                .filter(|(_, layout)| {
+            }
+            Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left))
+            | Event::Touch(touch::Event::FingerLifted { .. })
+            | Event::Touch(touch::Event::FingerLost { .. }) => {
+                if let Some((pane, _)) = self.state.picked_pane() {
+                    if let Some(on_drag) = &self.on_drag {
+                        let mut dropped_region =
+                            self.elements.iter().zip(layout.children()).filter(
+                                |(_, layout)| {
                                     layout.bounds().contains(cursor_position)
-                                });
-
-                            let event = match dropped_region.next() {
-                                Some(((target, _), _)) if pane != *target => {
-                                    DragEvent::Dropped {
-                                        pane,
-                                        target: *target,
-                                    }
+                                },
+                            );
+
+                        let event = match dropped_region.next() {
+                            Some(((target, _), _)) if pane != *target => {
+                                DragEvent::Dropped {
+                                    pane,
+                                    target: *target,
                                 }
-                                _ => DragEvent::Canceled { pane },
-                            };
+                            }
+                            _ => DragEvent::Canceled { pane },
+                        };
 
-                            messages.push(on_drag(event));
-                        }
+                        messages.push(on_drag(event));
+                    }
 
-                        self.state.idle();
+                    self.state.idle();
 
-                        event_status = event::Status::Captured;
-                    } else if self.state.picked_split().is_some() {
-                        self.state.idle();
+                    event_status = event::Status::Captured;
+                } else if self.state.picked_split().is_some() {
+                    self.state.idle();
 
-                        event_status = event::Status::Captured;
-                    }
-                }
-                mouse::Event::CursorMoved { .. } => {
-                    event_status =
-                        self.trigger_resize(layout, cursor_position, messages);
+                    event_status = event::Status::Captured;
                 }
-                _ => {}
-            },
+            }
+            Event::Mouse(mouse::Event::CursorMoved { .. })
+            | Event::Touch(touch::Event::FingerMoved { .. }) => {
+                event_status =
+                    self.trigger_resize(layout, cursor_position, messages);
+            }
             _ => {}
         }
 
diff --git a/native/src/widget/pick_list.rs b/native/src/widget/pick_list.rs
index 4110b9bb..74f4508e 100644
--- a/native/src/widget/pick_list.rs
+++ b/native/src/widget/pick_list.rs
@@ -6,6 +6,7 @@ use crate::overlay;
 use crate::overlay::menu::{self, Menu};
 use crate::scrollable;
 use crate::text;
+use crate::touch;
 use crate::{
     Clipboard, Element, Hasher, Layout, Length, Point, Rectangle, Size, Widget,
 };
@@ -214,7 +215,8 @@ where
         _clipboard: Option<&dyn Clipboard>,
     ) -> event::Status {
         match event {
-            Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {
+            Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))
+            | Event::Touch(touch::Event::FingerPressed { .. }) => {
                 let event_status = if *self.is_open {
                     // TODO: Encode cursor availability in the type system
                     *self.is_open =
diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs
index 78999cf8..4d92d9e9 100644
--- a/wgpu/src/text.rs
+++ b/wgpu/src/text.rs
@@ -19,6 +19,7 @@ impl Pipeline {
         let default_font = default_font.map(|slice| slice.to_vec());
 
         // TODO: Font customization
+        #[cfg(not(target_os = "ios"))]
         #[cfg(feature = "default_system_font")]
         let default_font = {
             default_font.or_else(|| {
-- 
cgit