Browse Source

Change TextEdit to use pushed text input.

Kestrel 1 month ago
parent
commit
a4ce0c8939
5 changed files with 43 additions and 12 deletions
  1. 1 1
      src/layout.rs
  2. 7 2
      src/render/text.rs
  3. 1 1
      src/ui.rs
  4. 27 8
      src/widget/text_edit.rs
  5. 7 0
      src/window.rs

+ 1 - 1
src/layout.rs

@@ -552,7 +552,7 @@ impl<'l> Iterator for LayoutChildIter<'l> {
 /// This trait accepts a tag type parameter to allow a single struct to store multiple layout nodes
 /// with internal edges. Use a `Tag` type of `()` or similar to denote a struct that only
 /// stores a single layout node.
-pub trait LayoutTreeNode<Tag: 'static> {
+pub trait LayoutTreeNode<Tag: 'static = ()> {
     fn current_node(&self) -> &LayoutNode;
     fn child_count(&self) -> usize;
     fn child(&self, ndx: usize) -> Option<LayoutNodeAccess<'_>>;

+ 7 - 2
src/render/text.rs

@@ -11,7 +11,7 @@ pub struct TextCache {
     text: String,
     font: Rc<fontdue::Font>,
     pxsize: f32,
-    x_offsets: Vec<u32>,
+    pub(crate) x_offsets: RefCell<Vec<u32>>,
     rendered: RefCell<Option<kahlo::Alphamap>>,
 }
 
@@ -21,7 +21,7 @@ impl TextCache {
             text: String::new(),
             font,
             pxsize,
-            x_offsets: vec![],
+            x_offsets: vec![].into(),
             rendered: Default::default(),
         }
     }
@@ -122,6 +122,9 @@ impl TextCache {
         let mut alphamap =
             kahlo::Alphamap::new(alphamap_size.width as usize, alphamap_size.height as usize);
 
+        let mut x_offsets = self.x_offsets.borrow_mut();
+        x_offsets.clear();
+
         // pass: generate alphamap
         for (offset, _width, ch) in self.generate_baseline_offsets(pxsize, text) {
             let (metrics, raster) = self.font.rasterize(ch, pxsize);
@@ -131,6 +134,8 @@ impl TextCache {
                 metrics.height,
             );
 
+            x_offsets.push(offset);
+
             alphamap.copy_from(
                 &character_alphamap,
                 PixelBox::from_size(character_alphamap.size()),

+ 1 - 1
src/ui.rs

@@ -210,7 +210,7 @@ impl<UIC: UIComponent> winit::application::ApplicationHandler<()> for UI<UIC> {
                     wsa.request_redraw();
                 }
             }
-            _ => {}
+            _evt => {}
         }
     }
 }

+ 27 - 8
src/widget/text_edit.rs

@@ -17,6 +17,10 @@ pub enum CursorPosition {
     End,
 }
 
+/*impl CursorPosition {
+
+}*/
+
 pub struct TextEdit<C: Component> {
     lnode: LeafLayoutNode,
     text: TextCache,
@@ -39,7 +43,7 @@ impl<C: Component> TextEdit<C> {
                 uih.theme().ui_font.clone(),
                 uih.theme().ui_font_size,
             ),
-            cursor_pos: CursorPosition::End,
+            cursor_pos: CursorPosition::Start,
             onchange: None,
             focused: false,
         }
@@ -65,6 +69,7 @@ impl<C: Component> Widget<C> for TextEdit<C> {
         };
 
         if istate.is_focused(self.lnode.id()) {
+            let mut key_press_eaten = true;
             if let Some(kp) = &istate.keypress {
                 match kp {
                     Key::Named(NamedKey::Backspace) => {
@@ -75,18 +80,26 @@ impl<C: Component> Widget<C> for TextEdit<C> {
                         self.text.change(String::pop);
                         self.lnode.render_needed();
                     }
+                    Key::Named(NamedKey::Space) => {
+                        self.text.change(|v| v.push(' '));
+                        self.lnode.render_needed();
+                    }
                     Key::Named(NamedKey::Enter) => {
                         istate.clear_focus();
                     }
-                    _ => {
-                        if let Some(inp) = &istate.text_input {
-                            self.text.change(|s| s.push_str(inp.as_str()));
-                            self.lnode.render_needed();
-                        }
-                    }
+                    Key::Named(_) => {}
+                    _ => key_press_eaten = false,
+                }
+            }
+            if !key_press_eaten {
+                if let Some(text) = &istate.text_input {
+                    println!("adding text {text:?}");
+                    self.text.change(|s| s.push_str(text.as_str()));
+                    self.lnode.render_needed();
                 }
             }
         }
+
         let render_area = self.lnode.render_area().unwrap();
         if istate
             .mouse_status_in(render_area, MouseButton::Left)
@@ -121,7 +134,13 @@ impl<C: Component> Widget<C> for TextEdit<C> {
             .simple_text(&self.text, ColourChoice::Foreground)
             .seq(|target| {
                 if self.focused {
-                    let cbar_offset = self.text.size_hint().width;
+                    let cbar_offset = match self.cursor_pos {
+                        CursorPosition::Start => 0,
+                        CursorPosition::Index(idx) => {
+                            *self.text.x_offsets.borrow().get(idx).unwrap() as i32
+                        }
+                        CursorPosition::End => self.text.size_hint().width,
+                    };
                     target.fill_relative_box(
                         PixelBox::from_origin_and_size(
                             PixelPoint::new(cbar_offset, 0),

+ 7 - 0
src/window.rs

@@ -167,6 +167,7 @@ pub(crate) trait WindowStateAccess {
     fn update_mouse_button(&self, which: MouseButton, to: bool);
     fn update_text_input(&self, what: &str);
     fn push_keypress(&self, key: winit::keyboard::Key);
+    fn push_text_input(&self, input: String);
 }
 
 impl<WC: WindowComponent> WindowStateAccess for RefCell<WindowState<WC>> {
@@ -222,6 +223,12 @@ impl<WC: WindowComponent> WindowStateAccess for RefCell<WindowState<WC>> {
             is.keypress = Some(key);
         }
     }
+    fn push_text_input(&self, input: String) {
+        let mut win = self.borrow_mut();
+        let is = &mut win.istate;
+
+        is.set_text_input(input);
+    }
 }
 
 pub struct WindowBuilder<'r, 'l: 'r> {