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

wallet: editbox click to focus/unfocus editing

darkfi 2 лет назад
Родитель
Сommit
77417cc9b8
3 измененных файлов с 239 добавлено и 13 удалено
  1. 5 0
      bin/darkwallet/src/app.rs
  2. 139 9
      bin/darkwallet/src/gfx2.rs
  3. 95 4
      bin/darkwallet/src/ui/editbox.rs

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

@@ -451,6 +451,11 @@ fn create_editbox(sg: &mut SceneGraph, name: &str) -> SceneNodeId {
     let node = sg.add_node(name, SceneNodeType::EditBox);
 
     let mut prop = Property::new("is_active", PropertyType::Bool, PropertySubType::Null);
+    prop.set_ui_text("Is Active", "An active EditBox can be focused");
+    node.add_property(prop).unwrap();
+
+    let mut prop = Property::new("is_focused", PropertyType::Bool, PropertySubType::Null);
+    prop.set_ui_text("Is Focused", "A focused EditBox receives input");
     node.add_property(prop).unwrap();
 
     let mut prop = Property::new("rect", PropertyType::Float32, PropertySubType::Pixel);

+ 139 - 9
bin/darkwallet/src/gfx2.rs

@@ -2,9 +2,9 @@ use darkfi_serial::{SerialDecodable, SerialEncodable};
 use log::debug;
 use miniquad::{
     conf, window, Backend, Bindings, BlendFactor, BlendState, BlendValue, BufferId, BufferLayout,
-    BufferSource, BufferType, BufferUsage, Equation, EventHandler, KeyCode, KeyMods, PassAction,
-    Pipeline, PipelineParams, RenderingBackend, ShaderMeta, ShaderSource, TextureId, UniformDesc,
-    UniformType, VertexAttribute, VertexFormat,
+    BufferSource, BufferType, BufferUsage, Equation, EventHandler, KeyCode, KeyMods, MouseButton,
+    PassAction, Pipeline, PipelineParams, RenderingBackend, ShaderMeta, ShaderSource, TextureId,
+    TouchPhase, UniformDesc, UniformType, VertexAttribute, VertexFormat,
 };
 use std::{
     collections::HashMap,
@@ -348,6 +348,18 @@ pub struct GraphicsEventPublisher {
     lock_key_up: SyncMutex<Option<SubscriptionId>>,
     key_up: PublisherPtr<(KeyCode, KeyMods)>,
 
+    lock_mouse_motion: SyncMutex<Option<SubscriptionId>>,
+    mouse_motion: PublisherPtr<(f32, f32)>,
+
+    lock_mouse_wheel: SyncMutex<Option<SubscriptionId>>,
+    mouse_wheel: PublisherPtr<(f32, f32)>,
+
+    lock_mouse_btn_down: SyncMutex<Option<SubscriptionId>>,
+    mouse_btn_down: PublisherPtr<(MouseButton, f32, f32)>,
+
+    lock_mouse_btn_up: SyncMutex<Option<SubscriptionId>>,
+    mouse_btn_up: PublisherPtr<(MouseButton, f32, f32)>,
+
     lock_resize: SyncMutex<Option<SubscriptionId>>,
     resize: PublisherPtr<(f32, f32)>,
 
@@ -360,10 +372,25 @@ impl GraphicsEventPublisher {
         Arc::new(Self {
             lock_key_down: SyncMutex::new(None),
             key_down: Publisher::new(),
+
             lock_key_up: SyncMutex::new(None),
             key_up: Publisher::new(),
+
+            lock_mouse_motion: SyncMutex::new(None),
+            mouse_motion: Publisher::new(),
+
+            lock_mouse_wheel: SyncMutex::new(None),
+            mouse_wheel: Publisher::new(),
+
+            lock_mouse_btn_down: SyncMutex::new(None),
+            mouse_btn_down: Publisher::new(),
+
+            lock_mouse_btn_up: SyncMutex::new(None),
+            mouse_btn_up: Publisher::new(),
+
             lock_resize: SyncMutex::new(None),
             resize: Publisher::new(),
+
             lock_char: SyncMutex::new(None),
             chr: Publisher::new(),
         })
@@ -383,6 +410,34 @@ impl GraphicsEventPublisher {
         *self.lock_key_up.lock().unwrap() = None;
     }
 
+    fn lock_mouse_motion(&self, sub_id: SubscriptionId) {
+        *self.lock_mouse_motion.lock().unwrap() = Some(sub_id);
+    }
+    fn unlock_mouse_motion(&self) {
+        *self.lock_mouse_motion.lock().unwrap() = None;
+    }
+
+    fn lock_mouse_wheel(&self, sub_id: SubscriptionId) {
+        *self.lock_mouse_wheel.lock().unwrap() = Some(sub_id);
+    }
+    fn unlock_mouse_wheel(&self) {
+        *self.lock_mouse_wheel.lock().unwrap() = None;
+    }
+
+    fn lock_mouse_btn_down(&self, sub_id: SubscriptionId) {
+        *self.lock_mouse_btn_down.lock().unwrap() = Some(sub_id);
+    }
+    fn unlock_mouse_btn_down(&self) {
+        *self.lock_mouse_btn_down.lock().unwrap() = None;
+    }
+
+    fn lock_mouse_btn_up(&self, sub_id: SubscriptionId) {
+        *self.lock_mouse_btn_up.lock().unwrap() = Some(sub_id);
+    }
+    fn unlock_mouse_btn_up(&self) {
+        *self.lock_mouse_btn_up.lock().unwrap() = None;
+    }
+
     fn lock_resize(&self, sub_id: SubscriptionId) {
         *self.lock_resize.lock().unwrap() = Some(sub_id);
     }
@@ -417,6 +472,51 @@ impl GraphicsEventPublisher {
             self.key_up.notify(ev);
         }
     }
+
+    fn notify_mouse_motion(&self, x: f32, y: f32) {
+        let ev = (x, y);
+
+        let locked = self.lock_mouse_motion.lock().unwrap().clone();
+        if let Some(locked) = locked {
+            self.mouse_motion.notify_with_include(ev, &[locked]);
+        } else {
+            self.mouse_motion.notify(ev);
+        }
+    }
+
+    fn notify_mouse_wheel(&self, x: f32, y: f32) {
+        let ev = (x, y);
+
+        let locked = self.lock_mouse_wheel.lock().unwrap().clone();
+        if let Some(locked) = locked {
+            self.mouse_wheel.notify_with_include(ev, &[locked]);
+        } else {
+            self.mouse_wheel.notify(ev);
+        }
+    }
+
+    fn notify_mouse_btn_down(&self, button: MouseButton, x: f32, y: f32) {
+        let ev = (button, x, y);
+
+        let locked = self.lock_mouse_btn_down.lock().unwrap().clone();
+        if let Some(locked) = locked {
+            self.mouse_btn_down.notify_with_include(ev, &[locked]);
+        } else {
+            self.mouse_btn_down.notify(ev);
+        }
+    }
+
+    fn notify_mouse_btn_up(&self, button: MouseButton, x: f32, y: f32) {
+        let ev = (button, x, y);
+
+        let locked = self.lock_mouse_btn_up.lock().unwrap().clone();
+        if let Some(locked) = locked {
+            self.mouse_btn_up.notify_with_include(ev, &[locked]);
+        } else {
+            self.mouse_btn_up.notify(ev);
+        }
+    }
+
     fn notify_resize(&self, w: f32, h: f32) {
         let ev = (w, h);
 
@@ -444,6 +544,18 @@ impl GraphicsEventPublisher {
     pub fn subscribe_key_up(&self) -> Subscription<(KeyCode, KeyMods)> {
         self.key_up.clone().subscribe()
     }
+    pub fn subscribe_mouse_motion(&self) -> Subscription<(f32, f32)> {
+        self.mouse_motion.clone().subscribe()
+    }
+    pub fn subscribe_mouse_wheel(&self) -> Subscription<(f32, f32)> {
+        self.mouse_wheel.clone().subscribe()
+    }
+    pub fn subscribe_mouse_btn_down(&self) -> Subscription<(MouseButton, f32, f32)> {
+        self.mouse_btn_down.clone().subscribe()
+    }
+    pub fn subscribe_mouse_btn_up(&self) -> Subscription<(MouseButton, f32, f32)> {
+        self.mouse_btn_up.clone().subscribe()
+    }
     pub fn subscribe_resize(&self) -> Subscription<(f32, f32)> {
         self.resize.clone().subscribe()
     }
@@ -655,23 +767,41 @@ impl EventHandler for Stage {
         self.ctx.commit_frame();
     }
 
+    fn resize_event(&mut self, width: f32, height: f32) {
+        self.event_pub.notify_resize(width, height);
+    }
+
+    fn mouse_motion_event(&mut self, x: f32, y: f32) {
+        self.event_pub.notify_mouse_motion(x, y);
+    }
+    fn mouse_wheel_event(&mut self, x: f32, y: f32) {
+        self.event_pub.notify_mouse_wheel(x, y);
+    }
+    fn mouse_button_down_event(&mut self, button: MouseButton, x: f32, y: f32) {
+        self.event_pub.notify_mouse_btn_down(button, x, y);
+    }
+    fn mouse_button_up_event(&mut self, button: MouseButton, x: f32, y: f32) {
+        self.event_pub.notify_mouse_btn_up(button, x, y);
+    }
+
+    fn char_event(&mut self, chr: char, mods: KeyMods, repeat: bool) {
+        self.event_pub.notify_char(chr, mods, repeat);
+    }
+
     fn key_down_event(&mut self, keycode: KeyCode, mods: KeyMods, repeat: bool) {
         self.event_pub.notify_key_down(keycode, mods, repeat);
     }
     fn key_up_event(&mut self, keycode: KeyCode, mods: KeyMods) {
         self.event_pub.notify_key_up(keycode, mods);
     }
-    fn resize_event(&mut self, width: f32, height: f32) {
-        self.event_pub.notify_resize(width, height);
+
+    fn touch_event(&mut self, phase: TouchPhase, id: u64, x: f32, y: f32) {
+        debug!(target: "gfx", "touch_event({:?}, {}, {}, {})", phase, id, x, y);
     }
 
     fn quit_requested_event(&mut self) {
         self.async_runtime.stop();
     }
-
-    fn char_event(&mut self, chr: char, mods: KeyMods, repeat: bool) {
-        self.event_pub.notify_char(chr, mods, repeat);
-    }
 }
 
 pub fn run_gui(

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

@@ -1,4 +1,4 @@
-use miniquad::{window, BufferId, KeyCode, KeyMods, TextureId};
+use miniquad::{window, BufferId, KeyCode, KeyMods, MouseButton, TextureId};
 use rand::{rngs::OsRng, Rng};
 use std::{
     collections::HashMap,
@@ -9,8 +9,8 @@ use std::{
 use crate::{
     error::Result,
     gfx2::{
-        DrawCall, DrawInstruction, DrawMesh, GraphicsEventPublisherPtr, Rectangle, RenderApi,
-        RenderApiPtr, Vertex,
+        DrawCall, DrawInstruction, DrawMesh, GraphicsEventPublisherPtr, Point, Rectangle,
+        RenderApi, RenderApiPtr, Vertex,
     },
     mesh::{Color, MeshBuilder, MeshInfo, COLOR_BLUE, COLOR_WHITE},
     prop::{
@@ -126,6 +126,7 @@ pub struct EditBox {
     dc_key: u64,
 
     is_active: PropertyBool,
+    is_focused: PropertyBool,
     rect: PropertyPtr,
     baseline: PropertyFloat32,
     scroll: PropertyFloat32,
@@ -151,7 +152,10 @@ impl EditBox {
     ) -> Pimpl {
         let scene_graph = sg.lock().await;
         let node = scene_graph.get_node(node_id).unwrap();
+        let node_name = node.name.clone();
+
         let is_active = PropertyBool::wrap(node, "is_active", 0).unwrap();
+        let is_focused = PropertyBool::wrap(node, "is_focused", 0).unwrap();
         let rect = node.get_property("rect").expect("EditBox::rect");
         let baseline = PropertyFloat32::wrap(node, "baseline", 0).unwrap();
         let scroll = PropertyFloat32::wrap(node, "scroll", 0).unwrap();
@@ -164,6 +168,7 @@ impl EditBox {
         let selected = node.get_property("selected").unwrap();
         let z_index = PropertyUint32::wrap(node, "z_index", 0).unwrap();
         let debug = PropertyBool::wrap(node, "debug", 0).unwrap();
+
         drop(scene_graph);
 
         // testing
@@ -211,8 +216,19 @@ impl EditBox {
             });
             */
 
+            let ev_sub = event_pub.subscribe_mouse_btn_down();
+            let me2 = me.clone();
+            let mouse_btn_down_task = ex.spawn(async move {
+                loop {
+                    Self::process_mouse_btn_down(&me2, &ev_sub).await;
+                }
+            });
+
+            let mut on_modify = OnModify::new(ex, node_name, node_id, me.clone());
+            on_modify.when_change(is_focused.prop(), Self::change_focus);
+
             // on modify tasks too
-            let tasks = vec![char_task, key_down_task];
+            let tasks = vec![char_task, key_down_task, mouse_btn_down_task];
 
             Self {
                 node_id,
@@ -228,6 +244,7 @@ impl EditBox {
                 dc_key: OsRng.gen(),
 
                 is_active,
+                is_focused,
                 rect,
                 baseline,
                 scroll,
@@ -388,6 +405,10 @@ impl EditBox {
             panic!("self destroyed before char_task was stopped!");
         };
 
+        if !self_.is_focused.get() {
+            return
+        }
+
         if mods.ctrl || mods.alt {
             if repeat {
                 return
@@ -423,6 +444,10 @@ impl EditBox {
             panic!("self destroyed before char_task was stopped!");
         };
 
+        if !self_.is_focused.get() {
+            return
+        }
+
         let actions = {
             let mut repeater = self_.key_repeat.lock().unwrap();
             repeater.key_down(PressedKey::Key(key), repeat)
@@ -436,6 +461,72 @@ impl EditBox {
         }
     }
 
+    async fn process_mouse_btn_down(
+        me: &Weak<Self>,
+        ev_sub: &Subscription<(MouseButton, f32, f32)>,
+    ) {
+        let Ok((btn, mouse_x, mouse_y)) = ev_sub.receive().await else {
+            debug!(target: "ui::editbox", "Event relayer closed");
+            return
+        };
+
+        let Some(self_) = me.upgrade() else {
+            // Should not happen
+            panic!("self destroyed before char_task was stopped!");
+        };
+
+        if !self_.is_active.get() {
+            return
+        }
+
+        self_.handle_mouse_btn_down(btn, mouse_x, mouse_y).await;
+    }
+
+    async fn change_focus(self: Arc<Self>) {
+        if !self.is_active.get() {
+            return
+        }
+
+        let is_focused = self.is_focused.get();
+    }
+
+    async fn handle_mouse_btn_down(&self, btn: MouseButton, mouse_x: f32, mouse_y: f32) {
+        if btn != MouseButton::Left {
+            return
+        }
+
+        // NBD if it's slightly wrong
+        let mut rect = self.cached_rect();
+
+        // If layers can be nested and we use offsets for (x, y)
+        // then this will be incorrect for nested layers.
+        // For now we don't allow nesting of layers.
+        let sg = self.sg.lock().await;
+        let node = sg.get_node(self.node_id).unwrap();
+        let Some(parent_rect) = get_parent_rect(&sg, node) else {
+            return;
+        };
+        drop(sg);
+
+        // Offset rect which is now in world coords
+        rect.x += parent_rect.x;
+        rect.y += parent_rect.y;
+
+        let mouse_pos = Point::from([mouse_x, mouse_y]);
+
+        if rect.contains(&mouse_pos) {
+            if self.is_focused.get() {
+                debug!(target: "ui::editbox", "EditBox clicked");
+            } else {
+                debug!(target: "ui::editbox", "EditBox focused");
+                self.is_focused.set(true);
+            }
+        } else if self.is_focused.get() {
+            debug!(target: "ui::editbox", "EditBox unfocused");
+            self.is_focused.set(false);
+        }
+    }
+
     async fn insert_char(&self, key: char) {
         if !self.selected.is_null(0).unwrap() {
             self.delete_highlighted();