Просмотр исходного кода

wallet: woo editbox cursor scrolling bitches

darkfi 2 лет назад
Родитель
Сommit
6442d4f30a
1 измененных файлов с 138 добавлено и 4 удалено
  1. 138 4
      bin/darkwallet/src/ui/editbox.rs

+ 138 - 4
bin/darkwallet/src/ui/editbox.rs

@@ -255,6 +255,9 @@ impl EditBox {
         let font_size = self.font_size.get();
         let text_color = self.text_color.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 debug = self.debug.get();
         debug!(target: "ui::editbox", "Rendering text '{}' clip={:?}", text, clip);
 
@@ -263,15 +266,37 @@ impl EditBox {
 
         let mut mesh = MeshBuilder::with_clip(clip.clone());
         let mut glyph_pos_iter = GlyphPositionIter::new(font_size, &glyphs, baseline);
-        for (glyph_idx, uv_rect, glyph_rect, glyph) in
+        // Used for drawing the cursor when it's at the end of the line.
+        let mut rhs = 0.;
+
+        for (glyph_idx, uv_rect, mut glyph_rect, glyph) in
             zip3(atlas.uv_rects.into_iter(), glyph_pos_iter, glyphs.iter())
         {
+            glyph_rect.x += scroll;
+
             //mesh.draw_outline(&glyph_rect, COLOR_BLUE, 2.);
             let mut color = text_color.clone();
             if glyph.sprite.has_color {
                 color = COLOR_WHITE;
             }
             mesh.draw_box(&glyph_rect, color, &uv_rect);
+
+            if cursor_pos != 0 && cursor_pos == glyph_idx {
+                let cursor_rect =
+                    Rectangle { x: glyph_rect.x - CURSOR_WIDTH, y: 0., w: CURSOR_WIDTH, h: clip.h };
+                mesh.draw_box(&cursor_rect, cursor_color, &Rectangle::zero());
+            }
+
+            rhs = glyph_rect.rhs();
+        }
+
+        if cursor_pos == 0 {
+            let cursor_rect = Rectangle { x: 0., y: 0., w: CURSOR_WIDTH, h: clip.h };
+            mesh.draw_box(&cursor_rect, cursor_color, &Rectangle::zero());
+        } else if cursor_pos == glyphs.len() {
+            let cursor_rect =
+                Rectangle { x: rhs - CURSOR_WIDTH, y: 0., w: CURSOR_WIDTH, h: clip.h };
+            mesh.draw_box(&cursor_rect, cursor_color, &Rectangle::zero());
         }
 
         if debug {
@@ -338,7 +363,10 @@ impl EditBox {
             let mut repeater = self_.key_repeat.lock().unwrap();
             repeater.key_down(PressedKey::Key(key), repeat)
         };
-        debug!(target: "ui::editbox", "Key {:?} has {} actions", key, actions);
+        // Suppress noisy message
+        if actions > 0 {
+            debug!(target: "ui::editbox", "Key {:?} has {} actions", key, actions);
+        }
         for _ in 0..actions {
             self_.handle_key(&key, &mods).await;
         }
@@ -380,8 +408,67 @@ impl EditBox {
     async fn handle_key(&self, key: &KeyCode, mods: &KeyMods) {
         debug!(target: "ui::editbox", "handle_key({:?}, {:?})", key, mods);
         match key {
-            //KeyCode::Left,
-            //KeyCode::Right,
+            KeyCode::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!(target: "ui::editbox", "Left cursor_pos={}", cursor_pos);
+                    self.cursor_pos.set(cursor_pos);
+                }
+
+                // Update selection
+                /*
+                if mods.shift {
+                    self.selected.set_u32(1, cursor_pos).unwrap();
+                }
+                */
+
+                self.apply_cursor_scrolling();
+                self.redraw().await;
+            }
+            KeyCode::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!(target: "ui::editbox", "Right cursor_pos={}", cursor_pos);
+                    self.cursor_pos.set(cursor_pos);
+                }
+
+                // Update selection
+                /*
+                if mods.shift {
+                    self.selected.set_u32(1, cursor_pos).unwrap();
+                }
+                */
+
+                self.apply_cursor_scrolling();
+                self.redraw().await;
+            }
             //KeyCode::Up,
             //KeyCode::Down,
             //KeyCode::Enter,
@@ -402,6 +489,53 @@ impl EditBox {
         }
     }
 
+    /// Beware of this method. Here be dragons.
+    /// Possibly racy so we limit it just to cursor scrolling.
+    fn cached_rect(&self) -> Rectangle {
+        let Ok(rect) = read_rect(self.rect.clone()) else {
+            panic!("Node bad rect property");
+        };
+        rect
+    }
+
+    fn apply_cursor_scrolling(&self) {
+        // This may need updating but yolo rite
+        let rect = self.cached_rect();
+
+        let cursor_pos = self.cursor_pos.get() as usize;
+        let mut scroll = self.scroll.get();
+
+        let cursor_x = {
+            let font_size = self.font_size.get();
+            let baseline = self.baseline.get();
+            let glyphs = &*self.glyphs.lock().unwrap();
+
+            let mut glyph_pos_iter = GlyphPositionIter::new(font_size, &glyphs, baseline);
+
+            if cursor_pos == 0 {
+                0.
+            } else if cursor_pos == glyphs.len() {
+                let glyph_pos = glyph_pos_iter.last().unwrap();
+                glyph_pos.rhs()
+            } else {
+                assert!(cursor_pos < glyphs.len());
+                let glyph_pos = glyph_pos_iter.nth(cursor_pos).expect("glyph pos mismatch glyphs");
+                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);
+    }
+
     async fn redraw(&self) {
         let old = self.render_info.lock().unwrap().clone();