Jelajahi Sumber

wallet/editbox: horizontal mouse wheel scrolling

darkfi 1 tahun lalu
induk
melakukan
e9754c3dab
2 mengubah file dengan 69 tambahan dan 9 penghapusan
  1. 5 0
      bin/darkwallet/src/app/node.rs
  2. 64 9
      bin/darkwallet/src/ui/editbox/mod.rs

+ 5 - 0
bin/darkwallet/src/app/node.rs

@@ -160,6 +160,11 @@ pub fn create_editbox(name: &str) -> SceneNode {
     prop.set_range_f32(0., f32::MAX);
     node.add_property(prop).unwrap();
 
+    let mut prop = Property::new("scroll_speed", PropertyType::Float32, PropertySubType::Pixel);
+    prop.set_ui_text("Scroll Speed", "Scrolling speed");
+    prop.set_defaults_f32(vec![4.]).unwrap();
+    node.add_property(prop).unwrap();
+
     let mut prop = Property::new("cursor_pos", PropertyType::Uint32, PropertySubType::Pixel);
     prop.set_range_u32(0, u32::MAX);
     node.add_property(prop).unwrap();

+ 64 - 9
bin/darkwallet/src/ui/editbox/mod.rs

@@ -227,6 +227,7 @@ pub struct EditBox {
     rect: PropertyRect,
     baseline: PropertyFloat32,
     scroll: PropertyFloat32,
+    scroll_speed: PropertyFloat32,
     cursor_pos: PropertyUint32,
     font_size: PropertyFloat32,
     text: PropertyStr,
@@ -260,6 +261,7 @@ pub struct EditBox {
     old_window_scale: AtomicF32,
     window_scale: PropertyFloat32,
     parent_rect: SyncMutex<Option<Rectangle>>,
+    is_mouse_hover: AtomicBool,
 }
 
 impl EditBox {
@@ -278,6 +280,8 @@ impl EditBox {
         let rect = PropertyRect::wrap(node_ref, Role::Internal, "rect").unwrap();
         let baseline = PropertyFloat32::wrap(node_ref, Role::Internal, "baseline", 0).unwrap();
         let scroll = PropertyFloat32::wrap(node_ref, Role::Internal, "scroll", 0).unwrap();
+        let scroll_speed =
+            PropertyFloat32::wrap(node_ref, Role::Internal, "scroll_speed", 0).unwrap();
         let cursor_pos = PropertyUint32::wrap(node_ref, Role::Internal, "cursor_pos", 0).unwrap();
         let font_size = PropertyFloat32::wrap(node_ref, Role::Internal, "font_size", 0).unwrap();
         let text = PropertyStr::wrap(node_ref, Role::Internal, "text", 0).unwrap();
@@ -326,6 +330,7 @@ impl EditBox {
             rect,
             baseline: baseline.clone(),
             scroll,
+            scroll_speed,
             cursor_pos,
             font_size: font_size.clone(),
             text,
@@ -363,6 +368,7 @@ impl EditBox {
             old_window_scale: AtomicF32::new(window_scale.get()),
             window_scale,
             parent_rect: SyncMutex::new(None),
+            is_mouse_hover: AtomicBool::new(false),
         });
 
         Pimpl::EditBox(self_)
@@ -394,8 +400,7 @@ impl EditBox {
         let rendered = self.editable.lock().unwrap().render();
         let atlas = text::make_texture_atlas(&self.render_api, &rendered.glyphs);
 
-        //let mut mesh = MeshBuilder::with_clip(clip.clone());
-        let mut mesh = MeshBuilder::new();
+        let mut mesh = MeshBuilder::with_clip(clip.clone());
 
         let selections = self.select.lock().unwrap().clone();
         // Just an assert
@@ -451,7 +456,6 @@ impl EditBox {
         let cursor_descent = self.cursor_descent.get();
         let baseline = self.baseline.get();
 
-        let rect_h = self.rect.get().h;
         let cursor_rect = Rectangle {
             x: 0.,
             y: baseline - cursor_ascent,
@@ -1175,13 +1179,38 @@ impl EditBox {
         self.scroll.set(scroll);
     }
 
+    fn max_cursor_scroll(&self) -> f32 {
+        let font_size = self.font_size.get();
+        let window_scale = self.window_scale.get();
+        let baseline = self.baseline.get();
+        let rhs = {
+            let mut editable = self.editable.lock().unwrap();
+            let rendered = editable.render();
+
+            if rendered.glyphs.is_empty() {
+                return 0.
+            }
+            let glyph_pos_iter =
+                GlyphPositionIter::new(font_size, window_scale, &rendered.glyphs, baseline);
+            let last_rect = glyph_pos_iter.last().unwrap();
+            last_rect.x + last_rect.w
+        };
+
+        let rect_w = self.rect.get().w;
+        if rhs <= rect_w {
+            return 0.;
+        }
+        let max_scroll = rhs - rect_w;
+        max_scroll
+    }
+
     fn pause_blinking(&self) {
         self.blink_is_paused.store(true, Ordering::Relaxed);
         self.cursor_is_visible.store(true, Ordering::Relaxed);
     }
 
     async fn redraw(&self) {
-        let Some(draw_update) = self.draw_cached() else {
+        let Some(draw_update) = self.make_draw_calls() else {
             error!(target: "ui::editbox", "Text failed to draw");
             return;
         };
@@ -1210,8 +1239,13 @@ impl EditBox {
 
         let mut cursor_instrs = vec![];
 
+        let rect_w = self.rect.get().w;
+
         let mut cursor_pos = Point::zero();
         cursor_pos.x += self.cursor_px_offset();
+        if cursor_pos.x > rect_w {
+            return vec![]
+        }
         cursor_instrs.push(GfxDrawInstruction::Move(cursor_pos));
 
         let cursor_mesh = {
@@ -1227,7 +1261,7 @@ impl EditBox {
         cursor_instrs
     }
 
-    fn draw_cached(&self) -> Option<DrawUpdate> {
+    fn make_draw_calls(&self) -> Option<DrawUpdate> {
         let rect = self.rect.get();
 
         let text_mesh = self.regen_text_mesh(rect.clone());
@@ -1343,7 +1377,12 @@ impl UIObject for EditBox {
         debug!(target: "ui::editbox", "EditBox::draw()");
         *self.parent_rect.lock().unwrap() = Some(parent_rect);
         self.rect.eval(&parent_rect).ok()?;
-        self.draw_cached()
+
+        let mut scroll = self.scroll.get();
+        scroll = scroll.clamp(0., self.max_cursor_scroll());
+        self.scroll.set(scroll);
+
+        self.make_draw_calls()
     }
 
     async fn handle_char(&self, key: char, mods: KeyMods, repeat: bool) -> bool {
@@ -1474,6 +1513,9 @@ impl UIObject for EditBox {
             return false
         }
 
+        let rect = self.rect.get();
+        self.is_mouse_hover.store(rect.contains(mouse_pos), Ordering::Relaxed);
+
         if !self.mouse_btn_held.load(Ordering::Relaxed) {
             return false;
         }
@@ -1483,8 +1525,6 @@ impl UIObject for EditBox {
         // just scroll to the end
         // also set cursor_pos too
 
-        let rect = self.rect.get();
-
         let font_size = self.font_size.get();
         let window_scale = self.window_scale.get();
         let baseline = self.baseline.get();
@@ -1507,7 +1547,22 @@ impl UIObject for EditBox {
         self.pause_blinking();
         //self.apply_cursor_scrolling();
         self.redraw().await;
-        false
+        true
+    }
+
+    async fn handle_mouse_wheel(&self, wheel_pos: Point) -> bool {
+        //debug!(target: "ui::editbox", "rect={rect:?}, wheel_pos={wheel_pos:?}");
+        if !self.is_mouse_hover.load(Ordering::Relaxed) {
+            return false
+        }
+
+        let mut scroll = self.scroll.get() + wheel_pos.y * self.scroll_speed.get();
+        scroll = scroll.clamp(0., self.max_cursor_scroll());
+        debug!(target: "ui::editbox", "handle_mouse_wheel({wheel_pos:?}) [scroll={scroll}]");
+        self.scroll.set(scroll);
+        self.redraw().await;
+
+        true
     }
 
     async fn handle_touch(&self, phase: TouchPhase, id: u64, touch_pos: Point) -> bool {