darkfi 2 лет назад
Родитель
Сommit
c9e13255cf

+ 107 - 1
bin/darkwallet/src/app.rs

@@ -8,7 +8,7 @@ use crate::{
     prop::{Property, PropertySubType, PropertyType},
     scene::{Pimpl, SceneGraph, SceneGraphPtr2, SceneNodeId, SceneNodeType},
     text2::TextShaperPtr,
-    ui::{Mesh, RenderLayer, Stoppable, Text, Window},
+    ui::{EditBox, Mesh, RenderLayer, Stoppable, Text, Window},
 };
 
 //fn print_type_of<T>(_: &T) {
@@ -317,6 +317,57 @@ impl App {
         node.pimpl = pimpl;
 
         sg.link(node_id, layer_node_id).unwrap();
+
+        // Text edit
+        let node_id = create_editbox(&mut sg, "editz");
+        let node = sg.get_node(node_id).unwrap();
+        node.set_property_bool("is_active", true).unwrap();
+        let prop = node.get_property("rect").unwrap();
+        prop.set_f32(0, 150.).unwrap();
+        let code =
+            vec![Op::Sub((Box::new(Op::LoadVar("lh".to_string())), Box::new(Op::ConstFloat32(60.))))];
+        prop.set_expr(1, code).unwrap();
+        let code =
+            vec![Op::Sub((Box::new(Op::LoadVar("lw".to_string())), Box::new(Op::ConstFloat32(120.))))];
+        prop.set_expr(2, code).unwrap();
+        prop.set_f32(3, 60.).unwrap();
+        node.set_property_f32("baseline", 40.).unwrap();
+        node.set_property_f32("font_size", 20.).unwrap();
+        node.set_property_str("text", "hello king!😁🍆jelly 🍆1234").unwrap();
+        let prop = node.get_property("text_color").unwrap();
+        prop.set_f32(0, 1.).unwrap();
+        prop.set_f32(1, 1.).unwrap();
+        prop.set_f32(2, 1.).unwrap();
+        prop.set_f32(3, 1.).unwrap();
+        let prop = node.get_property("cursor_color").unwrap();
+        prop.set_f32(0, 1.).unwrap();
+        prop.set_f32(1, 0.5).unwrap();
+        prop.set_f32(2, 0.5).unwrap();
+        prop.set_f32(3, 1.).unwrap();
+        let prop = node.get_property("hi_bg_color").unwrap();
+        prop.set_f32(0, 1.).unwrap();
+        prop.set_f32(1, 1.).unwrap();
+        prop.set_f32(2, 1.).unwrap();
+        prop.set_f32(3, 0.5).unwrap();
+        let prop = node.get_property("selected").unwrap();
+        prop.set_null(0).unwrap();
+        prop.set_null(1).unwrap();
+        node.set_property_u32("z_index", 1).unwrap();
+
+        drop(sg);
+        let pimpl = EditBox::new(
+            //self.ex.clone(),
+            //self.sg.clone(),
+            //node_id,
+            //self.render_api.clone(),
+            //self.text_shaper.clone(),
+        )
+        .await;
+        let mut sg = self.sg.lock().await;
+        let node = sg.get_node_mut(node_id).unwrap();
+        node.pimpl = pimpl;
+
+        sg.link(node_id, layer_node_id).unwrap();
     }
 
     async fn trigger_redraw(&self) {
@@ -386,3 +437,58 @@ fn create_text(sg: &mut SceneGraph, name: &str) -> SceneNodeId {
 
     node.id
 }
+
+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);
+    node.add_property(prop).unwrap();
+
+    let mut prop = Property::new("rect", PropertyType::Float32, PropertySubType::Pixel);
+    prop.set_array_len(4);
+    prop.allow_exprs();
+    node.add_property(prop).unwrap();
+
+    let mut prop = Property::new("baseline", PropertyType::Float32, PropertySubType::Pixel);
+    node.add_property(prop).unwrap();
+
+    let mut prop = Property::new("scroll", PropertyType::Float32, PropertySubType::Pixel);
+    node.add_property(prop).unwrap();
+
+    let mut prop = Property::new("cursor_pos", PropertyType::Uint32, PropertySubType::Pixel);
+    node.add_property(prop).unwrap();
+
+    let mut prop = Property::new("font_size", PropertyType::Float32, PropertySubType::Pixel);
+    node.add_property(prop).unwrap();
+
+    let mut prop = Property::new("text", PropertyType::Str, PropertySubType::Null);
+    node.add_property(prop).unwrap();
+
+    let mut prop = Property::new("text_color", PropertyType::Float32, PropertySubType::Color);
+    prop.set_array_len(4);
+    prop.set_range_f32(0., 1.);
+    node.add_property(prop).unwrap();
+
+    let mut prop = Property::new("cursor_color", PropertyType::Float32, PropertySubType::Color);
+    prop.set_array_len(4);
+    prop.set_range_f32(0., 1.);
+    node.add_property(prop).unwrap();
+
+    let mut prop = Property::new("hi_bg_color", PropertyType::Float32, PropertySubType::Color);
+    prop.set_array_len(4);
+    prop.set_range_f32(0., 1.);
+    node.add_property(prop).unwrap();
+
+    let mut prop = Property::new("selected", PropertyType::Uint32, PropertySubType::Color);
+    prop.set_array_len(2);
+    prop.allow_null_values();
+    node.add_property(prop).unwrap();
+
+    let mut prop = Property::new("z_index", PropertyType::Uint32, PropertySubType::Null);
+    node.add_property(prop).unwrap();
+
+    let mut prop = Property::new("debug", PropertyType::Bool, PropertySubType::Null);
+    node.add_property(prop).unwrap();
+
+    node.id
+}

