gesture.rs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2025 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use async_trait::async_trait;
  19. use darkfi_serial::serialize;
  20. use miniquad::TouchPhase;
  21. use std::sync::{Arc, Mutex as SyncMutex};
  22. use crate::{
  23. gfx::Point,
  24. prop::{
  25. PropertyBool, PropertyColor, PropertyFloat32, PropertyPtr, PropertyRect, PropertyStr,
  26. PropertyUint32, Role,
  27. },
  28. scene::{Pimpl, SceneNodePtr, SceneNodeWeak},
  29. };
  30. use super::UIObject;
  31. macro_rules! d { ($($arg:tt)*) => { debug!(target: "ui::gesture", $($arg)*); } }
  32. macro_rules! t { ($($arg:tt)*) => { trace!(target: "ui::gesture", $($arg)*); } }
  33. /// Maximum number of simultaneous touch events.
  34. /// Put 3 here because any more is ridiculous.
  35. const MAX_TOUCH: usize = 3;
  36. #[derive(Clone)]
  37. struct GestureState {
  38. start: [Option<Point>; MAX_TOUCH],
  39. curr: [Option<Point>; MAX_TOUCH],
  40. }
  41. pub type GesturePtr = Arc<Gesture>;
  42. pub struct Gesture {
  43. node: SceneNodeWeak,
  44. priority: PropertyUint32,
  45. state: SyncMutex<GestureState>,
  46. }
  47. impl Gesture {
  48. pub async fn new(node: SceneNodeWeak) -> Pimpl {
  49. t!("Gesture::new()");
  50. let node_ref = &node.upgrade().unwrap();
  51. let priority = PropertyUint32::wrap(node_ref, Role::Internal, "priority", 0).unwrap();
  52. let state = GestureState { start: [None; MAX_TOUCH], curr: [None; MAX_TOUCH] };
  53. let self_ = Arc::new(Self { node, priority, state: SyncMutex::new(state) });
  54. Pimpl::Gesture(self_)
  55. }
  56. fn handle_update(&self, state: GestureState) -> Option<f32> {
  57. let Some(start_1) = state.start[0] else { return None };
  58. let curr_1 = state.curr[0].unwrap();
  59. let Some(start_2) = state.start[1] else { return None };
  60. let curr_2 = state.curr[1].unwrap();
  61. let start_dist_sq = start_1.dist_sq(start_2);
  62. let curr_dist_sq = curr_1.dist_sq(curr_2);
  63. let r = (curr_dist_sq / start_dist_sq).sqrt();
  64. Some(r)
  65. }
  66. }
  67. #[async_trait]
  68. impl UIObject for Gesture {
  69. fn priority(&self) -> u32 {
  70. self.priority.get()
  71. }
  72. async fn handle_touch(&self, phase: TouchPhase, id: u64, touch_pos: Point) -> bool {
  73. //t!("handle_touch({phase:?}, {id}, {touch_pos:?})");
  74. let id = id as usize;
  75. if id >= MAX_TOUCH {
  76. return false
  77. }
  78. match phase {
  79. TouchPhase::Started => {
  80. let mut state = self.state.lock().unwrap();
  81. state.start[id] = Some(touch_pos);
  82. state.curr[id] = Some(touch_pos);
  83. false
  84. }
  85. TouchPhase::Moved => {
  86. let state = {
  87. let mut state = self.state.lock().unwrap();
  88. state.curr[id] = Some(touch_pos);
  89. state.clone()
  90. };
  91. if let Some(update) = self.handle_update(state) {
  92. let node = self.node.upgrade().unwrap();
  93. d!("Gesture invoked: {update}");
  94. node.trigger("gesture", serialize(&update)).await.unwrap();
  95. }
  96. false
  97. }
  98. TouchPhase::Ended | TouchPhase::Cancelled => {
  99. let mut state = self.state.lock().unwrap();
  100. state.start = [None; MAX_TOUCH];
  101. state.curr = [None; MAX_TOUCH];
  102. false
  103. }
  104. }
  105. }
  106. }