editbox.rs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796
  1. use miniquad::{KeyMods, UniformType, MouseButton, window};
  2. use log::{debug, info};
  3. use std::{
  4. collections::HashMap,
  5. io::Cursor, sync::{Arc, atomic::{AtomicBool, Ordering}, Mutex}, time::{Instant, Duration}};
  6. use darkfi_serial::Decodable;
  7. use freetype as ft;
  8. use crate::{error::{Error, Result}, prop::{
  9. PropertyBool, PropertyFloat32, PropertyUint32, PropertyStr, PropertyColor,
  10. Property}, scene::{SceneGraph, SceneNode, SceneNodeId, Pimpl, Slot}, gfx::{Rectangle, RenderContext, COLOR_WHITE, COLOR_BLUE, COLOR_RED, COLOR_GREEN, FreetypeFace, COLOR_DARKGREY, Point}, text::{Glyph, TextShaper}, keysym::{MouseButtonAsU8, KeyCodeAsU16}};
  11. const CURSOR_WIDTH: f32 = 4.;
  12. struct PressedKeysSmoothRepeat {
  13. /// When holding keys, we track from start and last sent time.
  14. /// This is useful for initial delay and smooth scrolling.
  15. pressed_keys: HashMap<String, RepeatingKeyTimer>,
  16. /// Initial delay before allowing keys
  17. start_delay: u32,
  18. /// Minimum time between repeated keys
  19. step_time: u32,
  20. }
  21. impl PressedKeysSmoothRepeat {
  22. fn new(start_delay: u32, step_time: u32) -> Self {
  23. Self {
  24. pressed_keys: HashMap::new(),
  25. start_delay,
  26. step_time
  27. }
  28. }
  29. fn key_down(&mut self, key: &str, repeat: bool) -> u32 {
  30. if !repeat {
  31. return 1;
  32. }
  33. // Insert key if not exists
  34. if !self.pressed_keys.contains_key(key) {
  35. self.pressed_keys.insert(key.to_string(), RepeatingKeyTimer::new());
  36. }
  37. let repeater = self.pressed_keys.get_mut(key).expect("repeat map");
  38. repeater.update(self.start_delay, self.step_time)
  39. }
  40. fn key_up(&mut self, key: &str) {
  41. self.pressed_keys.remove(key);
  42. }
  43. }
  44. struct RepeatingKeyTimer {
  45. start: Instant,
  46. actions: u32,
  47. }
  48. impl RepeatingKeyTimer {
  49. fn new() -> Self {
  50. Self {
  51. start: Instant::now(),
  52. actions: 0
  53. }
  54. }
  55. fn update(&mut self, start_delay: u32, step_time: u32) -> u32 {
  56. let elapsed = self.start.elapsed().as_millis();
  57. if elapsed < start_delay as u128 {
  58. return 0
  59. }
  60. let total_actions = ((elapsed - start_delay as u128) / step_time as u128) as u32;
  61. let remaining_actions = total_actions - self.actions;
  62. self.actions = total_actions;
  63. remaining_actions
  64. }
  65. }
  66. pub type EditBoxPtr = Arc<EditBox>;
  67. pub struct EditBox {
  68. node_name: String,
  69. is_active: PropertyBool,
  70. debug: PropertyBool,
  71. baseline: PropertyFloat32,
  72. scroll: PropertyFloat32,
  73. cursor_pos: PropertyUint32,
  74. selected: Arc<Property>,
  75. text: PropertyStr,
  76. font_size: PropertyFloat32,
  77. text_color: PropertyColor,
  78. cursor_color: PropertyColor,
  79. hi_bg_color: PropertyColor,
  80. // Used for mouse clicks
  81. world_rect: Mutex<Rectangle<f32>>,
  82. glyphs: Mutex<Vec<Glyph>>,
  83. text_shaper: TextShaper,
  84. key_repeat: Mutex<PressedKeysSmoothRepeat>,
  85. mouse_btn_held: AtomicBool,
  86. window_scale: f32,
  87. }
  88. impl EditBox {
  89. pub fn new(scene_graph: &mut SceneGraph, node_id: SceneNodeId, font_faces: Vec<FreetypeFace>) -> Result<Pimpl> {
  90. let node = scene_graph.get_node(node_id).unwrap();
  91. let node_name = node.name.clone();
  92. let is_active = PropertyBool::wrap(node, "is_active", 0)?;
  93. let debug = PropertyBool::wrap(node, "debug", 0)?;
  94. let baseline = PropertyFloat32::wrap(node, "baseline", 0)?;
  95. let scroll = PropertyFloat32::wrap(node, "scroll", 0)?;
  96. let cursor_pos = PropertyUint32::wrap(node, "cursor_pos", 0)?;
  97. let selected = node.get_property("selected").ok_or(Error::PropertyNotFound)?;
  98. let text = PropertyStr::wrap(node, "text", 0)?;
  99. let font_size = PropertyFloat32::wrap(node, "font_size", 0)?;
  100. let text_color = PropertyColor::wrap(node, "text_color")?;
  101. let cursor_color = PropertyColor::wrap(node, "cursor_color")?;
  102. let hi_bg_color = PropertyColor::wrap(node, "hi_bg_color")?;
  103. let text_shaper = TextShaper {
  104. font_faces
  105. };
  106. // TODO: catch window resize event and regen glyphs
  107. // Used for scaling the font size
  108. let window =
  109. scene_graph
  110. .lookup_node("/window")
  111. .expect("no window attached!");
  112. let window_scale = window.get_property_f32("scale")?;
  113. let self_ = Arc::new(Self{
  114. node_name: node_name.clone(),
  115. is_active,
  116. debug,
  117. baseline,
  118. scroll,
  119. cursor_pos,
  120. selected,
  121. text,
  122. font_size,
  123. text_color,
  124. cursor_color,
  125. hi_bg_color,
  126. world_rect: Mutex::new(Rectangle { x: 0., y: 0., w: 0., h: 0. }),
  127. glyphs: Mutex::new(vec![]),
  128. text_shaper,
  129. key_repeat: Mutex::new(PressedKeysSmoothRepeat::new(400, 50)),
  130. mouse_btn_held: AtomicBool::new(false),
  131. window_scale,
  132. });
  133. self_.regen_glyphs().unwrap();
  134. let weak_self = Arc::downgrade(&self_);
  135. let slot_key_down = Slot {
  136. name: format!("{}::key_down", node_name),
  137. func: Box::new(move |data| {
  138. let mut cur = Cursor::new(&data);
  139. let keymods = KeyMods {
  140. shift: Decodable::decode(&mut cur).unwrap(),
  141. ctrl: Decodable::decode(&mut cur).unwrap(),
  142. alt: Decodable::decode(&mut cur).unwrap(),
  143. logo: Decodable::decode(&mut cur).unwrap(),
  144. };
  145. let repeat = bool::decode(&mut cur).unwrap();
  146. let key = String::decode(&mut cur).unwrap();
  147. let self_ = weak_self.upgrade();
  148. if let Some(self_) = self_ {
  149. self_.key_down(key, keymods, repeat);
  150. }
  151. }),
  152. };
  153. let weak_self = Arc::downgrade(&self_);
  154. let slot_key_up = Slot {
  155. name: format!("{}::key_up", node_name),
  156. func: Box::new(move |data| {
  157. let mut cur = Cursor::new(&data);
  158. let keymods = KeyMods {
  159. shift: Decodable::decode(&mut cur).unwrap(),
  160. ctrl: Decodable::decode(&mut cur).unwrap(),
  161. alt: Decodable::decode(&mut cur).unwrap(),
  162. logo: Decodable::decode(&mut cur).unwrap(),
  163. };
  164. let key = String::decode(&mut cur).unwrap();
  165. let self_ = weak_self.upgrade();
  166. if let Some(self_) = self_ {
  167. self_.key_up(key, keymods);
  168. }
  169. }),
  170. };
  171. let keyb_node =
  172. scene_graph
  173. .lookup_node_mut("/window/input/keyboard")
  174. .expect("no keyboard attached!");
  175. keyb_node.register("key_down", slot_key_down);
  176. keyb_node.register("key_up", slot_key_up);
  177. let weak_self = Arc::downgrade(&self_);
  178. let slot_btn_down = Slot {
  179. name: format!("{}::mouse_button_down", node_name),
  180. func: Box::new(move |data| {
  181. let mut cur = Cursor::new(&data);
  182. let button = MouseButton::from_u8(u8::decode(&mut cur).unwrap());
  183. let x = f32::decode(&mut cur).unwrap();
  184. let y = f32::decode(&mut cur).unwrap();
  185. let self_ = weak_self.upgrade();
  186. if let Some(self_) = self_ {
  187. self_.mouse_button_down(button, x, y);
  188. }
  189. }),
  190. };
  191. let weak_self = Arc::downgrade(&self_);
  192. let slot_btn_up = Slot {
  193. name: format!("{}::mouse_button_up", node_name),
  194. func: Box::new(move |data| {
  195. let mut cur = Cursor::new(&data);
  196. let button = MouseButton::from_u8(u8::decode(&mut cur).unwrap());
  197. let x = f32::decode(&mut cur).unwrap();
  198. let y = f32::decode(&mut cur).unwrap();
  199. let self_ = weak_self.upgrade();
  200. if let Some(self_) = self_ {
  201. self_.mouse_button_up(button, x, y);
  202. }
  203. }),
  204. };
  205. let weak_self = Arc::downgrade(&self_);
  206. let slot_move = Slot {
  207. name: format!("{}::mouse_move", node_name),
  208. func: Box::new(move |data| {
  209. let mut cur = Cursor::new(&data);
  210. let x = f32::decode(&mut cur).unwrap();
  211. let y = f32::decode(&mut cur).unwrap();
  212. let self_ = weak_self.upgrade();
  213. if let Some(self_) = self_ {
  214. self_.mouse_move(x, y);
  215. }
  216. }),
  217. };
  218. let mouse_node =
  219. scene_graph
  220. .lookup_node_mut("/window/input/mouse")
  221. .expect("no mouse attached!");
  222. mouse_node.register("button_down", slot_btn_down);
  223. mouse_node.register("button_up", slot_btn_up);
  224. mouse_node.register("move", slot_move);
  225. // Save any properties we use
  226. Ok(Pimpl::EditBox(self_))
  227. }
  228. pub fn render<'a>(&self, render: &mut RenderContext<'a>, node_id: SceneNodeId, layer_rect: &Rectangle<f32>) -> Result<()> {
  229. let node = render.scene_graph.get_node(node_id).unwrap();
  230. let rect = RenderContext::get_dim(node, layer_rect)?;
  231. // Used for detecting mouse clicks
  232. let mut world_rect = rect.clone();
  233. world_rect.x += layer_rect.x as f32;
  234. world_rect.y += layer_rect.y as f32;
  235. *self.world_rect.lock().unwrap() = world_rect;
  236. let layer_w = layer_rect.w as f32;
  237. let layer_h = layer_rect.h as f32;
  238. let off_x = rect.x / layer_w;
  239. let off_y = rect.y / layer_h;
  240. // Use absolute pixel scale
  241. let scale_x = 1. / layer_w;
  242. let scale_y = 1. / layer_h;
  243. //let model = glam::Mat4::IDENTITY;
  244. let model = glam::Mat4::from_translation(glam::Vec3::new(off_x, off_y, 0.)) *
  245. glam::Mat4::from_scale(glam::Vec3::new(scale_x, scale_y, 1.));
  246. let mut uniforms_data = [0u8; 128];
  247. let data: [u8; 64] = unsafe { std::mem::transmute_copy(&render.proj) };
  248. uniforms_data[0..64].copy_from_slice(&data);
  249. let data: [u8; 64] = unsafe { std::mem::transmute_copy(&model) };
  250. uniforms_data[64..].copy_from_slice(&data);
  251. assert_eq!(128, 2 * UniformType::Mat4.size());
  252. render.ctx.apply_uniforms_from_bytes(uniforms_data.as_ptr(), uniforms_data.len());
  253. self.apply_cursor_scrolling(&rect);
  254. let node = render.scene_graph.get_node(node_id).unwrap();
  255. let debug = self.debug.get();
  256. let baseline = self.baseline.get();
  257. let scroll = self.scroll.get();
  258. let cursor_pos = self.cursor_pos.get() as usize;
  259. let cursor_color = self.cursor_color.get();
  260. let text_color = self.text_color.get();
  261. let glyphs = &*self.glyphs.lock().unwrap();
  262. if !self.selected.is_null(0)? && !self.selected.is_null(1)? {
  263. self.render_selected(render, &rect, glyphs)?;
  264. }
  265. let bound = Rectangle {
  266. x: 0.,
  267. y: 0.,
  268. w: rect.w,
  269. h: rect.h,
  270. };
  271. let mut rhs = 0.;
  272. for (glyph_idx, glyph) in glyphs.iter().enumerate() {
  273. let x1 = glyph.pos.x + scroll;
  274. let y1 = glyph.pos.y + baseline;
  275. let x2 = x1 + glyph.pos.w;
  276. let y2 = y1 + glyph.pos.h;
  277. let texture = render.ctx.new_texture_from_rgba8(glyph.bmp_width, glyph.bmp_height, &glyph.bmp);
  278. render.render_clipped_box_with_texture(&bound, x1, y1, x2, y2, COLOR_WHITE, texture);
  279. //render.render_box_with_texture(x1, y1, x2, y2, COLOR_WHITE, texture);
  280. render.ctx.delete_texture(texture);
  281. // Glyph outlines
  282. //if debug {
  283. // render.outline(x1, y1, x2, y2, COLOR_BLUE, 1.);
  284. //}
  285. if cursor_pos != 0 && cursor_pos == glyph_idx {
  286. render.render_box(x1 - CURSOR_WIDTH, 0., x1, rect.h, cursor_color);
  287. }
  288. rhs = x2;
  289. }
  290. if cursor_pos == 0 {
  291. render.render_box(0., 0., CURSOR_WIDTH, rect.h, cursor_color);
  292. } else if cursor_pos == glyphs.len() {
  293. render.render_box(rhs - CURSOR_WIDTH, 0., rhs, rect.h, cursor_color);
  294. }
  295. if debug {
  296. let outline_color = if self.is_active.get() {
  297. COLOR_GREEN
  298. } else {
  299. COLOR_DARKGREY
  300. };
  301. // Baseline
  302. //render.hline(0., rhs, 0., COLOR_RED, 1.);
  303. render.outline(0., 0., rect.w, rect.h, outline_color, 1.);
  304. }
  305. Ok(())
  306. }
  307. pub fn render_selected<'a>(&self, render: &mut RenderContext<'a>, rect: &Rectangle<f32>, glyphs: &Vec<Glyph>) -> Result<()> {
  308. let start = self.selected.get_u32(0)? as usize;
  309. let end = self.selected.get_u32(1)? as usize;
  310. let sel_start = std::cmp::min(start, end);
  311. let sel_end = std::cmp::max(start, end);
  312. let scroll = self.scroll.get();
  313. let hi_bg_color = self.hi_bg_color.get();
  314. let mut start_x = 0.;
  315. let mut end_x = 0.;
  316. for (glyph_idx, glyph) in glyphs.iter().enumerate() {
  317. let x1 = glyph.pos.x + scroll;
  318. if glyph_idx == sel_start {
  319. start_x = x1;
  320. }
  321. if glyph_idx == sel_end {
  322. end_x = x1;
  323. }
  324. }
  325. if sel_start == 0 {
  326. start_x = scroll;
  327. }
  328. if sel_end == glyphs.len() {
  329. let glyph = &glyphs.last().unwrap();
  330. let x2 = glyph.pos.x + scroll + glyph.pos.w;
  331. end_x = x2;
  332. }
  333. // Apply clipping
  334. if start_x < 0. {
  335. start_x = 0.;
  336. }
  337. if end_x > rect.w {
  338. end_x = rect.w;
  339. }
  340. render.render_box(start_x, 0., end_x, rect.h, hi_bg_color);
  341. Ok(())
  342. }
  343. fn delete_highlighted(&self) {
  344. assert!(!self.selected.is_null(0).unwrap());
  345. assert!(!self.selected.is_null(1).unwrap());
  346. let start = self.selected.get_u32(0).unwrap() as usize;
  347. let end = self.selected.get_u32(1).unwrap() as usize;
  348. let sel_start = std::cmp::min(start, end);
  349. let sel_end = std::cmp::max(start, end);
  350. let glyphs = &*self.glyphs.lock().unwrap();
  351. // Regen text
  352. let mut text = String::new();
  353. for (i, glyph) in glyphs.iter().enumerate() {
  354. let mut substr = glyph.substr.clone();
  355. if sel_start <= i && i < sel_end {
  356. continue
  357. }
  358. text.push_str(&substr);
  359. }
  360. debug!("EditBox(\"{}\")::delete_highlighted() text=\"{}\", cursor_pos={}",
  361. self.node_name, text, sel_start);
  362. self.text.set(text);
  363. self.selected.set_null(0).unwrap();
  364. self.selected.set_null(1).unwrap();
  365. self.cursor_pos.set(sel_start as u32);
  366. }
  367. fn apply_cursor_scrolling(&self, rect: &Rectangle<f32>) {
  368. let cursor_pos = self.cursor_pos.get() as usize;
  369. let mut scroll = self.scroll.get();
  370. let cursor_x = {
  371. let glyphs = &*self.glyphs.lock().unwrap();
  372. if cursor_pos == 0 {
  373. 0.
  374. } else if cursor_pos == glyphs.len() {
  375. let glyph = &glyphs.last().unwrap();
  376. glyph.pos.x + glyph.pos.w
  377. } else {
  378. assert!(cursor_pos < glyphs.len());
  379. let glyph = &glyphs[cursor_pos];
  380. glyph.pos.x
  381. }
  382. };
  383. let cursor_lhs = cursor_x + scroll;
  384. let cursor_rhs = cursor_lhs + CURSOR_WIDTH;
  385. if cursor_rhs > rect.w {
  386. scroll = rect.w - cursor_x;
  387. } else if cursor_lhs < 0. {
  388. scroll = -cursor_x + CURSOR_WIDTH;
  389. }
  390. self.scroll.set(scroll);
  391. }
  392. fn regen_glyphs(&self) -> Result<()> {
  393. let font_size = self.window_scale * self.font_size.get();
  394. let glyphs = self.text_shaper.shape(self.text.get(), font_size,
  395. self.text_color.get());
  396. if self.cursor_pos.get() > glyphs.len() as u32 {
  397. self.cursor_pos.set(glyphs.len() as u32);
  398. }
  399. *self.glyphs.lock().unwrap() = glyphs;
  400. Ok(())
  401. }
  402. fn key_down(self: Arc<Self>, key: String, mods: KeyMods, repeat: bool) {
  403. if !self.is_active.get() {
  404. return
  405. }
  406. let actions = {
  407. let mut repeater = self.key_repeat.lock().unwrap();
  408. repeater.key_down(&key, repeat)
  409. };
  410. for _ in 0..actions {
  411. self.do_key_down(&key, &mods)
  412. }
  413. }
  414. fn do_key_down(&self, key: &str, mods: &KeyMods) {
  415. match key {
  416. "Left" => {
  417. let mut cursor_pos = self.cursor_pos.get();
  418. // Start selection if shift is held
  419. if !mods.shift {
  420. self.selected.set_null(0).unwrap();
  421. self.selected.set_null(1).unwrap();
  422. } else if self.selected.is_null(0).unwrap() {
  423. assert!(self.selected.is_null(1).unwrap());
  424. self.selected.set_u32(0, cursor_pos).unwrap();
  425. }
  426. if cursor_pos > 0 {
  427. cursor_pos -= 1;
  428. debug!("EditBox(\"{}\")::key_down(Left) cursor_pos={}",
  429. self.node_name, cursor_pos);
  430. self.cursor_pos.set(cursor_pos);
  431. }
  432. // Update selection
  433. if mods.shift {
  434. self.selected.set_u32(1, cursor_pos).unwrap();
  435. }
  436. }
  437. "Right" => {
  438. let mut cursor_pos = self.cursor_pos.get();
  439. // Start selection if shift is held
  440. if !mods.shift {
  441. self.selected.set_null(0).unwrap();
  442. self.selected.set_null(1).unwrap();
  443. } else if self.selected.is_null(0).unwrap() {
  444. assert!(self.selected.is_null(1).unwrap());
  445. self.selected.set_u32(0, cursor_pos).unwrap();
  446. }
  447. let glyphs_len = self.glyphs.lock().unwrap().len() as u32;
  448. if cursor_pos < glyphs_len {
  449. cursor_pos += 1;
  450. debug!("EditBox(\"{}\")::key_down(Right) cursor_pos={}",
  451. self.node_name, cursor_pos);
  452. self.cursor_pos.set(cursor_pos);
  453. }
  454. // Update selection
  455. if mods.shift {
  456. self.selected.set_u32(1, cursor_pos).unwrap();
  457. }
  458. }
  459. "Delete" => {
  460. let cursor_pos = self.cursor_pos.get();
  461. let text = if !self.selected.is_null(0).unwrap() {
  462. self.delete_highlighted();
  463. } else {
  464. let glyphs = &*self.glyphs.lock().unwrap();
  465. if cursor_pos == glyphs.len() as u32 {
  466. return;
  467. }
  468. // Regen text
  469. let mut text = String::new();
  470. for (i, glyph) in glyphs.iter().enumerate() {
  471. let mut substr = glyph.substr.clone();
  472. if cursor_pos as usize == i {
  473. // Lmk if anyone knows a better way to do substr.pop_front()
  474. let mut chars = substr.chars();
  475. chars.next();
  476. substr = chars.as_str().to_string();
  477. }
  478. text.push_str(&substr);
  479. }
  480. self.text.set(text);
  481. };
  482. self.regen_glyphs().unwrap();
  483. }
  484. "Backspace" => {
  485. let cursor_pos = self.cursor_pos.get();
  486. let text = if !self.selected.is_null(0).unwrap() {
  487. self.delete_highlighted();
  488. } else {
  489. if cursor_pos == 0 {
  490. return;
  491. }
  492. let glyphs = &*self.glyphs.lock().unwrap();
  493. let mut text = String::new();
  494. for (i, glyph) in glyphs.iter().enumerate() {
  495. let mut substr = glyph.substr.clone();
  496. if cursor_pos as usize - 1 == i {
  497. substr.pop().unwrap();
  498. }
  499. text.push_str(&substr);
  500. }
  501. self.text.set(text);
  502. self.cursor_pos.set(cursor_pos - 1);
  503. };
  504. self.regen_glyphs().unwrap();
  505. }
  506. "C" => {
  507. if mods.ctrl {
  508. self.copy_highlighted_text().unwrap();
  509. } else {
  510. self.insert_char(key, mods);
  511. }
  512. }
  513. "V" => {
  514. if mods.ctrl {
  515. if let Some(text) = window::clipboard_get() {
  516. self.insert_text(text);
  517. }
  518. } else {
  519. self.insert_char(key, mods);
  520. }
  521. }
  522. _ => {
  523. self.insert_char(key, mods);
  524. }
  525. }
  526. }
  527. fn insert_char(&self, key: &str, mods: &KeyMods) {
  528. // First filter for only single digit keys
  529. let allowed_keys =
  530. ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
  531. " ", ":", ";", "'", "-", ".", "/", "=", "(", "\\", ")", "`",
  532. "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ];
  533. if !allowed_keys.contains(&key) {
  534. return
  535. }
  536. // If we want to only allow specific chars in a String here
  537. //let ch = key.chars().next().unwrap();
  538. // if !self.allowed_chars.chars().any(|c| c == ch) { return }
  539. let key = if mods.shift {
  540. key.to_string()
  541. } else {
  542. key.to_lowercase()
  543. };
  544. self.insert_text(key);
  545. }
  546. fn insert_text(&self, key: String) {
  547. let mut text = String::new();
  548. let cursor_pos = self.cursor_pos.get();
  549. if cursor_pos == 0 {
  550. text = key;
  551. } else {
  552. let glyphs = &*self.glyphs.lock().unwrap();
  553. for (glyph_idx, glyph) in glyphs.iter().enumerate() {
  554. text.push_str(&glyph.substr);
  555. if cursor_pos == glyph_idx as u32 + 1 {
  556. text.push_str(&key);
  557. }
  558. }
  559. }
  560. self.text.set(text);
  561. // Not always true lol
  562. self.cursor_pos.set(cursor_pos + 1);
  563. self.regen_glyphs().unwrap();
  564. }
  565. fn copy_highlighted_text(&self) -> Result<()> {
  566. let start = self.selected.get_u32(0)? as usize;
  567. let end = self.selected.get_u32(1)? as usize;
  568. let sel_start = std::cmp::min(start, end);
  569. let sel_end = std::cmp::max(start, end);
  570. let mut text = String::new();
  571. let glyphs = &*self.glyphs.lock().unwrap();
  572. for (glyph_idx, glyph) in glyphs.iter().enumerate() {
  573. if sel_start <= glyph_idx && glyph_idx < sel_end {
  574. text.push_str(&glyph.substr);
  575. }
  576. }
  577. info!("Copied '{}'", text);
  578. window::clipboard_set(&text);
  579. Ok(())
  580. }
  581. fn key_up(self: Arc<Self>, key: String, mods: KeyMods) {
  582. let mut repeater = self.key_repeat.lock().unwrap();
  583. repeater.key_up(&key);
  584. }
  585. fn mouse_button_down(self: Arc<Self>, button: MouseButton, x: f32, y: f32) {
  586. let mouse_pos = Point { x, y };
  587. let rect = self.world_rect.lock().unwrap().clone();
  588. // clicking inside box will:
  589. // 1. make it active
  590. // 2. begin selection
  591. if rect.contains(&mouse_pos) {
  592. if !self.is_active.get() {
  593. self.is_active.set(true);
  594. println!("inside!");
  595. // Send signal
  596. }
  597. let cpos = match self.find_closest_glyph_idx(x) {
  598. MouseClickGlyph::Pos(cpos) => cpos,
  599. _ => panic!("shouldn't be possible to reach here!")
  600. };
  601. // set cursor pos
  602. self.cursor_pos.set(cpos);
  603. // begin selection
  604. self.selected.set_u32(0, cpos).unwrap();
  605. self.selected.set_u32(1, cpos).unwrap();
  606. self.mouse_btn_held.store(true, Ordering::Relaxed);
  607. }
  608. // click outside the box will:
  609. // 1. make it inactive
  610. else {
  611. if self.is_active.get() {
  612. self.is_active.set(false);
  613. // Send signal
  614. }
  615. }
  616. }
  617. fn mouse_button_up(self: Arc<Self>, button: MouseButton, x: f32, y: f32) {
  618. // releasing mouse button will:
  619. // 1. end selection
  620. self.mouse_btn_held.store(false, Ordering::Relaxed);
  621. }
  622. fn mouse_move(self: Arc<Self>, x: f32, y: f32) {
  623. if !self.mouse_btn_held.load(Ordering::Relaxed) {
  624. return;
  625. }
  626. // if active and selection_active, then use x to modify the selection.
  627. // also implement scrolling when cursor is to the left or right
  628. // just scroll to the end
  629. // also set cursor_pos too
  630. let cpos = match self.find_closest_glyph_idx(x) {
  631. MouseClickGlyph::Lhs => 0,
  632. MouseClickGlyph::Pos(cpos) => cpos,
  633. MouseClickGlyph::Rhs(cpos) => cpos,
  634. };
  635. self.cursor_pos.set(cpos);
  636. self.selected.set_u32(1, cpos).unwrap();
  637. }
  638. // Uses screen x pos
  639. fn find_closest_glyph_idx(&self, x: f32) -> MouseClickGlyph {
  640. let rect = self.world_rect.lock().unwrap().clone();
  641. let glyphs = &*self.glyphs.lock().unwrap();
  642. let mouse_x = x - rect.x;
  643. if mouse_x > rect.w {
  644. // Highlight to the end
  645. let cpos = glyphs.len() as u32;
  646. return MouseClickGlyph::Rhs(cpos);
  647. // Scroll to the right handled in render
  648. } else if mouse_x < 0. {
  649. return MouseClickGlyph::Lhs;
  650. }
  651. let scroll = self.scroll.get();
  652. let mouse_x = x - rect.x;
  653. let mut cpos = 0;
  654. let lhs = 0.;
  655. let mut last_d = (lhs - mouse_x).abs();
  656. for (i, glyph) in glyphs.iter().skip(1).enumerate() {
  657. // Because we skip the first item
  658. let glyph_idx = (i + 1) as u32;
  659. let x1 = glyph.pos.x + scroll;
  660. let curr_d = (x1 - mouse_x).abs();
  661. if curr_d < last_d {
  662. last_d = curr_d;
  663. cpos = glyph_idx;
  664. }
  665. }
  666. // also check the right hand side
  667. let rhs = {
  668. let glyph = &glyphs.last().unwrap();
  669. glyph.pos.x + scroll + glyph.pos.w
  670. };
  671. let curr_d = (rhs - mouse_x).abs();
  672. if curr_d < last_d {
  673. //last_d = curr_d;
  674. cpos = glyphs.len() as u32;
  675. }
  676. MouseClickGlyph::Pos(cpos)
  677. }
  678. }
  679. enum MouseClickGlyph {
  680. Lhs,
  681. Pos(u32),
  682. Rhs(u32)
  683. }