+ 23 - 4
bin/darkwallet/src/gfx2.rs

@@ -8,14 +8,14 @@ use miniquad::{
 };
 use std::{
     collections::HashMap,
-    sync::{mpsc, Arc},
+    sync::{mpsc, Arc, Mutex as SyncMutex},
     time::{Duration, Instant},
 };
 
 use crate::{
     app::AsyncRuntime,
     error::{Error, Result},
-    pubsub::{Publisher, PublisherPtr, Subscription},
+    pubsub::{Publisher, PublisherPtr, Subscription, SubscriptionId},
     shader,
     util::ansi_texture,
 };
@@ -301,17 +301,36 @@ pub enum GraphicsMethod {
 pub type GraphicsEventPublisherPtr = Arc<GraphicsEventPublisher>;
 
 pub struct GraphicsEventPublisher {
+    lock_key_down: SyncMutex<Option<SubscriptionId>>,
     key_down: PublisherPtr<(KeyCode, KeyMods, bool)>,
+
     resize: PublisherPtr<(f32, f32)>,
 }
 
 impl GraphicsEventPublisher {
     pub fn new() -> Arc<Self> {
-        Arc::new(Self { key_down: Publisher::new(), resize: Publisher::new() })
+        Arc::new(Self {
+            lock_key_down: SyncMutex::new(None),
+            key_down: Publisher::new(),
+            resize: Publisher::new() })
+    }
+
+    fn lock_key_down(&self, sub_id: SubscriptionId) {
+        *self.lock_key_down.lock().unwrap() = Some(sub_id);
+    }
+    fn unlock_key_down(&self) {
+        *self.lock_key_down.lock().unwrap() = None;
     }
 
     fn notify_key_down(&self, key: KeyCode, mods: KeyMods, repeat: bool) {
-        self.key_down.notify((key, mods, repeat));
+        let ev = (key, mods, repeat);
+
+        let locked = self.lock_key_down.lock().unwrap().clone();
+        if let Some(locked) = locked {
+            self.key_down.notify_with_include(ev, &[locked]);
+        } else {
+            self.key_down.notify(ev);
+        }
     }
     fn notify_resize(&self, w: f32, h: f32) {
         self.resize.notify((w, h));

+ 19 - 1
bin/darkwallet/src/pubsub.rs

@@ -64,9 +64,27 @@ impl<T: Piped> Publisher<T> {
         self.subs.lock().unwrap().remove(&sub_id);
     }
 
+    /// Publish a message to subscriptions in the include list
+    pub async fn notify_with_include(&self, message_result: T, include_list: &[SubscriptionId]) {
+        // Maybe we should just provide a method to get all IDs
+        // Then people can call notify_with_exclude() instead.
+        // TODO: just collect and clone directly into a Vec
+        let subs = self.subs.lock().unwrap().clone();
+        for (id, sub) in subs.into_iter() {
+            if !include_list.contains(&id) {
+                continue
+            }
+
+            if let Err(e) = sub.send(message_result.clone()).await {
+                panic!("[system::publisher] Error returned sending message in notify_with_include() call! {}", e);
+            }
+        }
+    }
+
     /// Publish a message to all listening subscriptions.
     pub fn notify(&self, msg: T) {
-        for (id, sub) in self.subs.lock().unwrap().iter() {
+        let subs = self.subs.lock().unwrap().clone();
+        for (id, sub) in subs {
             if let Err(e) = sub.try_send(msg.clone()) {
                 // This should never happen since Drop calls unsubscribe()
                 panic!("Error in notify() call for sub={}! {}", id, e);

+ 1 - 0
bin/darkwallet/src/scene.rs

@@ -633,6 +633,7 @@ pub enum Pimpl {
     RenderLayer(ui::RenderLayerPtr),
     Mesh(ui::MeshPtr),
     Text(ui::TextPtr),
+    EditBox(ui::EditBoxPtr),
 }
 
 impl std::fmt::Debug for SceneNode {

+ 25 - 0
bin/darkwallet/src/ui/editbox.rs

@@ -0,0 +1,25 @@
+use std::sync::{Arc, Mutex, Weak};
+
+use crate::scene::Pimpl;
+
+// First refactor the event system
+// Each event should have its own unique pipe
+// Advantages:
+// - less overhead when publishing msgs to ppl who dont need them
+// - more advanced locking of streams when widgets capture input
+// also add capturing and make use of it with editbox.
+
+pub type EditBoxPtr = Arc<EditBox>;
+
+pub struct EditBox {
+}
+
+impl EditBox {
+    pub async fn new(
+    ) -> Pimpl {
+        let self_ = Arc::new(Self {});
+
+        Pimpl::EditBox(self_)
+    }
+}
+

+ 2 - 0
bin/darkwallet/src/ui/mod.rs

@@ -8,6 +8,8 @@ use crate::{
     scene::{SceneGraph, SceneNode, SceneNodeId, SceneNodeType},
 };
 
+mod editbox;
+pub use editbox::{EditBox, EditBoxPtr};
 mod mesh;
 pub use mesh::{Mesh, MeshPtr};
 mod layer;