editbox.rs 45 KB

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