From 9e453843b26f2f73228316334298a4c608b2f050 Mon Sep 17 00:00:00 2001 From: anunge Date: Fri, 12 Feb 2021 21:52:20 +0200 Subject: [PATCH] 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 --- native/src/overlay/menu.rs | 26 ++++++- native/src/widget/pane_grid.rs | 133 ++++++++++++++++----------------- native/src/widget/pick_list.rs | 4 +- wgpu/src/text.rs | 1 + 4 files changed, 93 insertions(+), 71 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,10 +338,11 @@ 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)) @@ -348,6 +350,26 @@ where ); } } + 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(); + Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) + | Event::Touch(touch::Event::FingerPressed { .. }) => { + let bounds = layout.bounds(); - if bounds.contains(cursor_position) { - event_status = event::Status::Captured; + 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, - ); + 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 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, - ); + 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, - messages, - ); - } - } - None => { + 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 ); } } - } - } - 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)| { - layout.bounds().contains(cursor_position) - }); - - let event = match dropped_region.next() { - Some(((target, _), _)) if pane != *target => { - DragEvent::Dropped { - pane, - target: *target, - } - } - _ => DragEvent::Canceled { pane }, - }; - - messages.push(on_drag(event)); + None => { + self.click_pane(layout, cursor_position, messages); } - - 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::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, + } + } + _ => DragEvent::Canceled { pane }, + }; + + messages.push(on_drag(event)); + } + + self.state.idle(); + + event_status = event::Status::Captured; + } else if self.state.picked_split().is_some() { + self.state.idle(); + + 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(|| {