mod.rs 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608
  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_lock::Mutex as AsyncMutex;
  19. use async_trait::async_trait;
  20. use atomic_float::AtomicF32;
  21. use darkfi::system::msleep;
  22. use miniquad::{window, KeyCode, KeyMods, MouseButton, TouchPhase};
  23. use rand::{rngs::OsRng, Rng};
  24. use std::{
  25. collections::HashMap,
  26. sync::{
  27. atomic::{AtomicBool, Ordering},
  28. Arc, Mutex as SyncMutex, OnceLock, Weak,
  29. },
  30. time::Instant,
  31. };
  32. use crate::{
  33. error::Result,
  34. gfx::{
  35. GfxDrawCall, GfxDrawInstruction, GfxDrawMesh, GfxTextureId, GraphicsEventPublisherPtr,
  36. Point, Rectangle, RenderApi, Vertex,
  37. },
  38. mesh::{MeshBuilder, MeshInfo, COLOR_BLUE, COLOR_WHITE},
  39. prop::{
  40. PropertyBool, PropertyColor, PropertyFloat32, PropertyPtr, PropertyRect, PropertyStr,
  41. PropertyUint32, Role,
  42. },
  43. pubsub::Subscription,
  44. scene::{Pimpl, SceneNodePtr, SceneNodeWeak},
  45. text::{self, Glyph, GlyphPositionIter, TextShaperPtr},
  46. util::{enumerate_ref, is_whitespace, zip3},
  47. ExecutorPtr,
  48. };
  49. use super::{DrawUpdate, OnModify, UIObject};
  50. mod editable;
  51. use editable::{Editable, Selection, TextIdx, TextPos};
  52. // EOL whitespace is given a nudge since it has a width of 0 after text shaping
  53. const CURSOR_EOL_WS_NUDGE: f32 = 0.8;
  54. // EOL chars are more aesthetic when given a smallish nudge
  55. const CURSOR_EOL_NUDGE: f32 = 0.2;
  56. fn eol_nudge(font_size: f32, glyphs: &Vec<Glyph>) -> f32 {
  57. if is_whitespace(&glyphs.last().unwrap().substr) {
  58. (font_size * CURSOR_EOL_WS_NUDGE).round()
  59. } else {
  60. (font_size * CURSOR_EOL_NUDGE).round()
  61. }
  62. }
  63. #[derive(Debug, Clone, Eq, Hash, PartialEq)]
  64. enum PressedKey {
  65. Char(char),
  66. Key(KeyCode),
  67. }
  68. /// On key press (repeat=false), we immediately process the event.
  69. /// Then there's a delay (repeat=true) and then for every step time
  70. /// while key press events are being sent, we allow an event.
  71. /// This ensures smooth typing in the editbox.
  72. struct PressedKeysSmoothRepeat {
  73. /// When holding keys, we track from start and last sent time.
  74. /// This is useful for initial delay and smooth scrolling.
  75. pressed_keys: HashMap<PressedKey, RepeatingKeyTimer>,
  76. /// Initial delay before allowing keys
  77. start_delay: u32,
  78. /// Minimum time between repeated keys
  79. step_time: u32,
  80. }
  81. impl PressedKeysSmoothRepeat {
  82. fn new(start_delay: u32, step_time: u32) -> Self {
  83. Self { pressed_keys: HashMap::new(), start_delay, step_time }
  84. }
  85. fn key_down(&mut self, key: PressedKey, repeat: bool) -> u32 {
  86. //debug!(target: "PressedKeysSmoothRepeat", "key_down({:?}, {})", key, repeat);
  87. if !repeat {
  88. self.pressed_keys.remove(&key);
  89. return 1;
  90. }
  91. // Insert key if not exists
  92. if !self.pressed_keys.contains_key(&key) {
  93. //debug!(target: "PressedKeysSmoothRepeat", "insert key {:?}", key);
  94. self.pressed_keys.insert(key.clone(), RepeatingKeyTimer::new());
  95. }
  96. let repeater = self.pressed_keys.get_mut(&key).expect("repeat map");
  97. repeater.update(self.start_delay, self.step_time)
  98. }
  99. /*
  100. fn key_up(&mut self, key: &PressedKey) {
  101. //debug!(target: "PressedKeysSmoothRepeat", "key_up({:?})", key);
  102. assert!(self.pressed_keys.contains_key(key));
  103. self.pressed_keys.remove(key).expect("key was pressed");
  104. }
  105. */
  106. }
  107. struct RepeatingKeyTimer {
  108. start: Instant,
  109. actions: u32,
  110. }
  111. impl RepeatingKeyTimer {
  112. fn new() -> Self {
  113. Self { start: Instant::now(), actions: 0 }
  114. }
  115. fn update(&mut self, start_delay: u32, step_time: u32) -> u32 {
  116. let elapsed = self.start.elapsed().as_millis();
  117. //debug!(target: "RepeatingKeyTimer", "update() elapsed={}, actions={}",
  118. // elapsed, self.actions);
  119. if elapsed < start_delay as u128 {
  120. return 0
  121. }
  122. let total_actions = ((elapsed - start_delay as u128) / step_time as u128) as u32;
  123. let remaining_actions = total_actions - self.actions;
  124. self.actions = total_actions;
  125. remaining_actions
  126. }
  127. }
  128. #[derive(Clone)]
  129. struct TouchStartInfo {
  130. pos: Point,
  131. instant: std::time::Instant,
  132. }
  133. impl TouchStartInfo {
  134. fn new(pos: Point) -> Self {
  135. Self { pos, instant: std::time::Instant::now() }
  136. }
  137. }
  138. #[derive(Clone)]
  139. enum TouchStateAction {
  140. Inactive,
  141. Started { pos: Point, instant: std::time::Instant },
  142. StartSelect,
  143. Select,
  144. DragSelectHandle { side: isize },
  145. ScrollHoriz,
  146. }
  147. struct TouchInfo {
  148. state: TouchStateAction,
  149. start: Option<TouchStartInfo>,
  150. }
  151. impl TouchInfo {
  152. fn new() -> Self {
  153. Self { state: TouchStateAction::Inactive, start: None }
  154. }
  155. fn start(&mut self, pos: Point) {
  156. debug!(target: "ui::editbox", "TouchStateAction::Started");
  157. self.state = TouchStateAction::Started { pos, instant: std::time::Instant::now() };
  158. }
  159. fn stop(&mut self) -> TouchStateAction {
  160. std::mem::replace(&mut self.state, TouchStateAction::Inactive)
  161. }
  162. fn update(&mut self, pos: &Point) {
  163. match &self.state {
  164. TouchStateAction::Started { pos: start_pos, instant } => {
  165. let travel_dist = pos.dist_sq(&start_pos);
  166. let x_dist = pos.x - start_pos.x;
  167. let elapsed = instant.elapsed().as_millis();
  168. if travel_dist < 5. {
  169. if elapsed > 1000 {
  170. debug!(target: "ui::editbox", "TouchStateAction::StartSelect");
  171. self.state = TouchStateAction::StartSelect;
  172. }
  173. } else if x_dist.abs() > 5. {
  174. debug!(target: "ui::editbox", "TouchStateAction::ScrollHoriz");
  175. self.state = TouchStateAction::ScrollHoriz;
  176. }
  177. }
  178. _ => {}
  179. }
  180. }
  181. }
  182. pub type EditBoxPtr = Arc<EditBox>;
  183. pub struct EditBox {
  184. node: SceneNodeWeak,
  185. tasks: OnceLock<Vec<smol::Task<()>>>,
  186. render_api: RenderApi,
  187. text_shaper: TextShaperPtr,
  188. key_repeat: SyncMutex<PressedKeysSmoothRepeat>,
  189. glyphs: SyncMutex<Vec<Glyph>>,
  190. /// DC key for the text
  191. text_dc_key: u64,
  192. cursor_mesh: SyncMutex<Option<GfxDrawMesh>>,
  193. /// DC key for the cursor. Allows updating cursor independently.
  194. cursor_dc_key: u64,
  195. is_active: PropertyBool,
  196. is_focused: PropertyBool,
  197. rect: PropertyRect,
  198. baseline: PropertyFloat32,
  199. scroll: PropertyFloat32,
  200. cursor_pos: PropertyUint32,
  201. font_size: PropertyFloat32,
  202. text: PropertyStr,
  203. text_color: PropertyColor,
  204. text_hi_color: PropertyColor,
  205. cursor_color: PropertyColor,
  206. cursor_width: PropertyFloat32,
  207. cursor_ascent: PropertyFloat32,
  208. cursor_descent: PropertyFloat32,
  209. cursor_blink_time: PropertyUint32,
  210. cursor_idle_time: PropertyUint32,
  211. hi_bg_color: PropertyColor,
  212. select_ascent: PropertyFloat32,
  213. select_descent: PropertyFloat32,
  214. selected: PropertyPtr,
  215. z_index: PropertyUint32,
  216. debug: PropertyBool,
  217. editable: SyncMutex<Editable>,
  218. select: SyncMutex<Vec<Selection>>,
  219. mouse_btn_held: AtomicBool,
  220. cursor_is_visible: AtomicBool,
  221. blink_is_paused: AtomicBool,
  222. /// Used to explicitly hide the cursor. Must be manually re-enabled.
  223. hide_cursor: AtomicBool,
  224. touch_info: SyncMutex<TouchInfo>,
  225. is_phone_select: AtomicBool,
  226. old_window_scale: AtomicF32,
  227. window_scale: PropertyFloat32,
  228. parent_rect: SyncMutex<Option<Rectangle>>,
  229. }
  230. impl EditBox {
  231. pub async fn new(
  232. node: SceneNodeWeak,
  233. window_scale: PropertyFloat32,
  234. render_api: RenderApi,
  235. text_shaper: TextShaperPtr,
  236. ex: ExecutorPtr,
  237. ) -> Pimpl {
  238. debug!(target: "ui::editbox", "EditBox::new()");
  239. let node_ref = &node.upgrade().unwrap();
  240. let is_active = PropertyBool::wrap(node_ref, Role::Internal, "is_active", 0).unwrap();
  241. let is_focused = PropertyBool::wrap(node_ref, Role::Internal, "is_focused", 0).unwrap();
  242. let rect = PropertyRect::wrap(node_ref, Role::Internal, "rect").unwrap();
  243. let baseline = PropertyFloat32::wrap(node_ref, Role::Internal, "baseline", 0).unwrap();
  244. let scroll = PropertyFloat32::wrap(node_ref, Role::Internal, "scroll", 0).unwrap();
  245. let cursor_pos = PropertyUint32::wrap(node_ref, Role::Internal, "cursor_pos", 0).unwrap();
  246. let font_size = PropertyFloat32::wrap(node_ref, Role::Internal, "font_size", 0).unwrap();
  247. let text = PropertyStr::wrap(node_ref, Role::Internal, "text", 0).unwrap();
  248. let text_color = PropertyColor::wrap(node_ref, Role::Internal, "text_color").unwrap();
  249. let text_hi_color = PropertyColor::wrap(node_ref, Role::Internal, "text_hi_color").unwrap();
  250. let cursor_color = PropertyColor::wrap(node_ref, Role::Internal, "cursor_color").unwrap();
  251. let cursor_width =
  252. PropertyFloat32::wrap(node_ref, Role::Internal, "cursor_width", 0).unwrap();
  253. let cursor_ascent =
  254. PropertyFloat32::wrap(node_ref, Role::Internal, "cursor_ascent", 0).unwrap();
  255. let cursor_descent =
  256. PropertyFloat32::wrap(node_ref, Role::Internal, "cursor_descent", 0).unwrap();
  257. let hi_bg_color = PropertyColor::wrap(node_ref, Role::Internal, "hi_bg_color").unwrap();
  258. let select_ascent =
  259. PropertyFloat32::wrap(node_ref, Role::Internal, "select_ascent", 0).unwrap();
  260. let select_descent =
  261. PropertyFloat32::wrap(node_ref, Role::Internal, "select_descent", 0).unwrap();
  262. let selected = node_ref.get_property("selected").unwrap();
  263. let cursor_blink_time =
  264. PropertyUint32::wrap(node_ref, Role::Internal, "cursor_blink_time", 0).unwrap();
  265. let cursor_idle_time =
  266. PropertyUint32::wrap(node_ref, Role::Internal, "cursor_idle_time", 0).unwrap();
  267. let z_index = PropertyUint32::wrap(node_ref, Role::Internal, "z_index", 0).unwrap();
  268. let debug = PropertyBool::wrap(node_ref, Role::Internal, "debug", 0).unwrap();
  269. let node_name = node_ref.name.clone();
  270. let node_id = node_ref.id;
  271. // Must do this whenever the text changes
  272. let glyphs = text_shaper.shape(text.get(), font_size.get(), window_scale.get());
  273. let self_ = Arc::new(Self {
  274. node,
  275. tasks: OnceLock::new(),
  276. render_api,
  277. text_shaper: text_shaper.clone(),
  278. key_repeat: SyncMutex::new(PressedKeysSmoothRepeat::new(400, 50)),
  279. glyphs: SyncMutex::new(glyphs),
  280. text_dc_key: OsRng.gen(),
  281. cursor_mesh: SyncMutex::new(None),
  282. cursor_dc_key: OsRng.gen(),
  283. is_active,
  284. is_focused,
  285. rect,
  286. baseline: baseline.clone(),
  287. scroll,
  288. cursor_pos,
  289. font_size: font_size.clone(),
  290. text,
  291. text_color,
  292. text_hi_color,
  293. cursor_color,
  294. cursor_width,
  295. cursor_ascent,
  296. cursor_descent,
  297. cursor_blink_time,
  298. cursor_idle_time,
  299. hi_bg_color,
  300. select_ascent,
  301. select_descent,
  302. selected,
  303. z_index,
  304. debug,
  305. editable: SyncMutex::new(Editable::new(
  306. text_shaper,
  307. font_size,
  308. window_scale.clone(),
  309. baseline,
  310. )),
  311. select: SyncMutex::new(vec![]),
  312. mouse_btn_held: AtomicBool::new(false),
  313. cursor_is_visible: AtomicBool::new(true),
  314. blink_is_paused: AtomicBool::new(false),
  315. hide_cursor: AtomicBool::new(false),
  316. touch_info: SyncMutex::new(TouchInfo::new()),
  317. is_phone_select: AtomicBool::new(false),
  318. old_window_scale: AtomicF32::new(window_scale.get()),
  319. window_scale,
  320. parent_rect: SyncMutex::new(None),
  321. });
  322. Pimpl::EditBox(self_)
  323. }
  324. fn node(&self) -> SceneNodePtr {
  325. self.node.upgrade().unwrap()
  326. }
  327. /// Called whenever the text or any text property changes.
  328. fn regen_text_mesh(&self, mut clip: Rectangle) -> GfxDrawMesh {
  329. clip.x = 0.;
  330. clip.y = 0.;
  331. let is_focused = self.is_focused.get();
  332. let text = self.text.get();
  333. let font_size = self.font_size.get();
  334. let window_scale = self.window_scale.get();
  335. let text_color = self.text_color.get();
  336. let text_hi_color = self.text_hi_color.get();
  337. let baseline = self.baseline.get();
  338. let scroll = self.scroll.get();
  339. let cursor_pos = self.cursor_pos.get() as usize;
  340. let cursor_color = self.cursor_color.get();
  341. let debug = self.debug.get();
  342. //debug!(target: "ui::editbox", "Rendering text '{text}' clip={clip:?}");
  343. //debug!(target: "ui::editbox", " cursor_pos={cursor_pos}, is_focused={is_focused}");
  344. let rendered = self.editable.lock().unwrap().render();
  345. let atlas = text::make_texture_atlas(&self.render_api, &rendered.glyphs);
  346. //let mut mesh = MeshBuilder::with_clip(clip.clone());
  347. let mut mesh = MeshBuilder::new();
  348. let selections = self.select.lock().unwrap().clone();
  349. // Just an assert
  350. if self.is_phone_select.load(Ordering::Relaxed) {
  351. assert!(selections.len() <= 1);
  352. }
  353. for select in &selections {
  354. self.draw_selected(&mut mesh, select, &rendered.glyphs, clip.h);
  355. }
  356. let select_marks = self.mark_selected_glyphs(&rendered.glyphs, selections);
  357. if rendered.has_underline() {
  358. self.draw_underline(
  359. &mut mesh,
  360. &rendered.glyphs,
  361. clip.h,
  362. rendered.under_start,
  363. rendered.under_end,
  364. );
  365. }
  366. let glyph_pos_iter =
  367. GlyphPositionIter::new(font_size, window_scale, &rendered.glyphs, baseline);
  368. for (glyph_idx, mut glyph_rect, glyph, is_selected) in
  369. zip3(glyph_pos_iter, rendered.glyphs.iter(), select_marks.iter())
  370. {
  371. let uv_rect = atlas.fetch_uv(glyph.glyph_id).expect("missing glyph UV rect");
  372. glyph_rect.x -= scroll;
  373. //mesh.draw_outline(&glyph_rect, COLOR_BLUE, 2.);
  374. let mut color = text_color.clone();
  375. if *is_selected {
  376. color = text_hi_color.clone();
  377. }
  378. if glyph.sprite.has_color {
  379. color = COLOR_WHITE;
  380. }
  381. mesh.draw_box(&glyph_rect, color, uv_rect);
  382. }
  383. if debug {
  384. mesh.draw_outline(&clip, COLOR_BLUE, 1.);
  385. }
  386. mesh.alloc(&self.render_api).draw_with_texture(atlas.texture)
  387. }
  388. fn regen_cursor_mesh(&self) -> GfxDrawMesh {
  389. let cursor_width = self.cursor_width.get();
  390. let cursor_ascent = self.cursor_ascent.get();
  391. let cursor_descent = self.cursor_descent.get();
  392. let baseline = self.baseline.get();
  393. let rect_h = self.rect.get().h;
  394. let cursor_rect = Rectangle {
  395. x: 0.,
  396. y: baseline - cursor_ascent,
  397. w: cursor_width,
  398. h: cursor_ascent + cursor_descent,
  399. };
  400. let cursor_color = self.cursor_color.get();
  401. let mut mesh = MeshBuilder::new();
  402. mesh.draw_filled_box(&cursor_rect, cursor_color);
  403. mesh.alloc(&self.render_api).draw_untextured()
  404. }
  405. fn cursor_px_offset(&self) -> f32 {
  406. assert!(self.is_focused.get());
  407. let (cursor_pos, glyphs) = {
  408. let editable = self.editable.lock().unwrap();
  409. let rendered = editable.render();
  410. let cursor_pos = editable.get_cursor_pos(&rendered);
  411. (cursor_pos, rendered.glyphs)
  412. };
  413. let font_size = self.font_size.get();
  414. let window_scale = self.window_scale.get();
  415. let baseline = self.baseline.get();
  416. let scroll = self.scroll.get();
  417. // Add composer glyphs too
  418. let glyph_pos_iter = GlyphPositionIter::new(font_size, window_scale, &glyphs, baseline);
  419. // Used for drawing the cursor when it's at the end of the line.
  420. let mut rhs = 0.;
  421. if cursor_pos == 0 {
  422. return 0.;
  423. }
  424. for (glyph_idx, (mut glyph_rect, glyph)) in glyph_pos_iter.zip(glyphs.iter()).enumerate() {
  425. glyph_rect.x -= scroll;
  426. if cursor_pos == glyph_idx {
  427. return glyph_rect.x;
  428. }
  429. rhs = glyph_rect.rhs();
  430. }
  431. assert!(cursor_pos == glyphs.len());
  432. rhs += eol_nudge(font_size, &glyphs);
  433. rhs
  434. }
  435. fn mark_selected_glyphs(&self, glyphs: &Vec<Glyph>, selections: Vec<Selection>) -> Vec<bool> {
  436. let mut marks: Vec<_> = glyphs.iter().map(|_| false).collect();
  437. for select in selections {
  438. let start = std::cmp::min(select.start, select.end);
  439. let end = std::cmp::max(select.start, select.end);
  440. for i in start..end {
  441. marks[i] = true;
  442. }
  443. }
  444. marks
  445. }
  446. fn draw_selected(
  447. &self,
  448. mesh: &mut MeshBuilder,
  449. select: &Selection,
  450. glyphs: &Vec<Glyph>,
  451. clip_h: f32,
  452. ) {
  453. if select.start == select.end {
  454. return
  455. }
  456. let start = std::cmp::min(select.start, select.end);
  457. let end = std::cmp::max(select.start, select.end);
  458. let font_size = self.font_size.get();
  459. let window_scale = self.window_scale.get();
  460. let baseline = self.baseline.get();
  461. let scroll = self.scroll.get();
  462. let hi_bg_color = self.hi_bg_color.get();
  463. let glyph_pos_iter = GlyphPositionIter::new(font_size, window_scale, &glyphs, baseline);
  464. let is_phone_select = self.is_phone_select.load(Ordering::Relaxed);
  465. let mut start_x = 0.;
  466. let mut end_x = 0.;
  467. // When cursor lands at the end of the line
  468. let mut rhs = 0.;
  469. for (glyph_idx, mut glyph_rect) in glyph_pos_iter.enumerate() {
  470. glyph_rect.x -= scroll;
  471. if glyph_idx == start {
  472. start_x = glyph_rect.x;
  473. }
  474. if glyph_idx == end {
  475. end_x = glyph_rect.x;
  476. }
  477. rhs = glyph_rect.rhs();
  478. }
  479. if start == 0 {
  480. start_x = scroll;
  481. }
  482. if end == glyphs.len() {
  483. rhs += eol_nudge(font_size, &glyphs);
  484. end_x = rhs;
  485. }
  486. let select_ascent = self.select_ascent.get();
  487. let select_descent = self.select_descent.get();
  488. let select_rect = Rectangle {
  489. x: start_x,
  490. y: baseline - select_ascent,
  491. w: end_x - start_x,
  492. h: select_ascent + select_descent,
  493. };
  494. mesh.draw_box(&select_rect, hi_bg_color, &Rectangle::zero());
  495. if is_phone_select {
  496. self.draw_phone_select_handle(mesh, start_x, -1.);
  497. self.draw_phone_select_handle(mesh, end_x, 1.);
  498. }
  499. }
  500. fn draw_phone_select_handle(&self, mesh: &mut MeshBuilder, x: f32, side: f32) {
  501. debug!(target: "ui::editbox", "draw_phone_select_handle(..., {x}, {side})");
  502. let baseline = self.baseline.get();
  503. let select_ascent = self.select_ascent.get();
  504. let select_descent = self.select_descent.get();
  505. let color = self.text_hi_color.get();
  506. // Transparent for fade
  507. let mut color_trans = color.clone();
  508. color_trans[3] = 0.;
  509. // Vertical line downwards. We use this instead of draw_box() so we have a fade.
  510. let verts = vec![
  511. Vertex {
  512. pos: [x - side * 1., baseline - select_ascent],
  513. color: color_trans,
  514. uv: [0., 0.],
  515. },
  516. Vertex {
  517. pos: [x + side * 4., baseline - select_ascent],
  518. color: color_trans,
  519. uv: [0., 0.],
  520. },
  521. Vertex { pos: [x - side * 1., baseline + select_descent + 5.], color, uv: [0., 0.] },
  522. Vertex { pos: [x + side * 4., baseline + select_descent + 5.], color, uv: [0., 0.] },
  523. ];
  524. let indices = vec![0, 2, 1, 1, 2, 3];
  525. mesh.append(verts, indices);
  526. let y = baseline + select_descent;
  527. // The arrow itself.
  528. // Go anti-clockwise
  529. let verts = vec![
  530. Vertex { pos: [x, y], color, uv: [0., 0.] },
  531. Vertex { pos: [x, y + 50.], color, uv: [0., 0.] },
  532. Vertex { pos: [x + side * 30., y + 50.], color, uv: [0., 0.] },
  533. Vertex { pos: [x + side * 50., y + 25.], color, uv: [0., 0.] },
  534. ];
  535. let indices = vec![0, 1, 2, 0, 2, 3];
  536. mesh.append(verts, indices);
  537. }
  538. fn draw_underline(
  539. &self,
  540. mesh: &mut MeshBuilder,
  541. glyphs: &Vec<Glyph>,
  542. clip_h: f32,
  543. under_start: usize,
  544. under_end: usize,
  545. ) {
  546. assert!(under_start < under_end);
  547. let font_size = self.font_size.get();
  548. let window_scale = self.window_scale.get();
  549. let baseline = self.baseline.get();
  550. let scroll = self.scroll.get();
  551. let text_color = self.text_color.get();
  552. let glyph_pos_iter = GlyphPositionIter::new(font_size, window_scale, &glyphs, baseline);
  553. let mut start_x = 0.;
  554. let mut end_x = 0.;
  555. // When cursor lands at the end of the line
  556. let mut rhs = 0.;
  557. for (glyph_idx, mut glyph_rect) in glyph_pos_iter.enumerate() {
  558. glyph_rect.x -= scroll;
  559. if glyph_idx == under_start {
  560. start_x = glyph_rect.x;
  561. }
  562. if glyph_idx == under_end {
  563. end_x = glyph_rect.x;
  564. }
  565. rhs = glyph_rect.rhs();
  566. }
  567. if under_start == 0 {
  568. start_x = scroll;
  569. }
  570. if under_end == glyphs.len() {
  571. end_x = rhs;
  572. }
  573. // We don't need to do manual clipping since MeshBuilder should do that
  574. let underline_rect = Rectangle { x: start_x, y: baseline + 6., w: end_x - start_x, h: 4. };
  575. mesh.draw_box(&underline_rect, text_color, &Rectangle::zero());
  576. }
  577. async fn change_focus(self: Arc<Self>) {
  578. if !self.is_active.get() {
  579. return
  580. }
  581. debug!(target: "ui::editbox", "Focus changed");
  582. // Cursor visibility will change so just redraw everything lol
  583. self.redraw().await;
  584. }
  585. async fn insert_char(&self, key: char) {
  586. {
  587. let mut editable = self.editable.lock().unwrap();
  588. let mut tmp = [0; 4];
  589. let key_str = key.encode_utf8(&mut tmp);
  590. editable.compose(key_str, true);
  591. }
  592. self.pause_blinking();
  593. self.redraw().await;
  594. }
  595. async fn handle_shortcut(&self, key: char, mods: &KeyMods) {
  596. debug!(target: "ui::editbox", "handle_shortcut({:?}, {:?})", key, mods);
  597. match key {
  598. 'c' => {
  599. if mods.ctrl {
  600. self.copy_highlighted().unwrap();
  601. }
  602. }
  603. 'v' => {
  604. if mods.ctrl {
  605. if let Some(text) = window::clipboard_get() {
  606. self.paste_text(text).await;
  607. }
  608. }
  609. }
  610. _ => {}
  611. }
  612. }
  613. async fn handle_key(&self, key: &KeyCode, mods: &KeyMods) {
  614. debug!(target: "ui::editbox", "handle_key({:?}, {:?})", key, mods);
  615. match key {
  616. KeyCode::Left => {
  617. self.adjust_cursor(mods.shift, |editable| editable.move_cursor(-1));
  618. self.pause_blinking();
  619. //self.apply_cursor_scrolling();
  620. self.redraw().await;
  621. }
  622. KeyCode::Right => {
  623. self.adjust_cursor(mods.shift, |editable| editable.move_cursor(1));
  624. self.pause_blinking();
  625. //self.apply_cursor_scrolling();
  626. self.redraw().await;
  627. }
  628. KeyCode::Kp0 => self.insert_char('0').await,
  629. KeyCode::Kp1 => self.insert_char('1').await,
  630. KeyCode::Kp2 => self.insert_char('2').await,
  631. KeyCode::Kp3 => self.insert_char('3').await,
  632. KeyCode::Kp4 => self.insert_char('4').await,
  633. KeyCode::Kp5 => self.insert_char('5').await,
  634. KeyCode::Kp6 => self.insert_char('6').await,
  635. KeyCode::Kp7 => self.insert_char('7').await,
  636. KeyCode::Kp8 => self.insert_char('8').await,
  637. KeyCode::Kp9 => self.insert_char('9').await,
  638. KeyCode::KpDecimal => self.insert_char('.').await,
  639. KeyCode::Enter | KeyCode::KpEnter => {
  640. let node = self.node.upgrade().unwrap();
  641. node.trigger("enter_pressed", vec![]).await.unwrap();
  642. }
  643. KeyCode::Delete => {
  644. self.delete(0, 1);
  645. self.pause_blinking();
  646. self.redraw().await;
  647. }
  648. KeyCode::Backspace => {
  649. self.delete(1, 0);
  650. self.pause_blinking();
  651. self.redraw().await;
  652. }
  653. KeyCode::Home => {
  654. self.adjust_cursor(mods.shift, |editable| editable.move_start());
  655. self.pause_blinking();
  656. //self.apply_cursor_scrolling();
  657. self.redraw().await;
  658. }
  659. KeyCode::End => {
  660. self.adjust_cursor(mods.shift, |editable| editable.move_end());
  661. self.pause_blinking();
  662. //self.apply_cursor_scrolling();
  663. self.redraw().await;
  664. }
  665. _ => {}
  666. }
  667. }
  668. fn delete(&self, before: usize, after: usize) {
  669. let mut editable = self.editable.lock().unwrap();
  670. let selection = std::mem::take(&mut *self.select.lock().unwrap());
  671. if selection.is_empty() {
  672. editable.delete(before, after);
  673. return
  674. }
  675. let sel = selection.first().unwrap();
  676. let cursor_pos = std::cmp::min(sel.start, sel.end);
  677. let render = editable.render();
  678. let mut before_text = String::new();
  679. let mut after_text = String::new();
  680. 'next: for (pos, glyph) in render.glyphs.iter().enumerate() {
  681. for select in &selection {
  682. let start = std::cmp::min(select.start, select.end);
  683. let end = std::cmp::max(select.start, select.end);
  684. if start <= pos && pos < end {
  685. continue 'next
  686. }
  687. }
  688. if pos <= cursor_pos {
  689. before_text += &glyph.substr;
  690. } else {
  691. after_text += &glyph.substr;
  692. }
  693. }
  694. editable.set_text(before_text, after_text);
  695. self.is_phone_select.store(false, Ordering::Relaxed);
  696. // Reshow cursor (if hidden)
  697. self.hide_cursor.store(false, Ordering::Relaxed);
  698. }
  699. fn adjust_cursor(&self, has_shift: bool, move_cursor: impl Fn(&mut Editable)) {
  700. let mut editable = self.editable.lock().unwrap();
  701. let rendered = editable.render();
  702. let prev_cursor_pos = editable.get_cursor_pos(&rendered);
  703. move_cursor(&mut editable);
  704. let cursor_pos = editable.get_cursor_pos(&rendered);
  705. drop(editable);
  706. let mut select = self.select.lock().unwrap();
  707. // Start selection if shift is held
  708. if has_shift {
  709. // Create a new selection
  710. if select.is_empty() {
  711. select.push(Selection::new(prev_cursor_pos, cursor_pos));
  712. }
  713. // Update the selection
  714. select.last_mut().unwrap().end = cursor_pos;
  715. } else {
  716. select.clear();
  717. }
  718. }
  719. /// This will select the entire word rather than move the cursor to that location
  720. fn start_touch_select(&self, x: f32) {
  721. let rect = self.rect.get();
  722. let font_size = self.font_size.get();
  723. let window_scale = self.window_scale.get();
  724. let baseline = self.baseline.get();
  725. {
  726. let mut editable = self.editable.lock().unwrap();
  727. editable.end_compose();
  728. let rendered = editable.render();
  729. // Adjust with scroll here too
  730. let x = x - rect.x;
  731. let cpos = rendered.x_to_pos(x, font_size, window_scale, baseline);
  732. // Find word start
  733. let mut cpos_start = cpos;
  734. while cpos_start > 0 {
  735. // Is the glyph before this pos just whitespace?
  736. let glyph_str = &rendered.glyphs[cpos_start - 1].substr;
  737. if is_whitespace(glyph_str) {
  738. break
  739. }
  740. cpos_start -= 1;
  741. }
  742. // Find word end
  743. let mut cpos_end = cpos;
  744. while cpos_end < rendered.glyphs.len() {
  745. cpos_end += 1;
  746. let glyph_str = &rendered.glyphs[cpos_end].substr;
  747. if is_whitespace(glyph_str) {
  748. break
  749. }
  750. }
  751. let cidx_start = rendered.pos_to_idx(cpos_start);
  752. let cidx_end = rendered.pos_to_idx(cpos_end);
  753. // begin selection
  754. let mut select = self.select.lock().unwrap();
  755. select.clear();
  756. select.push(Selection::new(cpos_start, cpos_end));
  757. }
  758. self.is_phone_select.store(true, Ordering::Relaxed);
  759. // redraw() will now hide the cursor
  760. self.hide_cursor.store(true, Ordering::Relaxed);
  761. }
  762. fn glyphs_to_string(glyphs: &Vec<Glyph>) -> String {
  763. let mut text = String::new();
  764. for (i, glyph) in glyphs.iter().enumerate() {
  765. text.push_str(&glyph.substr);
  766. }
  767. text
  768. }
  769. fn delete_highlighted(&self) {
  770. assert!(!self.selected.is_null(0).unwrap());
  771. assert!(!self.selected.is_null(1).unwrap());
  772. let start = self.selected.get_u32(0).unwrap() as usize;
  773. let end = self.selected.get_u32(1).unwrap() as usize;
  774. let sel_start = std::cmp::min(start, end);
  775. let sel_end = std::cmp::max(start, end);
  776. let mut glyphs = self.glyphs.lock().unwrap().clone();
  777. glyphs.drain(sel_start..sel_end);
  778. let text = Self::glyphs_to_string(&glyphs);
  779. debug!(
  780. target: "ui::editbox",
  781. "delete_highlighted() text=\"{}\", cursor_pos={}",
  782. text, sel_start
  783. );
  784. self.text.set(text);
  785. self.selected.set_null(Role::Internal, 0).unwrap();
  786. self.selected.set_null(Role::Internal, 1).unwrap();
  787. self.cursor_pos.set(sel_start as u32);
  788. }
  789. fn copy_highlighted(&self) -> Result<()> {
  790. let start = self.selected.get_u32(0)? as usize;
  791. let end = self.selected.get_u32(1)? as usize;
  792. let sel_start = std::cmp::min(start, end);
  793. let sel_end = std::cmp::max(start, end);
  794. let mut text = String::new();
  795. let glyphs = self.glyphs.lock().unwrap().clone();
  796. for (glyph_idx, glyph) in glyphs.iter().enumerate() {
  797. if sel_start <= glyph_idx && glyph_idx < sel_end {
  798. text.push_str(&glyph.substr);
  799. }
  800. }
  801. info!(target: "ui::editbox", "Copied '{}'", text);
  802. window::clipboard_set(&text);
  803. Ok(())
  804. }
  805. async fn paste_text(&self, key: String) {
  806. let mut text = String::new();
  807. let cursor_pos = self.cursor_pos.get();
  808. if cursor_pos == 0 {
  809. text = key.clone();
  810. }
  811. let glyphs = self.glyphs.lock().unwrap().clone();
  812. for (glyph_idx, glyph) in glyphs.iter().enumerate() {
  813. text.push_str(&glyph.substr);
  814. if cursor_pos == glyph_idx as u32 + 1 {
  815. text.push_str(&key);
  816. }
  817. }
  818. self.text.set(text);
  819. // Not always true lol
  820. self.cursor_pos.set(cursor_pos + 1);
  821. self.apply_cursor_scrolling();
  822. self.redraw().await;
  823. }
  824. async fn handle_touch_start(&self, pos: Point) -> bool {
  825. debug!(target: "ui::editbox", "handle_touch_start({pos:?})");
  826. let mut touch_info = self.touch_info.lock().unwrap();
  827. if self.try_handle_drag(&mut touch_info, pos) {
  828. return true
  829. }
  830. let rect = self.rect.get();
  831. if !rect.contains(pos) {}
  832. touch_info.start(pos);
  833. true
  834. }
  835. fn try_handle_drag(&self, touch_info: &mut TouchInfo, pos: Point) -> bool {
  836. let selections = self.select.lock().unwrap().clone();
  837. if self.is_phone_select.load(Ordering::Relaxed) && selections.len() == 1 {
  838. let select = selections.first().unwrap();
  839. let rendered = {
  840. let editable = self.editable.lock().unwrap();
  841. editable.render()
  842. };
  843. let font_size = self.font_size.get();
  844. let window_scale = self.window_scale.get();
  845. let baseline = self.baseline.get();
  846. // Get left handle centerpoint
  847. let x1 = rendered.pos_to_xw(select.start, font_size, window_scale, baseline).0;
  848. // Get right handle centerpoint
  849. let x2 = {
  850. let (x, w) = rendered.pos_to_xw(select.end, font_size, window_scale, baseline);
  851. x + w
  852. };
  853. // Are we within range of either one?
  854. let select_descent = self.select_descent.get();
  855. let y = baseline + select_descent + 25.;
  856. let p1 = Point::new(x1, y);
  857. let p2 = Point::new(x2, y);
  858. debug!(target: "ui::editbox", "handle center points = ({p1:?}, {p2:?})");
  859. const TOUCH_RADIUS_SQ: f32 = 10_000.;
  860. // Make pos relative to the rect
  861. let pos_rel = pos - self.rect.get().pos();
  862. if p1.dist_sq(&pos_rel) <= TOUCH_RADIUS_SQ {
  863. debug!(target: "ui::editbox", "TouchStateAction::DragSelectHandle [side=-1]");
  864. // Set touch_state status to enable begin dragging them
  865. touch_info.state = TouchStateAction::DragSelectHandle { side: -1 };
  866. return true;
  867. }
  868. if p2.dist_sq(&pos_rel) <= TOUCH_RADIUS_SQ {
  869. debug!(target: "ui::editbox", "TouchStateAction::DragSelectHandle [side=1]");
  870. // Set touch_state status to enable begin dragging them
  871. touch_info.state = TouchStateAction::DragSelectHandle { side: 1 };
  872. return true;
  873. }
  874. }
  875. false
  876. }
  877. async fn handle_touch_move(&self, pos: Point) -> bool {
  878. //debug!(target: "ui::editbox", "handle_touch_move({pos:?})");
  879. let touch_state = {
  880. let mut touch_info = self.touch_info.lock().unwrap();
  881. touch_info.update(&pos);
  882. touch_info.state.clone()
  883. };
  884. match &touch_state {
  885. TouchStateAction::Inactive => return false,
  886. TouchStateAction::StartSelect => {
  887. let x = pos.x;
  888. self.start_touch_select(x);
  889. self.redraw().await;
  890. debug!(target: "ui::editbox", "TouchStateAction::Select");
  891. self.touch_info.lock().unwrap().state = TouchStateAction::Select;
  892. }
  893. TouchStateAction::DragSelectHandle { side } => {
  894. {
  895. assert!(*side == -1 || *side == 1);
  896. assert!(self.is_phone_select.load(Ordering::Relaxed));
  897. let mut selections = self.select.lock().unwrap();
  898. assert_eq!(selections.len(), 1);
  899. let select = selections.first_mut().unwrap();
  900. let rendered = {
  901. let editable = self.editable.lock().unwrap();
  902. editable.render()
  903. };
  904. let font_size = self.font_size.get();
  905. let window_scale = self.window_scale.get();
  906. let baseline = self.baseline.get();
  907. let mut pos = rendered.x_to_pos(pos.x, font_size, window_scale, baseline);
  908. if *side == -1 {
  909. let select_other_pos = &mut select.end;
  910. if pos >= *select_other_pos {
  911. pos = *select_other_pos - 1;
  912. }
  913. select.start = pos;
  914. } else {
  915. let select_other_pos = &mut select.start;
  916. if pos <= *select_other_pos {
  917. pos = *select_other_pos + 1;
  918. }
  919. select.end = pos;
  920. }
  921. }
  922. self.redraw().await;
  923. }
  924. _ => {}
  925. }
  926. true
  927. }
  928. async fn handle_touch_end(&self, pos: Point) -> bool {
  929. debug!(target: "ui::editbox", "handle_touch_end({pos:?})");
  930. let state = self.touch_info.lock().unwrap().stop();
  931. match state {
  932. TouchStateAction::Inactive => return false,
  933. TouchStateAction::Started { pos: _, instant: _ } => {
  934. let rect = self.rect.get();
  935. let font_size = self.font_size.get();
  936. let window_scale = self.window_scale.get();
  937. let baseline = self.baseline.get();
  938. {
  939. let mut editable = self.editable.lock().unwrap();
  940. let rendered = editable.render();
  941. // Adjust with scroll here too
  942. let x = pos.x - rect.x;
  943. let cpos = rendered.x_to_pos(x, font_size, window_scale, baseline);
  944. let cidx = rendered.pos_to_idx(cpos);
  945. editable.set_cursor_idx(cidx);
  946. // begin selection
  947. let mut select = self.select.lock().unwrap();
  948. select.clear();
  949. }
  950. self.is_phone_select.store(false, Ordering::Relaxed);
  951. // Reshow cursor (if hidden)
  952. self.hide_cursor.store(false, Ordering::Relaxed);
  953. self.redraw().await;
  954. }
  955. _ => {}
  956. }
  957. window::show_keyboard(true);
  958. true
  959. }
  960. /// Whenever the cursor property is modified this MUST be called
  961. /// to recalculate the scroll x property.
  962. fn apply_cursor_scrolling(&self) {
  963. let rect = self.rect.get();
  964. let cursor_pos = self.cursor_pos.get() as usize;
  965. let cursor_width = self.cursor_width.get();
  966. let mut scroll = self.scroll.get();
  967. let cursor_x = {
  968. let font_size = self.font_size.get();
  969. let window_scale = self.window_scale.get();
  970. let baseline = self.baseline.get();
  971. let glyphs = self.glyphs.lock().unwrap().clone();
  972. let mut glyph_pos_iter =
  973. GlyphPositionIter::new(font_size, window_scale, &glyphs, baseline);
  974. if cursor_pos == 0 {
  975. 0.
  976. } else if cursor_pos == glyphs.len() {
  977. let glyph_pos = glyph_pos_iter.last().unwrap();
  978. let rhs = glyph_pos.rhs() + eol_nudge(font_size, &glyphs);
  979. rhs
  980. } else {
  981. assert!(cursor_pos < glyphs.len());
  982. let glyph_pos = glyph_pos_iter.nth(cursor_pos).expect("glyph pos mismatch glyphs");
  983. glyph_pos.x
  984. }
  985. };
  986. // The LHS and RHS of the cursor box
  987. let cursor_lhs = cursor_x - scroll;
  988. let cursor_rhs = cursor_lhs + cursor_width;
  989. // RHS is outside
  990. if cursor_rhs > rect.w {
  991. // We want a scroll so RHS = w
  992. // cursor_x - scroll + CURSOR_WIDTH = rect.w
  993. scroll = cursor_x + cursor_width - rect.w;
  994. // LHS is negative
  995. } else if cursor_lhs < 0. {
  996. // We want scroll so LHS = 0
  997. // cursor_x - scroll = 0
  998. scroll = cursor_x;
  999. }
  1000. self.scroll.set(scroll);
  1001. }
  1002. fn pause_blinking(&self) {
  1003. self.blink_is_paused.store(true, Ordering::Relaxed);
  1004. self.cursor_is_visible.store(true, Ordering::Relaxed);
  1005. }
  1006. async fn redraw(&self) {
  1007. let Some(draw_update) = self.draw_cached() else {
  1008. error!(target: "ui::editbox", "Text failed to draw");
  1009. return;
  1010. };
  1011. self.render_api.replace_draw_calls(draw_update.draw_calls);
  1012. }
  1013. fn redraw_cursor(&self) {
  1014. let cursor_instrs = self.get_cursor_instrs();
  1015. let draw_calls = vec![(
  1016. self.cursor_dc_key,
  1017. GfxDrawCall { instrs: cursor_instrs, dcs: vec![], z_index: self.z_index.get() },
  1018. )];
  1019. self.render_api.replace_draw_calls(draw_calls);
  1020. }
  1021. fn get_cursor_instrs(&self) -> Vec<GfxDrawInstruction> {
  1022. if !self.is_focused.get() ||
  1023. !self.cursor_is_visible.load(Ordering::Relaxed) ||
  1024. self.hide_cursor.load(Ordering::Relaxed)
  1025. {
  1026. return vec![]
  1027. }
  1028. let mut cursor_instrs = vec![];
  1029. let mut cursor_pos = Point::zero();
  1030. cursor_pos.x += self.cursor_px_offset();
  1031. cursor_instrs.push(GfxDrawInstruction::Move(cursor_pos));
  1032. let cursor_mesh = {
  1033. let mut cursor_mesh = self.cursor_mesh.lock().unwrap();
  1034. if cursor_mesh.is_none() {
  1035. *cursor_mesh = Some(self.regen_cursor_mesh());
  1036. }
  1037. cursor_mesh.clone().unwrap()
  1038. };
  1039. cursor_instrs.push(GfxDrawInstruction::Draw(cursor_mesh));
  1040. cursor_instrs
  1041. }
  1042. fn draw_cached(&self) -> Option<DrawUpdate> {
  1043. let rect = self.rect.get();
  1044. let text_mesh = self.regen_text_mesh(rect.clone());
  1045. let cursor_instrs = self.get_cursor_instrs();
  1046. Some(DrawUpdate {
  1047. key: self.text_dc_key,
  1048. draw_calls: vec![
  1049. (
  1050. self.text_dc_key,
  1051. GfxDrawCall {
  1052. instrs: vec![
  1053. GfxDrawInstruction::Move(rect.pos()),
  1054. GfxDrawInstruction::Draw(text_mesh),
  1055. ],
  1056. dcs: vec![self.cursor_dc_key],
  1057. z_index: self.z_index.get(),
  1058. },
  1059. ),
  1060. (
  1061. self.cursor_dc_key,
  1062. GfxDrawCall { instrs: cursor_instrs, dcs: vec![], z_index: self.z_index.get() },
  1063. ),
  1064. ],
  1065. })
  1066. }
  1067. }
  1068. impl Drop for EditBox {
  1069. fn drop(&mut self) {
  1070. self.render_api.replace_draw_calls(vec![(self.text_dc_key, Default::default())]);
  1071. }
  1072. }
  1073. #[async_trait]
  1074. impl UIObject for EditBox {
  1075. fn z_index(&self) -> u32 {
  1076. self.z_index.get()
  1077. }
  1078. async fn start(self: Arc<Self>, ex: ExecutorPtr) {
  1079. let me = Arc::downgrade(&self);
  1080. let node_ref = &self.node.upgrade().unwrap();
  1081. let node_name = node_ref.name.clone();
  1082. let node_id = node_ref.id;
  1083. let mut on_modify = OnModify::new(ex.clone(), node_name, node_id, me.clone());
  1084. on_modify.when_change(self.is_focused.prop(), Self::change_focus);
  1085. // When text has been changed.
  1086. // Cursor and selection might be invalidated.
  1087. async fn reset(self_: Arc<EditBox>) {
  1088. self_.cursor_pos.set(0);
  1089. self_.selected.set_null(Role::Internal, 0).unwrap();
  1090. self_.selected.set_null(Role::Internal, 1).unwrap();
  1091. self_.scroll.set(0.);
  1092. self_.redraw();
  1093. }
  1094. async fn redraw(self_: Arc<EditBox>) {
  1095. self_.redraw();
  1096. }
  1097. on_modify.when_change(self.rect.prop(), redraw);
  1098. on_modify.when_change(self.baseline.prop(), redraw);
  1099. // The commented properties are modified on input events
  1100. // So then redraw() will get repeatedly triggered when these properties
  1101. // are changed. We should find a solution. For now the hooks are disabled.
  1102. //on_modify.when_change(scroll.prop(), redraw);
  1103. //on_modify.when_change(cursor_pos.prop(), redraw);
  1104. on_modify.when_change(self.font_size.prop(), redraw);
  1105. // We must also reshape text
  1106. on_modify.when_change(self.text.prop(), reset);
  1107. on_modify.when_change(self.text_color.prop(), redraw);
  1108. on_modify.when_change(self.hi_bg_color.prop(), redraw);
  1109. //on_modify.when_change(selected.clone(), redraw);
  1110. on_modify.when_change(self.z_index.prop(), redraw);
  1111. on_modify.when_change(self.debug.prop(), redraw);
  1112. async fn regen_cursor(self_: Arc<EditBox>) {
  1113. let mesh = std::mem::take(&mut *self_.cursor_mesh.lock().unwrap());
  1114. }
  1115. on_modify.when_change(self.cursor_color.prop(), regen_cursor);
  1116. on_modify.when_change(self.cursor_ascent.prop(), regen_cursor);
  1117. on_modify.when_change(self.cursor_descent.prop(), regen_cursor);
  1118. on_modify.when_change(self.cursor_width.prop(), regen_cursor);
  1119. let me2 = me.clone();
  1120. let cursor_blink_time = self.cursor_blink_time.clone();
  1121. let cursor_idle_time = self.cursor_idle_time.clone();
  1122. let blinking_cursor_task = ex.spawn(async move {
  1123. loop {
  1124. msleep(cursor_blink_time.get() as u64).await;
  1125. let self_ = me2.upgrade().unwrap();
  1126. if self_.blink_is_paused.swap(false, Ordering::Relaxed) {
  1127. msleep(cursor_idle_time.get() as u64).await;
  1128. continue
  1129. }
  1130. // Invert the bool
  1131. self_.cursor_is_visible.fetch_not(Ordering::Relaxed);
  1132. self_.redraw_cursor();
  1133. }
  1134. });
  1135. let mut tasks = on_modify.tasks;
  1136. tasks.push(blinking_cursor_task);
  1137. self.tasks.set(tasks);
  1138. }
  1139. async fn draw(&self, parent_rect: Rectangle) -> Option<DrawUpdate> {
  1140. debug!(target: "ui::editbox", "EditBox::draw()");
  1141. *self.parent_rect.lock().unwrap() = Some(parent_rect);
  1142. self.rect.eval(&parent_rect).ok()?;
  1143. self.draw_cached()
  1144. }
  1145. async fn handle_char(&self, key: char, mods: KeyMods, repeat: bool) -> bool {
  1146. // First filter for only single digit keys
  1147. if DISALLOWED_CHARS.contains(&key) {
  1148. return false
  1149. }
  1150. if !self.is_focused.get() {
  1151. return false
  1152. }
  1153. if mods.ctrl || mods.alt {
  1154. if repeat {
  1155. return false
  1156. }
  1157. self.handle_shortcut(key, &mods).await;
  1158. return true
  1159. }
  1160. let actions = {
  1161. let mut repeater = self.key_repeat.lock().unwrap();
  1162. repeater.key_down(PressedKey::Char(key), repeat)
  1163. };
  1164. //debug!(target: "ui::editbox", "Key {:?} has {} actions", key, actions);
  1165. for _ in 0..actions {
  1166. self.insert_char(key).await;
  1167. }
  1168. true
  1169. }
  1170. async fn handle_key_down(&self, key: KeyCode, mods: KeyMods, repeat: bool) -> bool {
  1171. // First filter for only single digit keys
  1172. // Avoid processing events handled by insert_char()
  1173. if !ALLOWED_KEYCODES.contains(&key) {
  1174. return false
  1175. }
  1176. if !self.is_focused.get() {
  1177. return false
  1178. }
  1179. let actions = {
  1180. let mut repeater = self.key_repeat.lock().unwrap();
  1181. repeater.key_down(PressedKey::Key(key), repeat)
  1182. };
  1183. // Suppress noisy message
  1184. /*if actions > 0 {
  1185. debug!(target: "ui::editbox", "Key {:?} has {} actions", key, actions);
  1186. }*/
  1187. for _ in 0..actions {
  1188. self.handle_key(&key, &mods).await;
  1189. }
  1190. true
  1191. }
  1192. async fn handle_mouse_btn_down(&self, btn: MouseButton, mouse_pos: Point) -> bool {
  1193. if !self.is_active.get() {
  1194. return false
  1195. }
  1196. if btn != MouseButton::Left {
  1197. return false
  1198. }
  1199. let rect = self.rect.get();
  1200. // clicking inside box will:
  1201. // 1. make it active
  1202. // 2. begin selection
  1203. if !rect.contains(mouse_pos) {
  1204. if self.is_focused.get() {
  1205. debug!(target: "ui::editbox", "EditBox unfocused");
  1206. self.is_focused.set(false);
  1207. self.select.lock().unwrap().clear();
  1208. self.redraw().await;
  1209. }
  1210. return false
  1211. }
  1212. if self.is_focused.get() {
  1213. debug!(target: "ui::editbox", "EditBox clicked");
  1214. } else {
  1215. debug!(target: "ui::editbox", "EditBox focused");
  1216. self.is_focused.set(true);
  1217. }
  1218. let font_size = self.font_size.get();
  1219. let window_scale = self.window_scale.get();
  1220. let baseline = self.baseline.get();
  1221. {
  1222. let mut editable = self.editable.lock().unwrap();
  1223. let rendered = editable.render();
  1224. // Adjust with scroll here too
  1225. let x = mouse_pos.x - rect.x;
  1226. let cpos = rendered.x_to_pos(x, font_size, window_scale, baseline);
  1227. let cidx = rendered.pos_to_idx(cpos);
  1228. editable.set_cursor_idx(cidx);
  1229. // begin selection
  1230. let mut select = self.select.lock().unwrap();
  1231. select.clear();
  1232. select.push(Selection::new(cpos, cpos));
  1233. self.mouse_btn_held.store(true, Ordering::Relaxed);
  1234. }
  1235. self.pause_blinking();
  1236. self.redraw().await;
  1237. true
  1238. }
  1239. async fn handle_mouse_btn_up(&self, btn: MouseButton, mouse_pos: Point) -> bool {
  1240. if !self.is_active.get() {
  1241. return false
  1242. }
  1243. // releasing mouse button will end selection
  1244. self.mouse_btn_held.store(false, Ordering::Relaxed);
  1245. false
  1246. }
  1247. async fn handle_mouse_move(&self, mouse_pos: Point) -> bool {
  1248. if !self.is_active.get() {
  1249. return false
  1250. }
  1251. if !self.mouse_btn_held.load(Ordering::Relaxed) {
  1252. return false;
  1253. }
  1254. // if active and selection_active, then use x to modify the selection.
  1255. // also implement scrolling when cursor is to the left or right
  1256. // just scroll to the end
  1257. // also set cursor_pos too
  1258. let rect = self.rect.get();
  1259. let font_size = self.font_size.get();
  1260. let window_scale = self.window_scale.get();
  1261. let baseline = self.baseline.get();
  1262. {
  1263. let mut editable = self.editable.lock().unwrap();
  1264. let rendered = editable.render();
  1265. // Adjust with scroll here too
  1266. let x = mouse_pos.x - rect.x;
  1267. let cpos = rendered.x_to_pos(x, font_size, window_scale, baseline);
  1268. let cidx = rendered.pos_to_idx(cpos);
  1269. editable.set_cursor_idx(cidx);
  1270. // begin selection
  1271. let mut select = self.select.lock().unwrap();
  1272. select.last_mut().unwrap().end = cpos;
  1273. }
  1274. self.pause_blinking();
  1275. //self.apply_cursor_scrolling();
  1276. self.redraw().await;
  1277. false
  1278. }
  1279. async fn handle_touch(&self, phase: TouchPhase, id: u64, touch_pos: Point) -> bool {
  1280. if !self.is_active.get() {
  1281. return false
  1282. }
  1283. // Ignore multi-touch
  1284. if id != 0 {
  1285. return false
  1286. }
  1287. match phase {
  1288. TouchPhase::Started => self.handle_touch_start(touch_pos).await,
  1289. TouchPhase::Moved => self.handle_touch_move(touch_pos).await,
  1290. TouchPhase::Ended => self.handle_touch_end(touch_pos).await,
  1291. TouchPhase::Cancelled => false,
  1292. }
  1293. }
  1294. async fn handle_compose_text(&self, suggest_text: &str, is_commit: bool) -> bool {
  1295. debug!(target: "ui::editbox", "handle_compose_text({suggest_text}, {is_commit})");
  1296. if !self.is_active.get() {
  1297. return false
  1298. }
  1299. {
  1300. let mut editable = self.editable.lock().unwrap();
  1301. editable.compose(suggest_text, is_commit);
  1302. }
  1303. //self.apply_cursor_scrolling();
  1304. self.redraw().await;
  1305. true
  1306. }
  1307. async fn handle_set_compose_region(&self, start: usize, end: usize) -> bool {
  1308. debug!(target: "ui::editbox", "handle_set_compose_region({start}, {end})");
  1309. if !self.is_active.get() {
  1310. return false
  1311. }
  1312. {
  1313. let mut editable = self.editable.lock().unwrap();
  1314. editable.set_compose_region(start, end);
  1315. }
  1316. self.redraw().await;
  1317. true
  1318. }
  1319. }
  1320. /// Filter these char events from being handled since we handle them
  1321. /// using the key_up/key_down events.
  1322. /// Avoids duplicate processing of keyboard input events.
  1323. static DISALLOWED_CHARS: &'static [char] = &['\r', '\u{8}', '\u{7f}', '\t', '\n'];
  1324. /// These keycodes are handled via normal key_up/key_down events.
  1325. /// Anything in this list must be disallowed char events.
  1326. static ALLOWED_KEYCODES: &'static [KeyCode] = &[
  1327. KeyCode::Left,
  1328. KeyCode::Right,
  1329. KeyCode::Up,
  1330. KeyCode::Down,
  1331. KeyCode::Enter,
  1332. KeyCode::Kp0,
  1333. KeyCode::Kp1,
  1334. KeyCode::Kp2,
  1335. KeyCode::Kp3,
  1336. KeyCode::Kp4,
  1337. KeyCode::Kp5,
  1338. KeyCode::Kp6,
  1339. KeyCode::Kp7,
  1340. KeyCode::Kp8,
  1341. KeyCode::Kp9,
  1342. KeyCode::KpDecimal,
  1343. KeyCode::KpEnter,
  1344. KeyCode::Delete,
  1345. KeyCode::Backspace,
  1346. KeyCode::Home,
  1347. KeyCode::End,
  1348. ];
  1349. /*
  1350. impl Stoppable for EditBox {
  1351. async fn stop(&self) {
  1352. // TODO: Delete own draw call
  1353. // Free buffers
  1354. // Should this be in drop?
  1355. //self.render_api.delete_buffer(self.vertex_buffer);
  1356. //self.render_api.delete_buffer(self.index_buffer);
  1357. }
  1358. }
  1359. */