mod.rs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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 futures::stream::{FuturesUnordered, StreamExt};
  20. use miniquad::{KeyCode, KeyMods, MouseButton, TouchPhase};
  21. use std::sync::{Arc, Weak};
  22. use crate::{
  23. gfx::{DrawCall, Point, Rectangle},
  24. prop::{BatchGuardPtr, ModifyAction, PropertyAtomicGuard, PropertyPtr, Role},
  25. scene::{Pimpl, SceneNode as SceneNode3, SceneNodePtr, SceneNodeWeak},
  26. util::i18n::I18nBabelFish,
  27. ExecutorPtr,
  28. };
  29. mod button;
  30. pub use button::{Button, ButtonPtr};
  31. pub mod chatview;
  32. pub use chatview::{ChatView, ChatViewPtr};
  33. mod edit;
  34. pub use edit::{BaseEdit, BaseEditPtr, BaseEditType};
  35. pub mod emoji_picker;
  36. pub use emoji_picker::{EmojiPicker, EmojiPickerPtr};
  37. mod gesture;
  38. pub use gesture::GesturePtr;
  39. mod image;
  40. #[allow(unused_imports)]
  41. pub use image::{Image, ImagePtr};
  42. mod video;
  43. pub use video::{Video, VideoPtr};
  44. mod vector_art;
  45. pub use vector_art::{
  46. shape::{ShapeVertex, VectorShape},
  47. VectorArt, VectorArtPtr,
  48. };
  49. mod layer;
  50. pub use layer::{Layer, LayerPtr};
  51. mod shortcut;
  52. pub use shortcut::{Shortcut, ShortcutPtr};
  53. mod text;
  54. pub use text::{Text, TextPtr};
  55. mod win;
  56. pub use win::{Window, WindowPtr};
  57. macro_rules! e { ($($arg:tt)*) => { error!(target: "scene::on_modify", $($arg)*); } }
  58. macro_rules! t { ($($arg:tt)*) => { trace!(target: "scene::on_modify", $($arg)*); } }
  59. type DrawTrace = u32;
  60. #[async_trait]
  61. pub trait UIObject: Sync {
  62. fn priority(&self) -> u32;
  63. fn init(&self) {}
  64. async fn start(self: Arc<Self>, _ex: ExecutorPtr) {}
  65. /// Clear all buffers and caches
  66. fn stop(&self) {}
  67. async fn draw(
  68. &self,
  69. _parent_rect: Rectangle,
  70. _trace: DrawTrace,
  71. _atom: &mut PropertyAtomicGuard,
  72. ) -> Option<DrawUpdate> {
  73. None
  74. }
  75. async fn handle_char(&self, _key: char, _mods: KeyMods, _repeat: bool) -> bool {
  76. false
  77. }
  78. async fn handle_key_down(&self, _key: KeyCode, _mods: KeyMods, _repeat: bool) -> bool {
  79. false
  80. }
  81. async fn handle_key_up(&self, _key: KeyCode, _mods: KeyMods) -> bool {
  82. false
  83. }
  84. async fn handle_mouse_btn_down(&self, _btn: MouseButton, _mouse_pos: Point) -> bool {
  85. false
  86. }
  87. async fn handle_mouse_btn_up(&self, _btn: MouseButton, _mouse_pos: Point) -> bool {
  88. false
  89. }
  90. async fn handle_mouse_move(&self, _mouse_pos: Point) -> bool {
  91. false
  92. }
  93. async fn handle_mouse_wheel(&self, _wheel_pos: Point) -> bool {
  94. false
  95. }
  96. async fn handle_touch(&self, _phase: TouchPhase, _id: u64, _touch_pos: Point) -> bool {
  97. false
  98. }
  99. fn set_i18n(&self, _i18n_fish: &I18nBabelFish) {}
  100. }
  101. pub struct DrawUpdate {
  102. pub key: u64,
  103. pub draw_calls: Vec<(u64, DrawCall)>,
  104. }
  105. pub struct OnModify<T> {
  106. ex: ExecutorPtr,
  107. #[allow(dead_code)]
  108. node: SceneNodeWeak,
  109. me: Weak<T>,
  110. pub tasks: Vec<smol::Task<()>>,
  111. }
  112. impl<T: Send + Sync + 'static> OnModify<T> {
  113. pub fn new(ex: ExecutorPtr, node: SceneNodeWeak, me: Weak<T>) -> Self {
  114. Self { ex, node, me, tasks: vec![] }
  115. }
  116. pub fn when_change<F>(
  117. &mut self,
  118. prop: PropertyPtr,
  119. f: impl Fn(Arc<T>, BatchGuardPtr) -> F + Send + 'static,
  120. ) where
  121. F: std::future::Future<Output = ()> + Send + 'static,
  122. {
  123. let mut on_modify_subs = vec![(Arc::downgrade(&prop), None, prop.subscribe_modify())];
  124. for dep in prop.get_depends() {
  125. let Some(dep_prop) = dep.prop.upgrade() else { continue };
  126. on_modify_subs.push((dep.prop, Some(dep.i), dep_prop.subscribe_modify()));
  127. }
  128. let me = self.me.clone();
  129. let task = self.ex.spawn(async move {
  130. loop {
  131. let mut poll_queues = FuturesUnordered::new();
  132. for (i, (prop_weak, prop_i, on_modify_sub)) in on_modify_subs.iter().enumerate() {
  133. let recv = on_modify_sub.receive();
  134. poll_queues.push(async move {
  135. let (role, action, batch_guard) = recv.await.ok()?;
  136. Some((i, prop_weak, prop_i, role, action, batch_guard))
  137. });
  138. }
  139. let Some(Some((idx, prop_weak, prop_i, role, action, batch_guard))) = poll_queues.next().await else {
  140. e!("Property {:?} on_modify pipe is broken", prop);
  141. return
  142. };
  143. // Skip internal messages from ourselves or explicitly marked ignored
  144. if (idx == 0 && role == Role::Internal) || role == Role::Ignored {
  145. continue
  146. }
  147. if let Some(prop_i) = prop_i {
  148. match action {
  149. ModifyAction::Set(i) => if *prop_i != i { continue },
  150. ModifyAction::SetCache(idxs) => if !idxs.contains(prop_i) { continue }
  151. _ => continue
  152. }
  153. }
  154. if idx == 0 {
  155. t!("Property {:?} modified [depend_idx={idx}, role={role:?}]", prop);
  156. } else {
  157. t!(
  158. "Property {:?} modified -> triggering {:?} [depend_idx={idx}, role={role:?}]",
  159. prop_weak.upgrade().unwrap(),
  160. prop
  161. );
  162. }
  163. let Some(self_) = me.upgrade() else {
  164. // Should not happen
  165. panic!("{:?} self destroyed before modify_task was stopped!", prop);
  166. };
  167. //debug!(target: "app", "property modified");
  168. f(self_, batch_guard).await;
  169. }
  170. });
  171. self.tasks.push(task);
  172. }
  173. }
  174. pub fn get_ui_object_ptr(node: &SceneNode3) -> Arc<dyn UIObject + Send> {
  175. match node.pimpl() {
  176. Pimpl::Layer(obj) => obj.clone(),
  177. Pimpl::VectorArt(obj) => obj.clone(),
  178. Pimpl::Text(obj) => obj.clone(),
  179. Pimpl::Edit(obj) => obj.clone(),
  180. Pimpl::ChatView(obj) => obj.clone(),
  181. Pimpl::Image(obj) => obj.clone(),
  182. Pimpl::Video(obj) => obj.clone(),
  183. Pimpl::Button(obj) => obj.clone(),
  184. Pimpl::EmojiPicker(obj) => obj.clone(),
  185. Pimpl::Shortcut(obj) => obj.clone(),
  186. Pimpl::Gesture(obj) => obj.clone(),
  187. _ => panic!("unhandled type for get_ui_object: {node:?}"),
  188. }
  189. }
  190. pub fn get_ui_object3<'a>(node: &'a SceneNode3) -> &'a dyn UIObject {
  191. match node.pimpl() {
  192. Pimpl::Layer(obj) => obj.as_ref(),
  193. Pimpl::VectorArt(obj) => obj.as_ref(),
  194. Pimpl::Text(obj) => obj.as_ref(),
  195. Pimpl::Edit(obj) => obj.as_ref(),
  196. Pimpl::ChatView(obj) => obj.as_ref(),
  197. Pimpl::Image(obj) => obj.as_ref(),
  198. Pimpl::Video(obj) => obj.as_ref(),
  199. Pimpl::Button(obj) => obj.as_ref(),
  200. Pimpl::EmojiPicker(obj) => obj.as_ref(),
  201. Pimpl::Shortcut(obj) => obj.as_ref(),
  202. Pimpl::Gesture(obj) => obj.as_ref(),
  203. _ => panic!("unhandled type for get_ui_object: {node:?}"),
  204. }
  205. }
  206. pub fn get_children_ordered(node: &SceneNode3) -> Vec<SceneNodePtr> {
  207. let mut child_infs = vec![];
  208. for child in node.get_children() {
  209. let obj = get_ui_object3(&child);
  210. let priority = obj.priority();
  211. child_infs.push((child, priority));
  212. }
  213. child_infs.sort_unstable_by_key(|(_, priority)| *priority);
  214. let nodes = child_infs.into_iter().rev().map(|(node, _)| node).collect();
  215. nodes
  216. }