Browse Source

wallet: live resizing of layers

darkfi 2 years ago
parent
commit
cfd1e65c39

+ 3 - 0
bin/darkwallet/Makefile

@@ -1,3 +1,6 @@
+default:
+	cargo lrun
+
 android:
 	docker run -v $(shell pwd):/root/dw -v /tmp/miniquad:/tmp/miniquad -w /root/dw -t apk cargo quad-apk build
 	adb uninstall rust.darkwallet

+ 104 - 10
bin/darkwallet/src/app.rs

@@ -205,7 +205,9 @@ impl App {
         // Setup the pimpl
         let node_id = node.id;
         drop(sg);
-        let pimpl = RenderLayer::new(self.sg.clone(), node_id).await;
+        let pimpl =
+            RenderLayer::new(self.sg.clone(), node_id, self.ex.clone(), self.render_api.clone())
+                .await;
         let mut sg = self.sg.lock().await;
         let node = sg.get_node_mut(node_id).unwrap();
         node.pimpl = pimpl;
@@ -403,6 +405,8 @@ pub type RenderLayerPtr = Arc<RenderLayer>;
 pub struct RenderLayer {
     sg: SceneGraphPtr2,
     node_id: SceneNodeId,
+    modify_task: smol::Task<()>,
+    render_api: RenderApiPtr,
 
     dc_key: u64,
 
@@ -413,41 +417,47 @@ pub struct RenderLayer {
 }
 
 impl RenderLayer {
-    pub async fn new(sg_ptr: SceneGraphPtr2, node_id: SceneNodeId) -> Pimpl {
-        let sg_ptr2 = sg_ptr.clone();
-        let sg = sg_ptr2.lock().await;
+    pub async fn new(
+        sg_ptr: SceneGraphPtr2,
+        node_id: SceneNodeId,
+        ex: Arc<smol::Executor<'static>>,
+        render_api: RenderApiPtr,
+    ) -> Pimpl {
+        let sg = sg_ptr.lock().await;
         let node = sg.get_node(node_id).unwrap();
 
         let is_visible =
             PropertyBool::wrap(node, "is_visible", 0).expect("RenderLayer::is_visible");
         let rect = node.get_property("rect").expect("RenderLayer::rect");
+        drop(sg);
 
         // Monitor for changes to screen_size or scale properties
         // If so then trigger draw
         let rect_sub = rect.subscribe_modify();
 
         let self_ = Arc::new_cyclic(|me: &Weak<Self>| {
+            let me2 = me.clone();
             // Modify task needs a Weak<Self>
             let modify_task = ex.spawn(async move {
                 loop {
                     let _ = rect_sub.receive().await;
                     debug!(target: "app", "Layer rect modified");
 
-                    let Some(self_) = me.upgrade() else {
+                    let Some(self_) = me2.upgrade() else {
                         // Should not happen
                         panic!("self destroyed before modify_task was stopped!");
                     };
 
                     debug!(target: "app", "layer rect property modified");
-                    let sg = sg.lock().await;
-                    // read parent's rect
-                    //self_.draw(&sg).await;
+                    self_.redraw().await;
                 }
             });
 
             Self {
                 sg: sg_ptr,
                 node_id,
+                modify_task,
+                render_api,
                 dc_key: OsRng.gen(),
                 is_visible,
                 rect,
@@ -458,6 +468,86 @@ impl RenderLayer {
         Pimpl::RenderLayer(self_)
     }
 
+    async fn redraw(&self) {
+        let sg = self.sg.lock().await;
+        // read our parent
+        let node = sg.get_node(self.node_id).unwrap();
+        if node.parents.is_empty() {
+            info!("RenderLayer {:?} has no parents so skipping", node);
+            return
+        }
+        if node.parents.len() != 1 {
+            error!("RenderLayer {:?} has too many parents so skipping", node);
+            return
+        }
+        let parent_id = node.parents[0].id;
+        let parent_node = sg.get_node(parent_id).unwrap();
+        let parent_rect = match parent_node.typ {
+            SceneNodeType::Window => {
+                let Some(screen_size_prop) = parent_node.get_property("screen_size") else {
+                    error!(
+                        "RenderLayer {:?} parent node {:?} missing screen_size property",
+                        node, parent_node
+                    );
+                    return
+                };
+                let screen_width = screen_size_prop.get_f32(0).unwrap();
+                let screen_height = screen_size_prop.get_f32(1).unwrap();
+
+                let parent_rect = Rectangle { x: 0., y: 0., w: screen_width, h: screen_height };
+                parent_rect
+            }
+            SceneNodeType::RenderLayer => {
+                // get their rect property
+                let Some(parent_rect) = parent_node.get_property("rect") else {
+                    error!(
+                        "RenderLayer {:?} parent node {:?} missing rect property",
+                        node, parent_node
+                    );
+                    return
+                };
+                // read parent's rect
+                let Ok(parent_rect) = Self::read_rect(parent_rect) else {
+                    error!(
+                        "RenderLayer {:?} parent node {:?} malformed rect property",
+                        node, parent_node
+                    );
+                    return
+                };
+                parent_rect
+            }
+            _ => {
+                error!(
+                    "RenderLayer {:?} parent node {:?} wrong type {:?}",
+                    node, parent_node, parent_node.typ
+                );
+                return
+            }
+        };
+        let Some((_, dcs)) = self.draw(&sg, &parent_rect).await else {
+            error!("RenderLayer {:?} failed to draw", node);
+            return;
+        };
+        self.render_api.replace_draw_calls(dcs).await;
+        debug!("replace draw calls done");
+    }
+
+    fn read_rect(rect_prop: PropertyPtr) -> Result<Rectangle<f32>> {
+        if rect_prop.array_len != 4 {
+            return Err(Error::PropertyWrongLen)
+        }
+
+        let mut rect = [0.; 4];
+        for i in 0..4 {
+            if rect_prop.is_expr(i)? {
+                rect[i] = rect_prop.get_cached(i)?.as_f32()?;
+            } else {
+                rect[i] = rect_prop.get_f32(i)?;
+            }
+        }
+        Ok(Rectangle::from_array(rect))
+    }
+
     fn get_rect(&self, parent_rect: &Rectangle<f32>) -> Result<Rectangle<f32>> {
         if self.rect.array_len != 4 {
             return Err(Error::PropertyWrongLen)
@@ -476,7 +566,9 @@ impl RenderLayer {
                     stmts: &expr,
                 };
 
-                rect[i] = machine.call()?.as_f32()?;
+                let v = machine.call()?.as_f32()?;
+                self.rect.set_cache_f32(i, v).unwrap();
+                rect[i] = v;
             } else {
                 rect[i] = self.rect.get_f32(i)?;
             }
@@ -606,7 +698,9 @@ impl Mesh {
                     stmts: &expr,
                 };
 
-                rect[i] = machine.call()?.as_f32()?;
+                let v = machine.call()?.as_f32()?;
+                self.rect.set_cache_f32(i, v).unwrap();
+                rect[i] = v;
             } else {
                 rect[i] = self.rect.get_f32(i)?;
             }

+ 2 - 2
bin/darkwallet/src/gfx2.rs

@@ -156,8 +156,8 @@ impl<'a> RenderContext<'a> {
                     let view_w = view.w.round() as i32;
                     let view_h = view.h.round() as i32;
 
-                    //self.ctx.apply_viewport(view_x, view_y, view_w, view_h);
-                    //self.ctx.apply_scissor_rect(view_x, view_y, view_w, view_h);
+                    self.ctx.apply_viewport(view_x, view_y, view_w, view_h);
+                    self.ctx.apply_scissor_rect(view_x, view_y, view_w, view_h);
                 }
                 DrawInstruction::ApplyMatrix(model) => {
                     //debug!(target: "gfx", "{}apply_matrix({:?})", ws, model);

+ 63 - 10
bin/darkwallet/src/prop/mod.rs

@@ -113,49 +113,49 @@ impl PropertyValue {
         }
     }
 
-    fn as_bool(&self) -> Result<bool> {
+    pub fn as_bool(&self) -> Result<bool> {
         match self {
             Self::Bool(v) => Ok(*v),
             _ => Err(Error::PropertyWrongType),
         }
     }
-    fn as_u32(&self) -> Result<u32> {
+    pub fn as_u32(&self) -> Result<u32> {
         match self {
             Self::Uint32(v) => Ok(*v),
             _ => Err(Error::PropertyWrongType),
         }
     }
-    fn as_f32(&self) -> Result<f32> {
+    pub fn as_f32(&self) -> Result<f32> {
         match self {
             Self::Float32(v) => Ok(*v),
             _ => Err(Error::PropertyWrongType),
         }
     }
-    fn as_str(&self) -> Result<String> {
+    pub fn as_str(&self) -> Result<String> {
         match self {
             Self::Str(v) => Ok(v.clone()),
             _ => Err(Error::PropertyWrongType),
         }
     }
-    fn as_enum(&self) -> Result<String> {
+    pub fn as_enum(&self) -> Result<String> {
         match self {
             Self::Enum(v) => Ok(v.clone()),
             _ => Err(Error::PropertyWrongType),
         }
     }
-    fn as_buf(&self) -> Result<Buffer> {
+    pub fn as_buf(&self) -> Result<Buffer> {
         match self {
             Self::Buffer(v) => Ok(v.clone()),
             _ => Err(Error::PropertyWrongType),
         }
     }
-    fn as_node_id(&self) -> Result<SceneNodeId> {
+    pub fn as_node_id(&self) -> Result<SceneNodeId> {
         match self {
             Self::SceneNodeId(v) => Ok(*v),
             _ => Err(Error::PropertyWrongType),
         }
     }
-    fn as_sexpr(&self) -> Result<Arc<SExprCode>> {
+    pub fn as_sexpr(&self) -> Result<Arc<SExprCode>> {
         match self {
             Self::SExpr(v) => Ok(v.clone()),
             _ => Err(Error::PropertyWrongType),
@@ -195,9 +195,11 @@ pub struct Property {
     pub typ: PropertyType,
     pub subtype: PropertySubType,
     pub defaults: Vec<PropertyValue>,
-    pub vals: Mutex<Vec<PropertyValue>>,
     // either a value or an expr must be set
-    //pub exprs: Mutex<Vec<Option<SExprCode>>>,
+    pub vals: Mutex<Vec<PropertyValue>>,
+    // only used valid when PropertyValue is an expr
+    // caches the last calculated value
+    pub cache: Mutex<Vec<PropertyValue>>,
     pub ui_name: String,
     pub desc: String,
 
@@ -224,6 +226,7 @@ impl Property {
 
             defaults: vec![typ.default_value()],
             vals: Mutex::new(vec![PropertyValue::Unset]),
+            cache: Mutex::new(vec![PropertyValue::Null]),
 
             ui_name: String::new(),
             desc: String::new(),
@@ -249,9 +252,14 @@ impl Property {
         self.array_len = len;
         self.defaults.resize(len, self.typ.default_value());
         self.defaults.shrink_to_fit();
+
         let vals = &mut *self.vals.lock().unwrap();
         vals.resize(len, PropertyValue::Unset);
         vals.shrink_to_fit();
+
+        let cache = &mut *self.cache.lock().unwrap();
+        cache.resize(len, PropertyValue::Null);
+        cache.shrink_to_fit();
     }
     pub fn set_unbounded(&mut self) {
         self.set_array_len(0);
@@ -416,6 +424,25 @@ impl Property {
         Ok(())
     }
 
+    fn set_cache(&self, i: usize, val: PropertyValue) -> Result<()> {
+        if self.typ != val.as_type() {
+            return Err(Error::PropertyWrongType)
+        }
+
+        let cache = &mut self.cache.lock().unwrap();
+        if i >= cache.len() {
+            return Err(Error::PropertyWrongIndex)
+        }
+        cache[i] = val;
+        Ok(())
+    }
+    pub fn set_cache_f32(&self, i: usize, val: f32) -> Result<()> {
+        self.set_cache(i, PropertyValue::Float32(val))
+    }
+    pub fn set_cache_u32(&self, i: usize, val: u32) -> Result<()> {
+        self.set_cache(i, PropertyValue::Uint32(val))
+    }
+
     // Push
 
     pub fn push_null(&self) -> Result<usize> {
@@ -591,6 +618,17 @@ impl Property {
         self.get_value(i)?.as_sexpr()
     }
 
+    pub fn get_cached(&self, i: usize) -> Result<PropertyValue> {
+        let cache = &self.cache.lock().unwrap();
+        if self.is_bounded() {
+            assert_eq!(cache.len(), self.array_len);
+        }
+        if i >= cache.len() {
+            return Err(Error::PropertyWrongIndex)
+        }
+        Ok(cache[i].clone())
+    }
+
     // Subs
 
     pub fn subscribe_modify(&self) -> Subscription<ModifyAction> {
@@ -601,6 +639,7 @@ impl Property {
 #[cfg(test)]
 mod tests {
     use super::*;
+    use crate::expr::Op;
 
     #[test]
     fn test_getset() {
@@ -682,4 +721,18 @@ mod tests {
         assert!(prop.set_enum(0, "ABC").is_ok());
         assert!(prop.set_enum(0, "BAR").is_err());
     }
+
+    #[test]
+    fn test_expr() {
+        let mut prop = Property::new("foo", PropertyType::Float32, PropertySubType::Null);
+        prop.allow_exprs();
+        assert_eq!(prop.get_f32(0).unwrap(), 0.);
+        let code = vec![Op::ConstFloat32(4.)];
+        prop.set_expr(0, code).unwrap();
+        let val = prop.get_cached(0).unwrap();
+        assert!(val.is_null());
+        prop.set_cache_f32(0, 4.).unwrap();
+        let val = prop.get_cached(0).unwrap();
+        assert_eq!(val.as_f32().unwrap(), 4.);
+    }
 }

+ 9 - 3
bin/darkwallet/src/scene.rs

@@ -15,7 +15,7 @@ use std::{
 use crate::{
     app, chatview, editbox,
     error::{Error, Result},
-    prop::{Property, PropertyType},
+    prop::{Property, PropertyPtr, PropertyType},
 };
 
 pub type SceneNodeId = u32;
@@ -361,7 +361,7 @@ pub struct SceneNode {
     pub typ: SceneNodeType,
     pub parents: Vec<SceneNodeInfo>,
     pub children: Vec<SceneNodeInfo>,
-    pub props: Vec<Arc<Property>>,
+    pub props: Vec<PropertyPtr>,
     pub sigs: Vec<Signal>,
     pub methods: Vec<Method>,
     pub pimpl: Pimpl,
@@ -424,7 +424,7 @@ impl SceneNode {
         self.props.iter().any(|prop| prop.name == name)
     }
 
-    pub fn get_property(&self, name: &str) -> Option<Arc<Property>> {
+    pub fn get_property(&self, name: &str) -> Option<PropertyPtr> {
         self.props.iter().find(|prop| prop.name == name).map(|prop| prop.clone())
     }
 
@@ -641,3 +641,9 @@ pub enum Pimpl {
     RenderLayer(app::RenderLayerPtr),
     Mesh(app::Mesh),
 }
+
+impl std::fmt::Debug for SceneNode {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "'{}':{}", self.name, self.id)
+    }
+}