editbox.rs 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2024 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 atomic_float::AtomicF32;
  20. use darkfi::system::msleep;
  21. use miniquad::{window, KeyCode, KeyMods, MouseButton, TouchPhase};
  22. use rand::{rngs::OsRng, Rng};
  23. use std::{
  24. collections::HashMap,
  25. sync::{
  26. atomic::{AtomicBool, Ordering},
  27. Arc, Mutex as SyncMutex, Weak,
  28. },
  29. time::Instant,
  30. };
  31. use crate::{
  32. error::Result,
  33. gfx::{
  34. GfxDrawCall, GfxDrawInstruction, GfxDrawMesh, GfxTextureId, GraphicsEventPublisherPtr,
  35. Point, Rectangle, RenderApiPtr,
  36. },
  37. mesh::{MeshBuilder, MeshInfo, COLOR_BLUE, COLOR_WHITE},
  38. prop::{
  39. PropertyBool, PropertyColor, PropertyFloat32, PropertyPtr, PropertyRect, PropertyStr,
  40. PropertyUint32, Role,
  41. },
  42. pubsub::Subscription,
  43. scene::{Pimpl, SceneNodePtr, SceneNodeWeak},
  44. text::{self, Glyph, GlyphPositionIter, TextShaperPtr},
  45. ui::FreedData,
  46. util::is_whitespace,
  47. ExecutorPtr,
  48. };
  49. use super::{DrawUpdate, OnModify, UIObject};
  50. // EOL whitespace is given a nudge since it has a width of 0 after text shaping
  51. const CURSOR_EOL_WS_NUDGE: f32 = 0.8;
  52. // EOL chars are more aesthetic when given a smallish nudge
  53. const CURSOR_EOL_NUDGE: f32 = 0.2;
  54. fn eol_nudge(font_size: f32, glyphs: &Vec<Glyph>) -> f32 {
  55. if is_whitespace(&glyphs.last().unwrap().substr) {
  56. (font_size * CURSOR_EOL_WS_NUDGE).round()
  57. } else {
  58. (font_size * CURSOR_EOL_NUDGE).round()
  59. }
  60. }
  61. #[derive(Debug, Clone, Eq, Hash, PartialEq)]
  62. enum PressedKey {
  63. Char(char),
  64. Key(KeyCode),
  65. }
  66. /// On key press (repeat=false), we immediately process the event.
  67. /// Then there's a delay (repeat=true) and then for every step time
  68. /// while key press events are being sent, we allow an event.
  69. /// This ensures smooth typing in the editbox.
  70. struct PressedKeysSmoothRepeat {
  71. /// When holding keys, we track from start and last sent time.
  72. /// This is useful for initial delay and smooth scrolling.
  73. pressed_keys: HashMap<PressedKey, RepeatingKeyTimer>,
  74. /// Initial delay before allowing keys
  75. start_delay: u32,
  76. /// Minimum time between repeated keys
  77. step_time: u32,
  78. }
  79. impl PressedKeysSmoothRepeat {
  80. fn new(start_delay: u32, step_time: u32) -> Self {
  81. Self { pressed_keys: HashMap::new(), start_delay, step_time }
  82. }
  83. fn key_down(&mut self, key: PressedKey, repeat: bool) -> u32 {
  84. //debug!(target: "PressedKeysSmoothRepeat", "key_down({:?}, {})", key, repeat);
  85. if !repeat {
  86. self.pressed_keys.remove(&key);
  87. return 1;
  88. }
  89. // Insert key if not exists
  90. if !self.pressed_keys.contains_key(&key) {
  91. //debug!(target: "PressedKeysSmoothRepeat", "insert key {:?}", key);
  92. self.pressed_keys.insert(key.clone(), RepeatingKeyTimer::new());
  93. }
  94. let repeater = self.pressed_keys.get_mut(&key).expect("repeat map");
  95. repeater.update(self.start_delay, self.step_time)
  96. }
  97. /*
  98. fn key_up(&mut self, key: &PressedKey) {
  99. //debug!(target: "PressedKeysSmoothRepeat", "key_up({:?})", key);
  100. assert!(self.pressed_keys.contains_key(key));
  101. self.pressed_keys.remove(key).expect("key was pressed");
  102. }
  103. */
  104. }
  105. struct RepeatingKeyTimer {
  106. start: Instant,
  107. actions: u32,
  108. }
  109. impl RepeatingKeyTimer {
  110. fn new() -> Self {
  111. Self { start: Instant::now(), actions: 0 }
  112. }
  113. fn update(&mut self, start_delay: u32, step_time: u32) -> u32 {
  114. let elapsed = self.start.elapsed().as_millis();
  115. //debug!(target: "RepeatingKeyTimer", "update() elapsed={}, actions={}",
  116. // elapsed, self.actions);
  117. if elapsed < start_delay as u128 {
  118. return 0
  119. }
  120. let total_actions = ((elapsed - start_delay as u128) / step_time as u128) as u32;
  121. let remaining_actions = total_actions - self.actions;
  122. self.actions = total_actions;
  123. remaining_actions
  124. }
  125. }
  126. pub type EditBoxPtr = Arc<EditBox>;
  127. pub struct EditBox {
  128. node: SceneNodeWeak,
  129. #[allow(dead_code)]
  130. tasks: Vec<smol::Task<()>>,
  131. render_api: RenderApiPtr,
  132. text_shaper: TextShaperPtr,
  133. key_repeat: SyncMutex<PressedKeysSmoothRepeat>,
  134. text_mesh: SyncMutex<Option<GfxDrawMesh>>,
  135. glyphs: SyncMutex<Vec<Glyph>>,
  136. /// DC key for the text
  137. text_dc_key: u64,
  138. cursor_mesh: SyncMutex<Option<GfxDrawMesh>>,
  139. /// DC key for the cursor. Allows updating cursor independently.
  140. cursor_dc_key: u64,
  141. freed: SyncMutex<FreedData>,
  142. is_active: PropertyBool,
  143. is_focused: PropertyBool,
  144. rect: PropertyRect,
  145. baseline: PropertyFloat32,
  146. scroll: PropertyFloat32,
  147. cursor_pos: PropertyUint32,
  148. font_size: PropertyFloat32,
  149. text: PropertyStr,
  150. text_color: PropertyColor,
  151. cursor_color: PropertyColor,
  152. cursor_width: PropertyFloat32,
  153. cursor_ascent: PropertyFloat32,
  154. cursor_descent: PropertyFloat32,
  155. hi_bg_color: PropertyColor,
  156. selected: PropertyPtr,
  157. z_index: PropertyUint32,
  158. debug: PropertyBool,
  159. mouse_btn_held: AtomicBool,
  160. cursor_is_visible: AtomicBool,
  161. blink_is_paused: AtomicBool,
  162. old_window_scale: AtomicF32,
  163. window_scale: PropertyFloat32,
  164. parent_rect: SyncMutex<Option<Rectangle>>,
  165. }
  166. impl EditBox {
  167. pub async fn new(
  168. node: SceneNodeWeak,
  169. window_scale: PropertyFloat32,
  170. render_api: RenderApiPtr,
  171. text_shaper: TextShaperPtr,
  172. ex: ExecutorPtr,
  173. ) -> Pimpl {
  174. debug!(target: "ui::editbox", "EditBox::new()");
  175. let node_ref = &node.upgrade().unwrap();
  176. let is_active = PropertyBool::wrap(node_ref, Role::Internal, "is_active", 0).unwrap();
  177. let is_focused = PropertyBool::wrap(node_ref, Role::Internal, "is_focused", 0).unwrap();
  178. let rect = PropertyRect::wrap(node_ref, Role::Internal, "rect").unwrap();
  179. let baseline = PropertyFloat32::wrap(node_ref, Role::Internal, "baseline", 0).unwrap();
  180. let scroll = PropertyFloat32::wrap(node_ref, Role::Internal, "scroll", 0).unwrap();
  181. let cursor_pos = PropertyUint32::wrap(node_ref, Role::Internal, "cursor_pos", 0).unwrap();
  182. let font_size = PropertyFloat32::wrap(node_ref, Role::Internal, "font_size", 0).unwrap();
  183. let text = PropertyStr::wrap(node_ref, Role::Internal, "text", 0).unwrap();
  184. let text_color = PropertyColor::wrap(node_ref, Role::Internal, "text_color").unwrap();
  185. let cursor_color = PropertyColor::wrap(node_ref, Role::Internal, "cursor_color").unwrap();
  186. let cursor_width =
  187. PropertyFloat32::wrap(node_ref, Role::Internal, "cursor_width", 0).unwrap();
  188. let cursor_ascent =
  189. PropertyFloat32::wrap(node_ref, Role::Internal, "cursor_ascent", 0).unwrap();
  190. let cursor_descent =
  191. PropertyFloat32::wrap(node_ref, Role::Internal, "cursor_descent", 0).unwrap();
  192. let hi_bg_color = PropertyColor::wrap(node_ref, Role::Internal, "hi_bg_color").unwrap();
  193. let selected = node_ref.get_property("selected").unwrap();
  194. let cursor_blink_time =
  195. PropertyUint32::wrap(node_ref, Role::Internal, "cursor_blink_time", 0).unwrap();
  196. let cursor_idle_time =
  197. PropertyUint32::wrap(node_ref, Role::Internal, "cursor_idle_time", 0).unwrap();
  198. let z_index = PropertyUint32::wrap(node_ref, Role::Internal, "z_index", 0).unwrap();
  199. let debug = PropertyBool::wrap(node_ref, Role::Internal, "debug", 0).unwrap();
  200. let node_name = node_ref.name.clone();
  201. let node_id = node_ref.id;
  202. // Must do this whenever the text changes
  203. let glyphs = text_shaper.shape(text.get(), font_size.get(), window_scale.get()).await;
  204. let self_ = Arc::new_cyclic(|me: &Weak<Self>| {
  205. let mut on_modify = OnModify::new(ex.clone(), node_name, node_id, me.clone());
  206. on_modify.when_change(is_focused.prop(), Self::change_focus);
  207. // When text has been changed.
  208. // Cursor and selection might be invalidated.
  209. async fn reset(self_: Arc<EditBox>) {
  210. self_.cursor_pos.set(0);
  211. self_.selected.set_null(Role::Internal, 0).unwrap();
  212. self_.selected.set_null(Role::Internal, 1).unwrap();
  213. self_.scroll.set(0.);
  214. self_.regen_glyphs().await;
  215. self_.redraw().await;
  216. }
  217. async fn redraw(self_: Arc<EditBox>) {
  218. self_.redraw().await;
  219. }
  220. on_modify.when_change(rect.prop(), redraw);
  221. on_modify.when_change(baseline.prop(), redraw);
  222. // The commented properties are modified on input events
  223. // So then redraw() will get repeatedly triggered when these properties
  224. // are changed. We should find a solution. For now the hooks are disabled.
  225. //on_modify.when_change(scroll.prop(), redraw);
  226. //on_modify.when_change(cursor_pos.prop(), redraw);
  227. on_modify.when_change(font_size.prop(), redraw);
  228. // We must also reshape text
  229. on_modify.when_change(text.prop(), reset);
  230. on_modify.when_change(text_color.prop(), redraw);
  231. on_modify.when_change(hi_bg_color.prop(), redraw);
  232. //on_modify.when_change(selected.clone(), redraw);
  233. on_modify.when_change(z_index.prop(), redraw);
  234. on_modify.when_change(debug.prop(), redraw);
  235. async fn regen_cursor(self_: Arc<EditBox>) {
  236. let mesh = std::mem::take(&mut *self_.cursor_mesh.lock().unwrap());
  237. let mut freed = self_.freed.lock().unwrap();
  238. if let Some(mesh) = mesh {
  239. freed.add_mesh(mesh);
  240. }
  241. }
  242. on_modify.when_change(cursor_color.prop(), regen_cursor);
  243. on_modify.when_change(cursor_ascent.prop(), regen_cursor);
  244. on_modify.when_change(cursor_descent.prop(), regen_cursor);
  245. on_modify.when_change(cursor_width.prop(), regen_cursor);
  246. let me2 = me.clone();
  247. let blinking_cursor_task = ex.spawn(async move {
  248. loop {
  249. msleep(cursor_blink_time.get() as u64).await;
  250. let self_ = me2.upgrade().unwrap();
  251. if self_.blink_is_paused.swap(false, Ordering::Relaxed) {
  252. msleep(cursor_idle_time.get() as u64).await;
  253. continue
  254. }
  255. // Invert the bool
  256. self_.cursor_is_visible.fetch_not(Ordering::Relaxed);
  257. self_.redraw_cursor().await;
  258. }
  259. });
  260. let mut tasks = on_modify.tasks;
  261. tasks.push(blinking_cursor_task);
  262. Self {
  263. node,
  264. tasks,
  265. render_api,
  266. text_shaper,
  267. key_repeat: SyncMutex::new(PressedKeysSmoothRepeat::new(400, 50)),
  268. text_mesh: SyncMutex::new(None),
  269. glyphs: SyncMutex::new(glyphs),
  270. text_dc_key: OsRng.gen(),
  271. cursor_mesh: SyncMutex::new(None),
  272. cursor_dc_key: OsRng.gen(),
  273. freed: SyncMutex::new(Default::default()),
  274. is_active,
  275. is_focused,
  276. rect,
  277. baseline,
  278. scroll,
  279. cursor_pos,
  280. font_size,
  281. text,
  282. text_color,
  283. cursor_color,
  284. cursor_width,
  285. cursor_ascent,
  286. cursor_descent,
  287. hi_bg_color,
  288. selected,
  289. z_index,
  290. debug,
  291. mouse_btn_held: AtomicBool::new(false),
  292. cursor_is_visible: AtomicBool::new(true),
  293. blink_is_paused: AtomicBool::new(false),
  294. old_window_scale: AtomicF32::new(window_scale.get()),
  295. window_scale,
  296. parent_rect: SyncMutex::new(None),
  297. }
  298. });
  299. Pimpl::EditBox(self_)
  300. }
  301. fn node(&self) -> SceneNodePtr {
  302. self.node.upgrade().unwrap()
  303. }
  304. /// This MUST be called whenever the text property is changed.
  305. async fn regen_glyphs(&self) {
  306. let font_size = self.font_size.get();
  307. let window_scale = self.window_scale.get();
  308. let glyphs = self.text_shaper.shape(self.text.get(), font_size, window_scale).await;
  309. // TODO: we aren't freeing textures
  310. *self.glyphs.lock().unwrap() = glyphs;
  311. }
  312. /// Called whenever the text or any text property changes.
  313. fn regen_text_mesh(&self, mut clip: Rectangle) -> GfxDrawMesh {
  314. clip.x = 0.;
  315. clip.y = 0.;
  316. let is_focused = self.is_focused.get();
  317. let text = self.text.get();
  318. let font_size = self.font_size.get();
  319. let window_scale = self.window_scale.get();
  320. let text_color = self.text_color.get();
  321. let baseline = self.baseline.get();
  322. let scroll = self.scroll.get();
  323. let cursor_pos = self.cursor_pos.get() as usize;
  324. let cursor_color = self.cursor_color.get();
  325. let debug = self.debug.get();
  326. debug!(target: "ui::editbox", "Rendering text '{text}' clip={clip:?}");
  327. debug!(target: "ui::editbox", " cursor_pos={cursor_pos}, is_focused={is_focused}");
  328. let glyphs = self.glyphs.lock().unwrap().clone();
  329. let atlas = text::make_texture_atlas(&self.render_api, &glyphs);
  330. let mut mesh = MeshBuilder::with_clip(clip.clone());
  331. self.draw_selected(&mut mesh, &glyphs, clip.h).unwrap();
  332. let glyph_pos_iter = GlyphPositionIter::new(font_size, window_scale, &glyphs, baseline);
  333. for (glyph_idx, (mut glyph_rect, glyph)) in glyph_pos_iter.zip(glyphs.iter()).enumerate() {
  334. let uv_rect = atlas.fetch_uv(glyph.glyph_id).expect("missing glyph UV rect");
  335. glyph_rect.x -= scroll;
  336. //mesh.draw_outline(&glyph_rect, COLOR_BLUE, 2.);
  337. let mut color = text_color.clone();
  338. if glyph.sprite.has_color {
  339. color = COLOR_WHITE;
  340. }
  341. mesh.draw_box(&glyph_rect, color, uv_rect);
  342. }
  343. if debug {
  344. mesh.draw_outline(&clip, COLOR_BLUE, 1.);
  345. }
  346. mesh.alloc(&self.render_api).draw_with_texture(atlas.texture_id)
  347. }
  348. fn regen_cursor_mesh(&self) -> GfxDrawMesh {
  349. let cursor_width = self.cursor_width.get();
  350. let cursor_ascent = self.cursor_ascent.get();
  351. let cursor_descent = self.cursor_descent.get();
  352. let baseline = self.baseline.get();
  353. let rect_h = self.rect.get().h;
  354. let cursor_rect = Rectangle {
  355. x: 0.,
  356. y: baseline - cursor_ascent,
  357. w: cursor_width,
  358. h: cursor_ascent + cursor_descent,
  359. };
  360. let cursor_color = self.cursor_color.get();
  361. let mut mesh = MeshBuilder::new();
  362. mesh.draw_filled_box(&cursor_rect, cursor_color);
  363. mesh.alloc(&self.render_api).draw_untextured()
  364. }
  365. fn cursor_px_offset(&self) -> f32 {
  366. assert!(self.is_focused.get());
  367. let font_size = self.font_size.get();
  368. let window_scale = self.window_scale.get();
  369. let baseline = self.baseline.get();
  370. let scroll = self.scroll.get();
  371. let cursor_pos = self.cursor_pos.get() as usize;
  372. let glyphs = self.glyphs.lock().unwrap().clone();
  373. let glyph_pos_iter = GlyphPositionIter::new(font_size, window_scale, &glyphs, baseline);
  374. // Used for drawing the cursor when it's at the end of the line.
  375. let mut rhs = 0.;
  376. if cursor_pos == 0 {
  377. return 0.;
  378. }
  379. for (glyph_idx, (mut glyph_rect, glyph)) in glyph_pos_iter.zip(glyphs.iter()).enumerate() {
  380. glyph_rect.x -= scroll;
  381. if cursor_pos == glyph_idx {
  382. return glyph_rect.x;
  383. }
  384. rhs = glyph_rect.rhs();
  385. }
  386. assert!(cursor_pos == glyphs.len());
  387. rhs += eol_nudge(font_size, &glyphs);
  388. rhs
  389. }
  390. fn draw_selected(
  391. &self,
  392. mesh: &mut MeshBuilder,
  393. glyphs: &Vec<Glyph>,
  394. clip_h: f32,
  395. ) -> Result<()> {
  396. if self.selected.is_null(0)? || self.selected.is_null(1)? {
  397. // Nothing selected so do nothing
  398. return Ok(())
  399. }
  400. let start = self.selected.get_u32(0)? as usize;
  401. let end = self.selected.get_u32(1)? as usize;
  402. // Selection started but nothing selected yet so do nothing
  403. if start == end {
  404. return Ok(())
  405. }
  406. let sel_start = std::cmp::min(start, end);
  407. let sel_end = std::cmp::max(start, end);
  408. let font_size = self.font_size.get();
  409. let window_scale = self.window_scale.get();
  410. let baseline = self.baseline.get();
  411. let scroll = self.scroll.get();
  412. let hi_bg_color = self.hi_bg_color.get();
  413. let glyph_pos_iter = GlyphPositionIter::new(font_size, window_scale, &glyphs, baseline);
  414. let mut start_x = 0.;
  415. let mut end_x = 0.;
  416. // When cursor lands at the end of the line
  417. let mut rhs = 0.;
  418. for (glyph_idx, mut glyph_rect) in glyph_pos_iter.enumerate() {
  419. glyph_rect.x -= scroll;
  420. if glyph_idx == sel_start {
  421. start_x = glyph_rect.x;
  422. }
  423. if glyph_idx == sel_end {
  424. end_x = glyph_rect.x;
  425. }
  426. rhs = glyph_rect.rhs();
  427. }
  428. if sel_start == 0 {
  429. start_x = scroll;
  430. }
  431. if sel_end == glyphs.len() {
  432. rhs += eol_nudge(font_size, &glyphs);
  433. end_x = rhs;
  434. }
  435. // We don't need to do manual clipping since MeshBuilder should do that
  436. let select_rect = Rectangle { x: start_x, y: 0., w: end_x - start_x, h: clip_h };
  437. mesh.draw_box(&select_rect, hi_bg_color, &Rectangle::zero());
  438. Ok(())
  439. }
  440. async fn change_focus(self: Arc<Self>) {
  441. if !self.is_active.get() {
  442. return
  443. }
  444. debug!(target: "ui::editbox", "Focus changed");
  445. // Cursor visibility will change so just redraw everything lol
  446. self.redraw().await;
  447. }
  448. async fn handle_click_down(&self, btn: MouseButton, mouse_pos: Point) -> bool {
  449. if btn != MouseButton::Left {
  450. return false
  451. }
  452. let rect = self.rect.get();
  453. // clicking inside box will:
  454. // 1. make it active
  455. // 2. begin selection
  456. if !rect.contains(mouse_pos) {
  457. /*
  458. if self.is_focused.get() {
  459. debug!(target: "ui::editbox", "EditBox unfocused");
  460. self.is_focused.set(false);
  461. self.selected.set_null(Role::Internal, 0).unwrap();
  462. self.selected.set_null(Role::Internal, 1).unwrap();
  463. self.redraw().await;
  464. }
  465. */
  466. return false
  467. }
  468. window::show_keyboard(true);
  469. if self.is_focused.get() {
  470. debug!(target: "ui::editbox", "EditBox clicked");
  471. } else {
  472. debug!(target: "ui::editbox", "EditBox focused");
  473. self.is_focused.set(true);
  474. }
  475. let cpos = self.find_closest_glyph_idx(mouse_pos.x, &rect);
  476. // set cursor pos
  477. self.cursor_pos.set(cpos);
  478. self.apply_cursor_scrolling();
  479. // begin selection
  480. self.selected.set_u32(Role::Internal, 0, cpos).unwrap();
  481. self.selected.set_u32(Role::Internal, 1, cpos).unwrap();
  482. self.mouse_btn_held.store(true, Ordering::Relaxed);
  483. self.redraw().await;
  484. true
  485. }
  486. fn handle_click_up(&self, btn: MouseButton, pos: Point) -> bool {
  487. if btn != MouseButton::Left {
  488. return false
  489. }
  490. // releasing mouse button will end selection
  491. self.mouse_btn_held.store(false, Ordering::Relaxed);
  492. false
  493. }
  494. async fn handle_cursor_move(&self, pos: Point) -> bool {
  495. if !self.mouse_btn_held.load(Ordering::Relaxed) {
  496. return false;
  497. }
  498. // if active and selection_active, then use x to modify the selection.
  499. // also implement scrolling when cursor is to the left or right
  500. // just scroll to the end
  501. // also set cursor_pos too
  502. let rect = self.rect.get();
  503. let cpos = self.find_closest_glyph_idx(pos.x, &rect);
  504. self.cursor_pos.set(cpos);
  505. self.selected.set_u32(Role::Internal, 1, cpos).unwrap();
  506. self.apply_cursor_scrolling();
  507. self.redraw().await;
  508. false
  509. }
  510. /// Used when clicking the text. Given the x coord of the mouse, it finds the index
  511. /// of the closest glyph to that x coord.
  512. fn find_closest_glyph_idx(&self, x: f32, rect: &Rectangle) -> u32 {
  513. let font_size = self.font_size.get();
  514. let window_scale = self.window_scale.get();
  515. let baseline = self.baseline.get();
  516. let glyphs = self.glyphs.lock().unwrap().clone();
  517. let mouse_x = x - rect.x;
  518. if mouse_x > rect.w {
  519. // Highlight to the end
  520. let cpos = glyphs.len() as u32;
  521. return cpos;
  522. // Scroll to the right handled in render
  523. } else if mouse_x < 0. {
  524. return 0;
  525. }
  526. let scroll = self.scroll.get();
  527. let mut cpos = 0;
  528. let lhs = 0.;
  529. let mut last_d = (lhs - mouse_x).abs();
  530. let glyph_pos_iter = GlyphPositionIter::new(font_size, window_scale, &glyphs, baseline);
  531. let mut rhs = 0.;
  532. for (i, glyph_rect) in glyph_pos_iter.skip(1).enumerate() {
  533. // Because we skip the first item
  534. let glyph_idx = (i + 1) as u32;
  535. let x1 = glyph_rect.x - scroll;
  536. // I don't know what this is doing but it works so I won't touch it for now.
  537. let curr_d = (x1 - mouse_x).abs();
  538. if curr_d < last_d {
  539. last_d = curr_d;
  540. cpos = glyph_idx;
  541. }
  542. rhs = glyph_rect.rhs();
  543. }
  544. // also check the right hand side
  545. let curr_d = (rhs - mouse_x).abs();
  546. if curr_d < last_d {
  547. //last_d = curr_d;
  548. cpos = glyphs.len() as u32;
  549. }
  550. cpos
  551. }
  552. async fn insert_char(&self, key: char) {
  553. if !self.selected.is_null(0).unwrap() {
  554. self.delete_highlighted();
  555. self.regen_glyphs().await;
  556. };
  557. let mut text = String::new();
  558. let cursor_pos = self.cursor_pos.get();
  559. let glyphs = self.glyphs.lock().unwrap().clone();
  560. // We rebuild the string but insert our substr at cursor_pos.
  561. // The substr is inserted before cursor_pos, and appending to the end
  562. // of the string is when cursor_pos = len(str).
  563. // We can't use String::insert() because sometimes multiple chars are combined
  564. // into a single glyph. We treat the cursor pos as acting on the substrs
  565. // themselves.
  566. for (i, glyph) in glyphs.iter().enumerate() {
  567. if cursor_pos == i as u32 {
  568. text.push(key);
  569. }
  570. text.push_str(&glyph.substr);
  571. }
  572. // Append to the end
  573. if cursor_pos == glyphs.len() as u32 {
  574. text.push(key);
  575. }
  576. self.text.set(text);
  577. // Not always true lol
  578. // If glyphs are recombined, this could get messed up
  579. // meh lets pretend it doesn't exist for now.
  580. self.cursor_pos.set(cursor_pos + 1);
  581. self.pause_blinking();
  582. self.regen_glyphs().await;
  583. self.apply_cursor_scrolling();
  584. self.redraw().await;
  585. }
  586. async fn handle_shortcut(&self, key: char, mods: &KeyMods) {
  587. debug!(target: "ui::editbox", "handle_shortcut({:?}, {:?})", key, mods);
  588. match key {
  589. 'c' => {
  590. if mods.ctrl {
  591. self.copy_highlighted().unwrap();
  592. }
  593. }
  594. 'v' => {
  595. if mods.ctrl {
  596. if let Some(text) = window::clipboard_get() {
  597. self.paste_text(text).await;
  598. }
  599. }
  600. }
  601. _ => {}
  602. }
  603. }
  604. async fn handle_key(&self, key: &KeyCode, mods: &KeyMods) {
  605. debug!(target: "ui::editbox", "handle_key({:?}, {:?})", key, mods);
  606. match key {
  607. KeyCode::Left => {
  608. let mut cursor_pos = self.cursor_pos.get();
  609. // Start selection if shift is held
  610. if !mods.shift {
  611. self.selected.set_null(Role::Internal, 0).unwrap();
  612. self.selected.set_null(Role::Internal, 1).unwrap();
  613. } else if self.selected.is_null(0).unwrap() {
  614. assert!(self.selected.is_null(1).unwrap());
  615. self.selected.set_u32(Role::Internal, 0, cursor_pos).unwrap();
  616. }
  617. if cursor_pos > 0 {
  618. cursor_pos -= 1;
  619. debug!(target: "ui::editbox", "Left cursor_pos={}", cursor_pos);
  620. self.cursor_pos.set(cursor_pos);
  621. }
  622. // Update selection
  623. if mods.shift {
  624. self.selected.set_u32(Role::Internal, 1, cursor_pos).unwrap();
  625. }
  626. self.pause_blinking();
  627. self.apply_cursor_scrolling();
  628. self.redraw().await;
  629. }
  630. KeyCode::Right => {
  631. let mut cursor_pos = self.cursor_pos.get();
  632. // Start selection if shift is held
  633. if !mods.shift {
  634. self.selected.set_null(Role::Internal, 0).unwrap();
  635. self.selected.set_null(Role::Internal, 1).unwrap();
  636. } else if self.selected.is_null(0).unwrap() {
  637. assert!(self.selected.is_null(1).unwrap());
  638. self.selected.set_u32(Role::Internal, 0, cursor_pos).unwrap();
  639. }
  640. let glyphs_len = self.glyphs.lock().unwrap().len() as u32;
  641. if cursor_pos < glyphs_len {
  642. cursor_pos += 1;
  643. debug!(target: "ui::editbox", "Right cursor_pos={}", cursor_pos);
  644. self.cursor_pos.set(cursor_pos);
  645. }
  646. // Update selection
  647. if mods.shift {
  648. self.selected.set_u32(Role::Internal, 1, cursor_pos).unwrap();
  649. }
  650. self.pause_blinking();
  651. self.apply_cursor_scrolling();
  652. self.redraw().await;
  653. }
  654. //KeyCode::Up,
  655. //KeyCode::Down,
  656. //KeyCode::Enter,
  657. KeyCode::Kp0 => self.insert_char('0').await,
  658. KeyCode::Kp1 => self.insert_char('1').await,
  659. KeyCode::Kp2 => self.insert_char('2').await,
  660. KeyCode::Kp3 => self.insert_char('3').await,
  661. KeyCode::Kp4 => self.insert_char('4').await,
  662. KeyCode::Kp5 => self.insert_char('5').await,
  663. KeyCode::Kp6 => self.insert_char('6').await,
  664. KeyCode::Kp7 => self.insert_char('7').await,
  665. KeyCode::Kp8 => self.insert_char('8').await,
  666. KeyCode::Kp9 => self.insert_char('9').await,
  667. KeyCode::KpDecimal => self.insert_char('.').await,
  668. KeyCode::Enter | KeyCode::KpEnter => {
  669. let node = self.node.upgrade().unwrap();
  670. node.trigger("enter_pressed", vec![]).await.unwrap();
  671. }
  672. KeyCode::Delete => {
  673. if !self.selected.is_null(0).unwrap() {
  674. self.delete_highlighted();
  675. } else {
  676. let glyphs = self.glyphs.lock().unwrap().clone();
  677. let cursor_pos = self.cursor_pos.get();
  678. if cursor_pos == glyphs.len() as u32 {
  679. return;
  680. }
  681. // Regen text
  682. let mut text = String::new();
  683. for (i, glyph) in glyphs.iter().enumerate() {
  684. let mut substr = glyph.substr.clone();
  685. if cursor_pos as usize == i {
  686. // Lmk if anyone knows a better way to do substr.pop_front()
  687. let mut chars = substr.chars();
  688. chars.next();
  689. substr = chars.as_str().to_string();
  690. }
  691. text.push_str(&substr);
  692. }
  693. self.text.set(text);
  694. };
  695. self.pause_blinking();
  696. self.regen_glyphs().await;
  697. self.apply_cursor_scrolling();
  698. self.redraw().await;
  699. }
  700. KeyCode::Backspace => {
  701. if !self.selected.is_null(0).unwrap() {
  702. self.delete_highlighted();
  703. } else {
  704. let glyphs = self.glyphs.lock().unwrap().clone();
  705. let cursor_pos = self.cursor_pos.get();
  706. if cursor_pos == 0 {
  707. return;
  708. }
  709. let mut text = String::new();
  710. for (i, glyph) in glyphs.iter().enumerate() {
  711. let mut substr = glyph.substr.clone();
  712. if cursor_pos as usize - 1 == i {
  713. substr.pop().unwrap();
  714. }
  715. text.push_str(&substr);
  716. }
  717. self.text.set(text);
  718. self.cursor_pos.set(cursor_pos - 1);
  719. };
  720. self.pause_blinking();
  721. self.regen_glyphs().await;
  722. self.apply_cursor_scrolling();
  723. self.redraw().await;
  724. }
  725. KeyCode::Home => {
  726. let cursor_pos = self.cursor_pos.get();
  727. if !mods.shift {
  728. self.selected.set_null(Role::Internal, 0).unwrap();
  729. self.selected.set_null(Role::Internal, 1).unwrap();
  730. } else if self.selected.is_null(0).unwrap() {
  731. assert!(self.selected.is_null(1).unwrap());
  732. self.selected.set_u32(Role::Internal, 0, cursor_pos).unwrap();
  733. }
  734. self.cursor_pos.set(0);
  735. // Update selection
  736. if mods.shift {
  737. self.selected.set_u32(Role::Internal, 1, cursor_pos).unwrap();
  738. }
  739. self.pause_blinking();
  740. self.apply_cursor_scrolling();
  741. self.redraw().await;
  742. }
  743. KeyCode::End => {
  744. let cursor_pos = self.cursor_pos.get();
  745. if !mods.shift {
  746. self.selected.set_null(Role::Internal, 0).unwrap();
  747. self.selected.set_null(Role::Internal, 1).unwrap();
  748. } else if self.selected.is_null(0).unwrap() {
  749. assert!(self.selected.is_null(1).unwrap());
  750. self.selected.set_u32(Role::Internal, 0, cursor_pos).unwrap();
  751. }
  752. let glyphs_len = self.glyphs.lock().unwrap().len();
  753. self.cursor_pos.set(glyphs_len as u32);
  754. // Update selection
  755. if mods.shift {
  756. self.selected.set_u32(Role::Internal, 1, cursor_pos).unwrap();
  757. }
  758. self.pause_blinking();
  759. self.apply_cursor_scrolling();
  760. self.redraw().await;
  761. }
  762. _ => {}
  763. }
  764. }
  765. fn delete_highlighted(&self) {
  766. assert!(!self.selected.is_null(0).unwrap());
  767. assert!(!self.selected.is_null(1).unwrap());
  768. let start = self.selected.get_u32(0).unwrap() as usize;
  769. let end = self.selected.get_u32(1).unwrap() as usize;
  770. let sel_start = std::cmp::min(start, end);
  771. let sel_end = std::cmp::max(start, end);
  772. let mut text = String::new();
  773. let glyphs = self.glyphs.lock().unwrap().clone();
  774. // Regen text
  775. for (i, glyph) in glyphs.iter().enumerate() {
  776. if sel_start <= i && i < sel_end {
  777. continue
  778. }
  779. text.push_str(&glyph.substr);
  780. }
  781. debug!(
  782. target: "ui::editbox",
  783. "delete_highlighted() text=\"{}\", cursor_pos={}",
  784. text, sel_start
  785. );
  786. self.text.set(text);
  787. self.selected.set_null(Role::Internal, 0).unwrap();
  788. self.selected.set_null(Role::Internal, 1).unwrap();
  789. self.cursor_pos.set(sel_start as u32);
  790. }
  791. fn copy_highlighted(&self) -> Result<()> {
  792. let start = self.selected.get_u32(0)? as usize;
  793. let end = self.selected.get_u32(1)? as usize;
  794. let sel_start = std::cmp::min(start, end);
  795. let sel_end = std::cmp::max(start, end);
  796. let mut text = String::new();
  797. let glyphs = self.glyphs.lock().unwrap().clone();
  798. for (glyph_idx, glyph) in glyphs.iter().enumerate() {
  799. if sel_start <= glyph_idx && glyph_idx < sel_end {
  800. text.push_str(&glyph.substr);
  801. }
  802. }
  803. info!(target: "ui::editbox", "Copied '{}'", text);
  804. window::clipboard_set(&text);
  805. Ok(())
  806. }
  807. async fn paste_text(&self, key: String) {
  808. let mut text = String::new();
  809. let cursor_pos = self.cursor_pos.get();
  810. if cursor_pos == 0 {
  811. text = key.clone();
  812. }
  813. let glyphs = self.glyphs.lock().unwrap().clone();
  814. for (glyph_idx, glyph) in glyphs.iter().enumerate() {
  815. text.push_str(&glyph.substr);
  816. if cursor_pos == glyph_idx as u32 + 1 {
  817. text.push_str(&key);
  818. }
  819. }
  820. self.text.set(text);
  821. // Not always true lol
  822. self.cursor_pos.set(cursor_pos + 1);
  823. self.apply_cursor_scrolling();
  824. self.redraw().await;
  825. }
  826. /// Whenever the cursor property is modified this MUST be called
  827. /// to recalculate the scroll x property.
  828. fn apply_cursor_scrolling(&self) {
  829. let rect = self.rect.get();
  830. let cursor_pos = self.cursor_pos.get() as usize;
  831. let cursor_width = self.cursor_width.get();
  832. let mut scroll = self.scroll.get();
  833. let cursor_x = {
  834. let font_size = self.font_size.get();
  835. let window_scale = self.window_scale.get();
  836. let baseline = self.baseline.get();
  837. let glyphs = self.glyphs.lock().unwrap().clone();
  838. let mut glyph_pos_iter =
  839. GlyphPositionIter::new(font_size, window_scale, &glyphs, baseline);
  840. if cursor_pos == 0 {
  841. 0.
  842. } else if cursor_pos == glyphs.len() {
  843. let glyph_pos = glyph_pos_iter.last().unwrap();
  844. let rhs = glyph_pos.rhs() + eol_nudge(font_size, &glyphs);
  845. rhs
  846. } else {
  847. assert!(cursor_pos < glyphs.len());
  848. let glyph_pos = glyph_pos_iter.nth(cursor_pos).expect("glyph pos mismatch glyphs");
  849. glyph_pos.x
  850. }
  851. };
  852. // The LHS and RHS of the cursor box
  853. let cursor_lhs = cursor_x - scroll;
  854. let cursor_rhs = cursor_lhs + cursor_width;
  855. // RHS is outside
  856. if cursor_rhs > rect.w {
  857. // We want a scroll so RHS = w
  858. // cursor_x - scroll + CURSOR_WIDTH = rect.w
  859. scroll = cursor_x + cursor_width - rect.w;
  860. // LHS is negative
  861. } else if cursor_lhs < 0. {
  862. // We want scroll so LHS = 0
  863. // cursor_x - scroll = 0
  864. scroll = cursor_x;
  865. }
  866. self.scroll.set(scroll);
  867. }
  868. fn pause_blinking(&self) {
  869. self.blink_is_paused.store(true, Ordering::Relaxed);
  870. self.cursor_is_visible.store(true, Ordering::Relaxed);
  871. }
  872. async fn redraw(&self) {
  873. let Some(draw_update) = self.draw_cached().await else {
  874. error!(target: "ui::editbox", "Text failed to draw");
  875. return;
  876. };
  877. self.render_api.replace_draw_calls(draw_update.draw_calls);
  878. //debug!(target: "ui::editbox", "replace draw calls done");
  879. for buffer_id in draw_update.freed_buffers {
  880. self.render_api.delete_buffer(buffer_id);
  881. }
  882. for texture_id in draw_update.freed_textures {
  883. self.render_api.delete_texture(texture_id);
  884. }
  885. }
  886. async fn redraw_cursor(&self) {
  887. let cursor_instrs = self.get_cursor_instrs();
  888. let draw_calls = vec![(
  889. self.cursor_dc_key,
  890. GfxDrawCall { instrs: cursor_instrs, dcs: vec![], z_index: self.z_index.get() },
  891. )];
  892. self.render_api.replace_draw_calls(draw_calls);
  893. }
  894. fn get_cursor_instrs(&self) -> Vec<GfxDrawInstruction> {
  895. if !self.is_focused.get() || !self.cursor_is_visible.load(Ordering::Relaxed) {
  896. return vec![]
  897. }
  898. let mut cursor_instrs = vec![];
  899. let mut cursor_pos = Point::zero();
  900. cursor_pos.x += self.cursor_px_offset();
  901. cursor_instrs.push(GfxDrawInstruction::Move(cursor_pos));
  902. let cursor_mesh = {
  903. let mut cursor_mesh = self.cursor_mesh.lock().unwrap();
  904. if cursor_mesh.is_none() {
  905. *cursor_mesh = Some(self.regen_cursor_mesh());
  906. }
  907. cursor_mesh.clone().unwrap()
  908. };
  909. cursor_instrs.push(GfxDrawInstruction::Draw(cursor_mesh));
  910. cursor_instrs
  911. }
  912. async fn draw_cached(&self) -> Option<DrawUpdate> {
  913. let rect = self.rect.get();
  914. let mut freed = std::mem::take(&mut *self.freed.lock().unwrap());
  915. // Force complete redraw if the window scale changed
  916. let window_scale = self.window_scale.get();
  917. if self.old_window_scale.swap(window_scale, Ordering::Relaxed) != window_scale {
  918. self.regen_glyphs().await;
  919. let text_mesh = std::mem::replace(&mut *self.text_mesh.lock().unwrap(), None);
  920. // We're finished with these so clean up.
  921. if let Some(old) = text_mesh {
  922. if let Some(texture) = old.texture {
  923. debug!(target: "ui::editbox", "{:?}: freeing old texture", self.node());
  924. freed.textures.push(texture);
  925. }
  926. freed.buffers.push(old.vertex_buffer);
  927. freed.buffers.push(old.index_buffer);
  928. }
  929. }
  930. let text_mesh = self.regen_text_mesh(rect.clone());
  931. let old_text_mesh =
  932. std::mem::replace(&mut *self.text_mesh.lock().unwrap(), Some(text_mesh.clone()));
  933. // We're finished with these so clean up.
  934. if let Some(old) = old_text_mesh {
  935. if let Some(texture) = old.texture {
  936. debug!(target: "ui::editbox", "{:?}: freeing old texture", self.node());
  937. freed.textures.push(texture);
  938. }
  939. freed.buffers.push(old.vertex_buffer);
  940. freed.buffers.push(old.index_buffer);
  941. }
  942. let cursor_instrs = self.get_cursor_instrs();
  943. Some(DrawUpdate {
  944. key: self.text_dc_key,
  945. draw_calls: vec![
  946. (
  947. self.text_dc_key,
  948. GfxDrawCall {
  949. instrs: vec![
  950. GfxDrawInstruction::Move(rect.pos()),
  951. GfxDrawInstruction::Draw(text_mesh),
  952. ],
  953. dcs: vec![self.cursor_dc_key],
  954. z_index: self.z_index.get(),
  955. },
  956. ),
  957. (
  958. self.cursor_dc_key,
  959. GfxDrawCall { instrs: cursor_instrs, dcs: vec![], z_index: self.z_index.get() },
  960. ),
  961. ],
  962. freed_textures: freed.textures,
  963. freed_buffers: freed.buffers,
  964. })
  965. }
  966. }
  967. impl Drop for EditBox {
  968. fn drop(&mut self) {
  969. let text_mesh = std::mem::replace(&mut *self.text_mesh.lock().unwrap(), None);
  970. // We're finished with these so clean up.
  971. if let Some(old) = text_mesh {
  972. if let Some(texture) = old.texture {
  973. self.render_api.delete_texture(texture);
  974. }
  975. self.render_api.delete_buffer(old.vertex_buffer);
  976. self.render_api.delete_buffer(old.index_buffer);
  977. }
  978. }
  979. }
  980. #[async_trait]
  981. impl UIObject for EditBox {
  982. fn z_index(&self) -> u32 {
  983. self.z_index.get()
  984. }
  985. async fn draw(&self, parent_rect: Rectangle) -> Option<DrawUpdate> {
  986. debug!(target: "ui::editbox", "EditBox::draw()");
  987. *self.parent_rect.lock().unwrap() = Some(parent_rect);
  988. self.rect.eval(&parent_rect).ok()?;
  989. self.draw_cached().await
  990. }
  991. async fn handle_char(&self, key: char, mods: KeyMods, repeat: bool) -> bool {
  992. // First filter for only single digit keys
  993. if DISALLOWED_CHARS.contains(&key) {
  994. return false
  995. }
  996. if !self.is_focused.get() {
  997. return false
  998. }
  999. if mods.ctrl || mods.alt {
  1000. if repeat {
  1001. return false
  1002. }
  1003. self.handle_shortcut(key, &mods).await;
  1004. return true
  1005. }
  1006. let actions = {
  1007. let mut repeater = self.key_repeat.lock().unwrap();
  1008. repeater.key_down(PressedKey::Char(key), repeat)
  1009. };
  1010. debug!(target: "ui::editbox", "Key {:?} has {} actions", key, actions);
  1011. for _ in 0..actions {
  1012. self.insert_char(key).await;
  1013. }
  1014. true
  1015. }
  1016. async fn handle_key_down(&self, key: KeyCode, mods: KeyMods, repeat: bool) -> bool {
  1017. // First filter for only single digit keys
  1018. // Avoid processing events handled by insert_char()
  1019. if !ALLOWED_KEYCODES.contains(&key) {
  1020. return false
  1021. }
  1022. if !self.is_focused.get() {
  1023. return false
  1024. }
  1025. let actions = {
  1026. let mut repeater = self.key_repeat.lock().unwrap();
  1027. repeater.key_down(PressedKey::Key(key), repeat)
  1028. };
  1029. // Suppress noisy message
  1030. if actions > 0 {
  1031. debug!(target: "ui::editbox", "Key {:?} has {} actions", key, actions);
  1032. }
  1033. for _ in 0..actions {
  1034. self.handle_key(&key, &mods).await;
  1035. }
  1036. true
  1037. }
  1038. async fn handle_mouse_btn_down(&self, btn: MouseButton, mouse_pos: Point) -> bool {
  1039. if !self.is_active.get() {
  1040. return true
  1041. }
  1042. self.handle_click_down(btn, mouse_pos).await
  1043. }
  1044. async fn handle_mouse_btn_up(&self, btn: MouseButton, mouse_pos: Point) -> bool {
  1045. if !self.is_active.get() {
  1046. return true
  1047. }
  1048. self.handle_click_up(btn, mouse_pos)
  1049. }
  1050. async fn handle_mouse_move(&self, mouse_pos: Point) -> bool {
  1051. if !self.is_active.get() {
  1052. return false
  1053. }
  1054. self.handle_cursor_move(mouse_pos).await
  1055. }
  1056. async fn handle_touch(&self, phase: TouchPhase, id: u64, touch_pos: Point) -> bool {
  1057. if !self.is_active.get() {
  1058. return true
  1059. }
  1060. // Ignore multi-touch
  1061. if id != 0 {
  1062. return false
  1063. }
  1064. // Simulate mouse events
  1065. match phase {
  1066. TouchPhase::Started => self.handle_click_down(MouseButton::Left, touch_pos).await,
  1067. TouchPhase::Moved => self.handle_cursor_move(touch_pos).await,
  1068. TouchPhase::Ended => self.handle_click_up(MouseButton::Left, touch_pos),
  1069. TouchPhase::Cancelled => false,
  1070. }
  1071. }
  1072. }
  1073. /// Filter these char events from being handled since we handle them
  1074. /// using the key_up/key_down events.
  1075. /// Avoids duplicate processing of keyboard input events.
  1076. static DISALLOWED_CHARS: &'static [char] = &['\r', '\u{8}', '\u{7f}', '\t', '\n'];
  1077. /// These keycodes are handled via normal key_up/key_down events.
  1078. /// Anything in this list must be disallowed char events.
  1079. static ALLOWED_KEYCODES: &'static [KeyCode] = &[
  1080. KeyCode::Left,
  1081. KeyCode::Right,
  1082. KeyCode::Up,
  1083. KeyCode::Down,
  1084. KeyCode::Enter,
  1085. KeyCode::Kp0,
  1086. KeyCode::Kp1,
  1087. KeyCode::Kp2,
  1088. KeyCode::Kp3,
  1089. KeyCode::Kp4,
  1090. KeyCode::Kp5,
  1091. KeyCode::Kp6,
  1092. KeyCode::Kp7,
  1093. KeyCode::Kp8,
  1094. KeyCode::Kp9,
  1095. KeyCode::KpDecimal,
  1096. KeyCode::KpEnter,
  1097. KeyCode::Delete,
  1098. KeyCode::Backspace,
  1099. KeyCode::Home,
  1100. KeyCode::End,
  1101. ];
  1102. /*
  1103. impl Stoppable for EditBox {
  1104. async fn stop(&self) {
  1105. // TODO: Delete own draw call
  1106. // Free buffers
  1107. // Should this be in drop?
  1108. //self.render_api.delete_buffer(self.vertex_buffer);
  1109. //self.render_api.delete_buffer(self.index_buffer);
  1110. }
  1111. }
  1112. */