| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796 |
- use miniquad::{KeyMods, UniformType, MouseButton, window};
- use log::{debug, info};
- use std::{
- collections::HashMap,
- io::Cursor, sync::{Arc, atomic::{AtomicBool, Ordering}, Mutex}, time::{Instant, Duration}};
- use darkfi_serial::Decodable;
- use freetype as ft;
- use crate::{error::{Error, Result}, prop::{
- PropertyBool, PropertyFloat32, PropertyUint32, PropertyStr, PropertyColor,
- 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}};
- const CURSOR_WIDTH: f32 = 4.;
- struct PressedKeysSmoothRepeat {
- /// When holding keys, we track from start and last sent time.
- /// This is useful for initial delay and smooth scrolling.
- pressed_keys: HashMap<String, RepeatingKeyTimer>,
- /// Initial delay before allowing keys
- start_delay: u32,
- /// Minimum time between repeated keys
- step_time: u32,
- }
- impl PressedKeysSmoothRepeat {
- fn new(start_delay: u32, step_time: u32) -> Self {
- Self {
- pressed_keys: HashMap::new(),
- start_delay,
- step_time
- }
- }
- fn key_down(&mut self, key: &str, repeat: bool) -> u32 {
- if !repeat {
- return 1;
- }
- // Insert key if not exists
- if !self.pressed_keys.contains_key(key) {
- self.pressed_keys.insert(key.to_string(), RepeatingKeyTimer::new());
- }
- let repeater = self.pressed_keys.get_mut(key).expect("repeat map");
- repeater.update(self.start_delay, self.step_time)
- }
- fn key_up(&mut self, key: &str) {
- self.pressed_keys.remove(key);
- }
- }
- struct RepeatingKeyTimer {
- start: Instant,
- actions: u32,
- }
- impl RepeatingKeyTimer {
- fn new() -> Self {
- Self {
- start: Instant::now(),
- actions: 0
- }
- }
- fn update(&mut self, start_delay: u32, step_time: u32) -> u32 {
- let elapsed = self.start.elapsed().as_millis();
- if elapsed < start_delay as u128 {
- return 0
- }
- let total_actions = ((elapsed - start_delay as u128) / step_time as u128) as u32;
- let remaining_actions = total_actions - self.actions;
- self.actions = total_actions;
- remaining_actions
- }
- }
- pub type EditBoxPtr = Arc<EditBox>;
- pub struct EditBox {
- node_name: String,
- is_active: PropertyBool,
- debug: PropertyBool,
- baseline: PropertyFloat32,
- scroll: PropertyFloat32,
- cursor_pos: PropertyUint32,
- selected: Arc<Property>,
- text: PropertyStr,
- font_size: PropertyFloat32,
- text_color: PropertyColor,
- cursor_color: PropertyColor,
- hi_bg_color: PropertyColor,
- // Used for mouse clicks
- world_rect: Mutex<Rectangle<f32>>,
- glyphs: Mutex<Vec<Glyph>>,
- text_shaper: TextShaper,
- key_repeat: Mutex<PressedKeysSmoothRepeat>,
- mouse_btn_held: AtomicBool,
- window_scale: f32,
- }
- impl EditBox {
- pub fn new(scene_graph: &mut SceneGraph, node_id: SceneNodeId, font_faces: Vec<FreetypeFace>) -> Result<Pimpl> {
- let node = scene_graph.get_node(node_id).unwrap();
- let node_name = node.name.clone();
- let is_active = PropertyBool::wrap(node, "is_active", 0)?;
- let debug = PropertyBool::wrap(node, "debug", 0)?;
- let baseline = PropertyFloat32::wrap(node, "baseline", 0)?;
- let scroll = PropertyFloat32::wrap(node, "scroll", 0)?;
- let cursor_pos = PropertyUint32::wrap(node, "cursor_pos", 0)?;
- let selected = node.get_property("selected").ok_or(Error::PropertyNotFound)?;
- let text = PropertyStr::wrap(node, "text", 0)?;
- let font_size = PropertyFloat32::wrap(node, "font_size", 0)?;
- let text_color = PropertyColor::wrap(node, "text_color")?;
- let cursor_color = PropertyColor::wrap(node, "cursor_color")?;
- let hi_bg_color = PropertyColor::wrap(node, "hi_bg_color")?;
- let text_shaper = TextShaper {
- font_faces
- };
- // TODO: catch window resize event and regen glyphs
- // Used for scaling the font size
- let window =
- scene_graph
- .lookup_node("/window")
- .expect("no window attached!");
- let window_scale = window.get_property_f32("scale")?;
- let self_ = Arc::new(Self{
- node_name: node_name.clone(),
- is_active,
- debug,
- baseline,
- scroll,
- cursor_pos,
- selected,
- text,
- font_size,
- text_color,
- cursor_color,
- hi_bg_color,
- world_rect: Mutex::new(Rectangle { x: 0., y: 0., w: 0., h: 0. }),
- glyphs: Mutex::new(vec![]),
- text_shaper,
- key_repeat: Mutex::new(PressedKeysSmoothRepeat::new(400, 50)),
- mouse_btn_held: AtomicBool::new(false),
- window_scale,
- });
- self_.regen_glyphs().unwrap();
- let weak_self = Arc::downgrade(&self_);
- let slot_key_down = Slot {
- name: format!("{}::key_down", node_name),
- func: Box::new(move |data| {
- let mut cur = Cursor::new(&data);
- let keymods = KeyMods {
- shift: Decodable::decode(&mut cur).unwrap(),
- ctrl: Decodable::decode(&mut cur).unwrap(),
- alt: Decodable::decode(&mut cur).unwrap(),
- logo: Decodable::decode(&mut cur).unwrap(),
- };
- let repeat = bool::decode(&mut cur).unwrap();
- let key = String::decode(&mut cur).unwrap();
- let self_ = weak_self.upgrade();
- if let Some(self_) = self_ {
- self_.key_down(key, keymods, repeat);
- }
- }),
- };
- let weak_self = Arc::downgrade(&self_);
- let slot_key_up = Slot {
- name: format!("{}::key_up", node_name),
- func: Box::new(move |data| {
- let mut cur = Cursor::new(&data);
- let keymods = KeyMods {
- shift: Decodable::decode(&mut cur).unwrap(),
- ctrl: Decodable::decode(&mut cur).unwrap(),
- alt: Decodable::decode(&mut cur).unwrap(),
- logo: Decodable::decode(&mut cur).unwrap(),
- };
- let key = String::decode(&mut cur).unwrap();
- let self_ = weak_self.upgrade();
- if let Some(self_) = self_ {
- self_.key_up(key, keymods);
- }
- }),
- };
- let keyb_node =
- scene_graph
- .lookup_node_mut("/window/input/keyboard")
- .expect("no keyboard attached!");
- keyb_node.register("key_down", slot_key_down);
- keyb_node.register("key_up", slot_key_up);
- let weak_self = Arc::downgrade(&self_);
- let slot_btn_down = Slot {
- name: format!("{}::mouse_button_down", node_name),
- func: Box::new(move |data| {
- let mut cur = Cursor::new(&data);
- let button = MouseButton::from_u8(u8::decode(&mut cur).unwrap());
- let x = f32::decode(&mut cur).unwrap();
- let y = f32::decode(&mut cur).unwrap();
- let self_ = weak_self.upgrade();
- if let Some(self_) = self_ {
- self_.mouse_button_down(button, x, y);
- }
- }),
- };
- let weak_self = Arc::downgrade(&self_);
- let slot_btn_up = Slot {
- name: format!("{}::mouse_button_up", node_name),
- func: Box::new(move |data| {
- let mut cur = Cursor::new(&data);
- let button = MouseButton::from_u8(u8::decode(&mut cur).unwrap());
- let x = f32::decode(&mut cur).unwrap();
- let y = f32::decode(&mut cur).unwrap();
- let self_ = weak_self.upgrade();
- if let Some(self_) = self_ {
- self_.mouse_button_up(button, x, y);
- }
- }),
- };
- let weak_self = Arc::downgrade(&self_);
- let slot_move = Slot {
- name: format!("{}::mouse_move", node_name),
- func: Box::new(move |data| {
- let mut cur = Cursor::new(&data);
- let x = f32::decode(&mut cur).unwrap();
- let y = f32::decode(&mut cur).unwrap();
- let self_ = weak_self.upgrade();
- if let Some(self_) = self_ {
- self_.mouse_move(x, y);
- }
- }),
- };
- let mouse_node =
- scene_graph
- .lookup_node_mut("/window/input/mouse")
- .expect("no mouse attached!");
- mouse_node.register("button_down", slot_btn_down);
- mouse_node.register("button_up", slot_btn_up);
- mouse_node.register("move", slot_move);
- // Save any properties we use
- Ok(Pimpl::EditBox(self_))
- }
- pub fn render<'a>(&self, render: &mut RenderContext<'a>, node_id: SceneNodeId, layer_rect: &Rectangle<f32>) -> Result<()> {
- let node = render.scene_graph.get_node(node_id).unwrap();
- let rect = RenderContext::get_dim(node, layer_rect)?;
- // Used for detecting mouse clicks
- let mut world_rect = rect.clone();
- world_rect.x += layer_rect.x as f32;
- world_rect.y += layer_rect.y as f32;
- *self.world_rect.lock().unwrap() = world_rect;
- let layer_w = layer_rect.w as f32;
- let layer_h = layer_rect.h as f32;
- let off_x = rect.x / layer_w;
- let off_y = rect.y / layer_h;
- // Use absolute pixel scale
- let scale_x = 1. / layer_w;
- let scale_y = 1. / layer_h;
- //let model = glam::Mat4::IDENTITY;
- let model = glam::Mat4::from_translation(glam::Vec3::new(off_x, off_y, 0.)) *
- glam::Mat4::from_scale(glam::Vec3::new(scale_x, scale_y, 1.));
- let mut uniforms_data = [0u8; 128];
- let data: [u8; 64] = unsafe { std::mem::transmute_copy(&render.proj) };
- uniforms_data[0..64].copy_from_slice(&data);
- let data: [u8; 64] = unsafe { std::mem::transmute_copy(&model) };
- uniforms_data[64..].copy_from_slice(&data);
- assert_eq!(128, 2 * UniformType::Mat4.size());
- render.ctx.apply_uniforms_from_bytes(uniforms_data.as_ptr(), uniforms_data.len());
- self.apply_cursor_scrolling(&rect);
- let node = render.scene_graph.get_node(node_id).unwrap();
- let debug = self.debug.get();
- let baseline = self.baseline.get();
- let scroll = self.scroll.get();
- let cursor_pos = self.cursor_pos.get() as usize;
- let cursor_color = self.cursor_color.get();
- let text_color = self.text_color.get();
- let glyphs = &*self.glyphs.lock().unwrap();
- if !self.selected.is_null(0)? && !self.selected.is_null(1)? {
- self.render_selected(render, &rect, glyphs)?;
- }
- let bound = Rectangle {
- x: 0.,
- y: 0.,
- w: rect.w,
- h: rect.h,
- };
- let mut rhs = 0.;
- for (glyph_idx, glyph) in glyphs.iter().enumerate() {
- let x1 = glyph.pos.x + scroll;
- let y1 = glyph.pos.y + baseline;
- let x2 = x1 + glyph.pos.w;
- let y2 = y1 + glyph.pos.h;
- let texture = render.ctx.new_texture_from_rgba8(glyph.bmp_width, glyph.bmp_height, &glyph.bmp);
- render.render_clipped_box_with_texture(&bound, x1, y1, x2, y2, COLOR_WHITE, texture);
- //render.render_box_with_texture(x1, y1, x2, y2, COLOR_WHITE, texture);
- render.ctx.delete_texture(texture);
- // Glyph outlines
- //if debug {
- // render.outline(x1, y1, x2, y2, COLOR_BLUE, 1.);
- //}
- if cursor_pos != 0 && cursor_pos == glyph_idx {
- render.render_box(x1 - CURSOR_WIDTH, 0., x1, rect.h, cursor_color);
- }
- rhs = x2;
- }
- if cursor_pos == 0 {
- render.render_box(0., 0., CURSOR_WIDTH, rect.h, cursor_color);
- } else if cursor_pos == glyphs.len() {
- render.render_box(rhs - CURSOR_WIDTH, 0., rhs, rect.h, cursor_color);
- }
- if debug {
- let outline_color = if self.is_active.get() {
- COLOR_GREEN
- } else {
- COLOR_DARKGREY
- };
- // Baseline
- //render.hline(0., rhs, 0., COLOR_RED, 1.);
- render.outline(0., 0., rect.w, rect.h, outline_color, 1.);
- }
- Ok(())
- }
- pub fn render_selected<'a>(&self, render: &mut RenderContext<'a>, rect: &Rectangle<f32>, glyphs: &Vec<Glyph>) -> Result<()> {
- let start = self.selected.get_u32(0)? as usize;
- let end = self.selected.get_u32(1)? as usize;
- let sel_start = std::cmp::min(start, end);
- let sel_end = std::cmp::max(start, end);
- let scroll = self.scroll.get();
- let hi_bg_color = self.hi_bg_color.get();
- let mut start_x = 0.;
- let mut end_x = 0.;
- for (glyph_idx, glyph) in glyphs.iter().enumerate() {
- let x1 = glyph.pos.x + scroll;
- if glyph_idx == sel_start {
- start_x = x1;
- }
- if glyph_idx == sel_end {
- end_x = x1;
- }
- }
- if sel_start == 0 {
- start_x = scroll;
- }
- if sel_end == glyphs.len() {
- let glyph = &glyphs.last().unwrap();
- let x2 = glyph.pos.x + scroll + glyph.pos.w;
- end_x = x2;
- }
- // Apply clipping
- if start_x < 0. {
- start_x = 0.;
- }
- if end_x > rect.w {
- end_x = rect.w;
- }
- render.render_box(start_x, 0., end_x, rect.h, hi_bg_color);
- Ok(())
- }
- fn delete_highlighted(&self) {
- assert!(!self.selected.is_null(0).unwrap());
- assert!(!self.selected.is_null(1).unwrap());
- let start = self.selected.get_u32(0).unwrap() as usize;
- let end = self.selected.get_u32(1).unwrap() as usize;
- let sel_start = std::cmp::min(start, end);
- let sel_end = std::cmp::max(start, end);
- let glyphs = &*self.glyphs.lock().unwrap();
- // Regen text
- let mut text = String::new();
- for (i, glyph) in glyphs.iter().enumerate() {
- let mut substr = glyph.substr.clone();
- if sel_start <= i && i < sel_end {
- continue
- }
- text.push_str(&substr);
- }
- debug!("EditBox(\"{}\")::delete_highlighted() text=\"{}\", cursor_pos={}",
- self.node_name, text, sel_start);
- self.text.set(text);
- self.selected.set_null(0).unwrap();
- self.selected.set_null(1).unwrap();
- self.cursor_pos.set(sel_start as u32);
- }
- fn apply_cursor_scrolling(&self, rect: &Rectangle<f32>) {
- let cursor_pos = self.cursor_pos.get() as usize;
- let mut scroll = self.scroll.get();
- let cursor_x = {
- let glyphs = &*self.glyphs.lock().unwrap();
- if cursor_pos == 0 {
- 0.
- } else if cursor_pos == glyphs.len() {
- let glyph = &glyphs.last().unwrap();
- glyph.pos.x + glyph.pos.w
- } else {
- assert!(cursor_pos < glyphs.len());
- let glyph = &glyphs[cursor_pos];
- glyph.pos.x
- }
- };
- let cursor_lhs = cursor_x + scroll;
- let cursor_rhs = cursor_lhs + CURSOR_WIDTH;
- if cursor_rhs > rect.w {
- scroll = rect.w - cursor_x;
- } else if cursor_lhs < 0. {
- scroll = -cursor_x + CURSOR_WIDTH;
- }
- self.scroll.set(scroll);
- }
- fn regen_glyphs(&self) -> Result<()> {
- let font_size = self.window_scale * self.font_size.get();
- let glyphs = self.text_shaper.shape(self.text.get(), font_size,
- self.text_color.get());
- if self.cursor_pos.get() > glyphs.len() as u32 {
- self.cursor_pos.set(glyphs.len() as u32);
- }
- *self.glyphs.lock().unwrap() = glyphs;
- Ok(())
- }
- fn key_down(self: Arc<Self>, key: String, mods: KeyMods, repeat: bool) {
- if !self.is_active.get() {
- return
- }
- let actions = {
- let mut repeater = self.key_repeat.lock().unwrap();
- repeater.key_down(&key, repeat)
- };
- for _ in 0..actions {
- self.do_key_down(&key, &mods)
- }
- }
- fn do_key_down(&self, key: &str, mods: &KeyMods) {
- match key {
- "Left" => {
- let mut cursor_pos = self.cursor_pos.get();
- // Start selection if shift is held
- if !mods.shift {
- self.selected.set_null(0).unwrap();
- self.selected.set_null(1).unwrap();
- } else if self.selected.is_null(0).unwrap() {
- assert!(self.selected.is_null(1).unwrap());
- self.selected.set_u32(0, cursor_pos).unwrap();
- }
- if cursor_pos > 0 {
- cursor_pos -= 1;
- debug!("EditBox(\"{}\")::key_down(Left) cursor_pos={}",
- self.node_name, cursor_pos);
- self.cursor_pos.set(cursor_pos);
- }
- // Update selection
- if mods.shift {
- self.selected.set_u32(1, cursor_pos).unwrap();
- }
- }
- "Right" => {
- let mut cursor_pos = self.cursor_pos.get();
- // Start selection if shift is held
- if !mods.shift {
- self.selected.set_null(0).unwrap();
- self.selected.set_null(1).unwrap();
- } else if self.selected.is_null(0).unwrap() {
- assert!(self.selected.is_null(1).unwrap());
- self.selected.set_u32(0, cursor_pos).unwrap();
- }
- let glyphs_len = self.glyphs.lock().unwrap().len() as u32;
- if cursor_pos < glyphs_len {
- cursor_pos += 1;
- debug!("EditBox(\"{}\")::key_down(Right) cursor_pos={}",
- self.node_name, cursor_pos);
- self.cursor_pos.set(cursor_pos);
- }
- // Update selection
- if mods.shift {
- self.selected.set_u32(1, cursor_pos).unwrap();
- }
- }
- "Delete" => {
- let cursor_pos = self.cursor_pos.get();
- let text = if !self.selected.is_null(0).unwrap() {
- self.delete_highlighted();
- } else {
- let glyphs = &*self.glyphs.lock().unwrap();
- if cursor_pos == glyphs.len() as u32 {
- return;
- }
- // Regen text
- let mut text = String::new();
- for (i, glyph) in glyphs.iter().enumerate() {
- let mut substr = glyph.substr.clone();
- if cursor_pos as usize == i {
- // Lmk if anyone knows a better way to do substr.pop_front()
- let mut chars = substr.chars();
- chars.next();
- substr = chars.as_str().to_string();
- }
- text.push_str(&substr);
- }
- self.text.set(text);
- };
- self.regen_glyphs().unwrap();
- }
- "Backspace" => {
- let cursor_pos = self.cursor_pos.get();
- let text = if !self.selected.is_null(0).unwrap() {
- self.delete_highlighted();
- } else {
- if cursor_pos == 0 {
- return;
- }
- let glyphs = &*self.glyphs.lock().unwrap();
- let mut text = String::new();
- for (i, glyph) in glyphs.iter().enumerate() {
- let mut substr = glyph.substr.clone();
- if cursor_pos as usize - 1 == i {
- substr.pop().unwrap();
- }
- text.push_str(&substr);
- }
- self.text.set(text);
- self.cursor_pos.set(cursor_pos - 1);
- };
- self.regen_glyphs().unwrap();
- }
- "C" => {
- if mods.ctrl {
- self.copy_highlighted_text().unwrap();
- } else {
- self.insert_char(key, mods);
- }
- }
- "V" => {
- if mods.ctrl {
- if let Some(text) = window::clipboard_get() {
- self.insert_text(text);
- }
- } else {
- self.insert_char(key, mods);
- }
- }
- _ => {
- self.insert_char(key, mods);
- }
- }
- }
- fn insert_char(&self, key: &str, mods: &KeyMods) {
- // First filter for only single digit keys
- let allowed_keys =
- ["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",
- " ", ":", ";", "'", "-", ".", "/", "=", "(", "\\", ")", "`",
- "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ];
- if !allowed_keys.contains(&key) {
- return
- }
- // If we want to only allow specific chars in a String here
- //let ch = key.chars().next().unwrap();
- // if !self.allowed_chars.chars().any(|c| c == ch) { return }
- let key = if mods.shift {
- key.to_string()
- } else {
- key.to_lowercase()
- };
- self.insert_text(key);
- }
- fn insert_text(&self, key: String) {
- let mut text = String::new();
- let cursor_pos = self.cursor_pos.get();
- if cursor_pos == 0 {
- text = key;
- } else {
- let glyphs = &*self.glyphs.lock().unwrap();
- for (glyph_idx, glyph) in glyphs.iter().enumerate() {
- text.push_str(&glyph.substr);
- if cursor_pos == glyph_idx as u32 + 1 {
- text.push_str(&key);
- }
- }
- }
- self.text.set(text);
- // Not always true lol
- self.cursor_pos.set(cursor_pos + 1);
- self.regen_glyphs().unwrap();
- }
- fn copy_highlighted_text(&self) -> Result<()> {
- let start = self.selected.get_u32(0)? as usize;
- let end = self.selected.get_u32(1)? as usize;
- let sel_start = std::cmp::min(start, end);
- let sel_end = std::cmp::max(start, end);
- let mut text = String::new();
- let glyphs = &*self.glyphs.lock().unwrap();
- for (glyph_idx, glyph) in glyphs.iter().enumerate() {
- if sel_start <= glyph_idx && glyph_idx < sel_end {
- text.push_str(&glyph.substr);
- }
- }
- info!("Copied '{}'", text);
- window::clipboard_set(&text);
- Ok(())
- }
- fn key_up(self: Arc<Self>, key: String, mods: KeyMods) {
- let mut repeater = self.key_repeat.lock().unwrap();
- repeater.key_up(&key);
- }
- fn mouse_button_down(self: Arc<Self>, button: MouseButton, x: f32, y: f32) {
- let mouse_pos = Point { x, y };
- let rect = self.world_rect.lock().unwrap().clone();
- // clicking inside box will:
- // 1. make it active
- // 2. begin selection
- if rect.contains(&mouse_pos) {
- if !self.is_active.get() {
- self.is_active.set(true);
- println!("inside!");
- // Send signal
- }
- let cpos = match self.find_closest_glyph_idx(x) {
- MouseClickGlyph::Pos(cpos) => cpos,
- _ => panic!("shouldn't be possible to reach here!")
- };
- // set cursor pos
- self.cursor_pos.set(cpos);
- // begin selection
- self.selected.set_u32(0, cpos).unwrap();
- self.selected.set_u32(1, cpos).unwrap();
- self.mouse_btn_held.store(true, Ordering::Relaxed);
- }
- // click outside the box will:
- // 1. make it inactive
- else {
- if self.is_active.get() {
- self.is_active.set(false);
- // Send signal
- }
- }
- }
- fn mouse_button_up(self: Arc<Self>, button: MouseButton, x: f32, y: f32) {
- // releasing mouse button will:
- // 1. end selection
- self.mouse_btn_held.store(false, Ordering::Relaxed);
- }
- fn mouse_move(self: Arc<Self>, x: f32, y: f32) {
- if !self.mouse_btn_held.load(Ordering::Relaxed) {
- return;
- }
- // if active and selection_active, then use x to modify the selection.
- // also implement scrolling when cursor is to the left or right
- // just scroll to the end
- // also set cursor_pos too
- let cpos = match self.find_closest_glyph_idx(x) {
- MouseClickGlyph::Lhs => 0,
- MouseClickGlyph::Pos(cpos) => cpos,
- MouseClickGlyph::Rhs(cpos) => cpos,
- };
- self.cursor_pos.set(cpos);
- self.selected.set_u32(1, cpos).unwrap();
- }
- // Uses screen x pos
- fn find_closest_glyph_idx(&self, x: f32) -> MouseClickGlyph {
- let rect = self.world_rect.lock().unwrap().clone();
- let glyphs = &*self.glyphs.lock().unwrap();
- let mouse_x = x - rect.x;
- if mouse_x > rect.w {
- // Highlight to the end
- let cpos = glyphs.len() as u32;
- return MouseClickGlyph::Rhs(cpos);
- // Scroll to the right handled in render
- } else if mouse_x < 0. {
- return MouseClickGlyph::Lhs;
- }
- let scroll = self.scroll.get();
- let mouse_x = x - rect.x;
- let mut cpos = 0;
- let lhs = 0.;
- let mut last_d = (lhs - mouse_x).abs();
- for (i, glyph) in glyphs.iter().skip(1).enumerate() {
- // Because we skip the first item
- let glyph_idx = (i + 1) as u32;
- let x1 = glyph.pos.x + scroll;
- let curr_d = (x1 - mouse_x).abs();
- if curr_d < last_d {
- last_d = curr_d;
- cpos = glyph_idx;
- }
- }
- // also check the right hand side
- let rhs = {
- let glyph = &glyphs.last().unwrap();
- glyph.pos.x + scroll + glyph.pos.w
- };
- let curr_d = (rhs - mouse_x).abs();
- if curr_d < last_d {
- //last_d = curr_d;
- cpos = glyphs.len() as u32;
- }
- MouseClickGlyph::Pos(cpos)
- }
- }
- enum MouseClickGlyph {
- Lhs,
- Pos(u32),
- Rhs(u32)
- }
|