mod.rs 8.9 KB

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