Browse Source

wallet: make Point copy and allow Point arithmetic.

darkfi 1 year ago
parent
commit
752a085513

+ 183 - 0
bin/darkwallet/src/gfx/linalg.rs

@@ -0,0 +1,183 @@
+/* This file is part of DarkFi (https://dark.fi)
+ *
+ * Copyright (C) 2020-2024 Dyne.org foundation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+use std::ops::{Add, Sub};
+
+#[derive(Clone, Copy, Debug)]
+pub struct Point {
+    pub x: f32,
+    pub y: f32,
+}
+
+impl Point {
+    pub fn new(x: f32, y: f32) -> Self {
+        Self { x, y }
+    }
+
+    pub fn unpack(&self) -> (f32, f32) {
+        (self.x, self.y)
+    }
+
+    pub fn as_arr(&self) -> [f32; 2] {
+        [self.x, self.y]
+    }
+
+    pub fn offset(&self, off_x: f32, off_y: f32) -> Self {
+        Self { x: self.x + off_x, y: self.y + off_y }
+    }
+
+    pub fn to_rect(&self, w: f32, h: f32) -> Rectangle {
+        Rectangle { x: self.x, y: self.y, w, h }
+    }
+}
+
+impl From<[f32; 2]> for Point {
+    fn from(pos: [f32; 2]) -> Self {
+        Self { x: pos[0], y: pos[1] }
+    }
+}
+
+impl Add for Point {
+    type Output = Self;
+
+    fn add(self, other: Self) -> Self::Output {
+        Self { x: self.x + other.x, y: self.y + other.y }
+    }
+}
+
+impl Sub for Point {
+    type Output = Self;
+
+    fn sub(self, other: Self) -> Self::Output {
+        Self { x: self.x - other.x, y: self.y - other.y }
+    }
+}
+
+#[derive(Debug, Clone)]
+pub struct Rectangle {
+    pub x: f32,
+    pub y: f32,
+    pub w: f32,
+    pub h: f32,
+}
+
+impl Rectangle {
+    pub fn new(x: f32, y: f32, w: f32, h: f32) -> Self {
+        Self { x, y, w, h }
+    }
+
+    pub fn zero() -> Self {
+        Self { x: 0., y: 0., w: 0., h: 0. }
+    }
+
+    pub fn from_array(arr: [f32; 4]) -> Self {
+        Self { x: arr[0], y: arr[1], w: arr[2], h: arr[3] }
+    }
+
+    pub fn clip(&self, other: &Self) -> Option<Self> {
+        if other.x + other.w < self.x ||
+            other.x > self.x + self.w ||
+            other.y + other.h < self.y ||
+            other.y > self.y + self.h
+        {
+            return None
+        }
+
+        let mut clipped = other.clone();
+        if clipped.x < self.x {
+            clipped.x = self.x;
+            clipped.w = other.x + other.w - clipped.x;
+        }
+        if clipped.y < self.y {
+            clipped.y = self.y;
+            clipped.h = other.y + other.h - clipped.y;
+        }
+        if clipped.x + clipped.w > self.x + self.w {
+            clipped.w = self.x + self.w - clipped.x;
+        }
+        if clipped.y + clipped.h > self.y + self.h {
+            clipped.h = self.y + self.h - clipped.y;
+        }
+        Some(clipped)
+    }
+
+    pub fn clip_point(&self, point: &mut Point) {
+        if point.x < self.x {
+            point.x = self.x;
+        }
+        if point.y < self.y {
+            point.y = self.y;
+        }
+        if point.x > self.x + self.w {
+            point.x = self.x + self.w;
+        }
+        if point.y > self.y + self.h {
+            point.y = self.y + self.h;
+        }
+    }
+
+    pub fn contains(&self, point: Point) -> bool {
+        self.x <= point.x &&
+            point.x <= self.x + self.w &&
+            self.y <= point.y &&
+            point.y <= self.y + self.h
+    }
+
+    pub fn rhs(&self) -> f32 {
+        self.x + self.w
+    }
+    pub fn bhs(&self) -> f32 {
+        self.y + self.h
+    }
+
+    pub fn pos(&self) -> Point {
+        Point { x: self.x, y: self.y }
+    }
+    pub fn corner(&self) -> Point {
+        Point { x: self.x + self.w, y: self.y + self.h }
+    }
+
+    #[deprecated]
+    pub fn top_left(&self) -> Point {
+        Point { x: self.x, y: self.y }
+    }
+    #[deprecated]
+    pub fn bottom_right(&self) -> Point {
+        Point { x: self.x + self.w, y: self.y + self.h }
+    }
+
+    pub fn includes(&self, child: &Self) -> bool {
+        self.contains(child.pos()) && self.contains(child.corner())
+    }
+}
+
+impl Add<Point> for Rectangle {
+    type Output = Rectangle;
+
+    fn add(self, other: Point) -> Self::Output {
+        Self { x: self.x + other.x, y: self.y + other.y, w: self.w, h: self.h }
+    }
+}
+
+impl Sub<Point> for Rectangle {
+    type Output = Rectangle;
+
+    fn sub(self, other: Point) -> Self::Output {
+        Self { x: self.x - other.x, y: self.y - other.y, w: self.w, h: self.h }
+    }
+}

+ 2 - 119
bin/darkwallet/src/gfx/mod.rs

@@ -30,6 +30,8 @@ use std::{
     time::{Duration, Instant},
 };
 
+mod linalg;
+pub use linalg::{Point, Rectangle};
 mod shader;
 
 use crate::{
@@ -63,125 +65,6 @@ impl Vertex {
     }
 }
 
-#[derive(Clone, Debug)]
-pub struct Point {
-    pub x: f32,
-    pub y: f32,
-}
-
-impl Point {
-    pub fn unpack(&self) -> (f32, f32) {
-        (self.x, self.y)
-    }
-
-    pub fn as_arr(&self) -> [f32; 2] {
-        [self.x, self.y]
-    }
-
-    pub fn offset(&self, off_x: f32, off_y: f32) -> Self {
-        Self { x: self.x + off_x, y: self.y + off_y }
-    }
-
-    pub fn to_rect(&self, w: f32, h: f32) -> Rectangle {
-        Rectangle { x: self.x, y: self.y, w, h }
-    }
-}
-
-impl From<[f32; 2]> for Point {
-    fn from(pos: [f32; 2]) -> Self {
-        Self { x: pos[0], y: pos[1] }
-    }
-}
-
-#[derive(Debug, Clone)]
-pub struct Rectangle {
-    pub x: f32,
-    pub y: f32,
-    pub w: f32,
-    pub h: f32,
-}
-
-impl Rectangle {
-    pub fn new(x: f32, y: f32, w: f32, h: f32) -> Self {
-        Self { x, y, w, h }
-    }
-
-    pub fn zero() -> Self {
-        Self { x: 0., y: 0., w: 0., h: 0. }
-    }
-
-    pub fn from_array(arr: [f32; 4]) -> Self {
-        Self { x: arr[0], y: arr[1], w: arr[2], h: arr[3] }
-    }
-
-    pub fn clip(&self, other: &Self) -> Option<Self> {
-        if other.x + other.w < self.x ||
-            other.x > self.x + self.w ||
-            other.y + other.h < self.y ||
-            other.y > self.y + self.h
-        {
-            return None
-        }
-
-        let mut clipped = other.clone();
-        if clipped.x < self.x {
-            clipped.x = self.x;
-            clipped.w = other.x + other.w - clipped.x;
-        }
-        if clipped.y < self.y {
-            clipped.y = self.y;
-            clipped.h = other.y + other.h - clipped.y;
-        }
-        if clipped.x + clipped.w > self.x + self.w {
-            clipped.w = self.x + self.w - clipped.x;
-        }
-        if clipped.y + clipped.h > self.y + self.h {
-            clipped.h = self.y + self.h - clipped.y;
-        }
-        Some(clipped)
-    }
-
-    pub fn clip_point(&self, point: &mut Point) {
-        if point.x < self.x {
-            point.x = self.x;
-        }
-        if point.y < self.y {
-            point.y = self.y;
-        }
-        if point.x > self.x + self.w {
-            point.x = self.x + self.w;
-        }
-        if point.y > self.y + self.h {
-            point.y = self.y + self.h;
-        }
-    }
-
-    pub fn contains(&self, point: &Point) -> bool {
-        self.x <= point.x &&
-            point.x <= self.x + self.w &&
-            self.y <= point.y &&
-            point.y <= self.y + self.h
-    }
-
-    pub fn rhs(&self) -> f32 {
-        self.x + self.w
-    }
-    pub fn bhs(&self) -> f32 {
-        self.y + self.h
-    }
-
-    pub fn top_left(&self) -> Point {
-        Point { x: self.x, y: self.y }
-    }
-    pub fn bottom_right(&self) -> Point {
-        Point { x: self.x + self.w, y: self.y + self.h }
-    }
-
-    pub fn includes(&self, child: &Self) -> bool {
-        self.contains(&child.top_left()) && self.contains(&child.bottom_right())
-    }
-}
-
 pub type RenderApiPtr = Arc<RenderApi>;
 
 pub struct RenderApi {

+ 2 - 1
bin/darkwallet/src/prop/mod.rs

@@ -31,7 +31,8 @@ use crate::{
 
 mod wrap;
 pub use wrap::{
-    PropertyBool, PropertyColor, PropertyFloat32, PropertyRect, PropertyStr, PropertyUint32,
+    PropertyBool, PropertyColor, PropertyFloat32, PropertyPoint, PropertyRect, PropertyStr,
+    PropertyUint32,
 };
 
 type Buffer = Arc<Vec<u8>>;

+ 35 - 1
bin/darkwallet/src/prop/wrap.rs

@@ -19,7 +19,7 @@
 use crate::{
     error::{Error, Result},
     expr::{SExprMachine, SExprVal},
-    gfx::Rectangle,
+    gfx::{Point, Rectangle},
     scene::SceneNode,
 };
 
@@ -193,6 +193,40 @@ impl PropertyColor {
     }
 }
 
+#[derive(Clone)]
+pub struct PropertyPoint {
+    prop: PropertyPtr,
+    role: Role,
+}
+
+impl PropertyPoint {
+    pub fn wrap(node: &SceneNode, role: Role, prop_name: &str) -> Result<Self> {
+        let prop = node.get_property(prop_name).ok_or(Error::PropertyNotFound)?;
+
+        if !prop.is_bounded() || prop.get_len() != 2 {
+            return Err(Error::PropertyWrongLen)
+        }
+
+        // Test if it works
+        let _ = prop.get_f32(0)?;
+
+        Ok(Self { prop, role })
+    }
+
+    pub fn get(&self) -> Point {
+        [self.prop.get_f32(0).unwrap(), self.prop.get_f32(1).unwrap()].into()
+    }
+
+    pub fn set(&self, pos: Point) {
+        self.prop.set_f32(self.role, 0, pos.x).unwrap();
+        self.prop.set_f32(self.role, 1, pos.y).unwrap();
+    }
+
+    pub fn prop(&self) -> PropertyPtr {
+        self.prop.clone()
+    }
+}
+
 #[derive(Clone)]
 pub struct PropertyRect {
     prop: PropertyPtr,

+ 3 - 3
bin/darkwallet/src/ui/button.rs

@@ -90,7 +90,7 @@ impl UIObject for Button {
         &self,
         sg: &SceneGraph,
         btn: MouseButton,
-        mouse_pos: &Point,
+        mouse_pos: Point,
     ) -> bool {
         if !self.is_active.get() {
             return false
@@ -113,7 +113,7 @@ impl UIObject for Button {
         &self,
         sg: &SceneGraph,
         btn: MouseButton,
-        mouse_pos: &Point,
+        mouse_pos: Point,
     ) -> bool {
         if !self.is_active.get() {
             return false
@@ -147,7 +147,7 @@ impl UIObject for Button {
         sg: &SceneGraph,
         phase: TouchPhase,
         id: u64,
-        touch_pos: &Point,
+        touch_pos: Point,
     ) -> bool {
         if !self.is_active.get() {
             return false

+ 7 - 7
bin/darkwallet/src/ui/chatview/mod.rs

@@ -756,7 +756,7 @@ impl UIObject for ChatView {
         &self,
         sg: &SceneGraph,
         btn: MouseButton,
-        mouse_pos: &Point,
+        mouse_pos: Point,
     ) -> bool {
         if btn != MouseButton::Left {
             return false
@@ -776,17 +776,17 @@ impl UIObject for ChatView {
         &self,
         sg: &SceneGraph,
         btn: MouseButton,
-        mouse_pos: &Point,
+        mouse_pos: Point,
     ) -> bool {
         if btn != MouseButton::Left {
             return false
         }
 
         self.mouse_btn_held.store(false, Ordering::Relaxed);
-        true
+        false
     }
 
-    async fn handle_mouse_move(&self, sg: &SceneGraph, mouse_pos: &Point) -> bool {
+    async fn handle_mouse_move(&self, sg: &SceneGraph, mouse_pos: Point) -> bool {
         //debug!(target: "ui::chatview", "handle_mouse_move({mouse_x}, {mouse_y})");
 
         // We store the mouse pos for use in handle_mouse_wheel()
@@ -805,13 +805,13 @@ impl UIObject for ChatView {
         false
     }
 
-    async fn handle_mouse_wheel(&self, sg: &SceneGraph, wheel_pos: &Point) -> bool {
+    async fn handle_mouse_wheel(&self, sg: &SceneGraph, wheel_pos: Point) -> bool {
         //debug!(target: "ui::chatview", "handle_mouse_wheel({wheel_x}, {wheel_y})");
 
         let rect = self.rect.get();
 
         let mouse_pos = self.mouse_pos.lock().unwrap().clone();
-        if !rect.contains(&mouse_pos) {
+        if !rect.contains(mouse_pos) {
             //debug!(target: "ui::chatview", "not inside rect");
             return false
         }
@@ -826,7 +826,7 @@ impl UIObject for ChatView {
         sg: &SceneGraph,
         phase: TouchPhase,
         id: u64,
-        touch_pos: &Point,
+        touch_pos: Point,
     ) -> bool {
         // Ignore multi-touch
         if id != 0 {

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

@@ -432,7 +432,7 @@ impl EditBox {
         self.redraw().await;
     }
 
-    async fn handle_click_down(&self, btn: MouseButton, mouse_pos: &Point) {
+    async fn handle_click_down(&self, btn: MouseButton, mouse_pos: Point) {
         if btn != MouseButton::Left {
             return
         }
@@ -442,7 +442,7 @@ impl EditBox {
         // clicking inside box will:
         // 1. make it active
         // 2. begin selection
-        if rect.contains(&mouse_pos) {
+        if rect.contains(mouse_pos) {
             window::show_keyboard(true);
 
             if self.is_focused.get() {
@@ -476,7 +476,7 @@ impl EditBox {
 
         self.redraw().await;
     }
-    fn handle_click_up(&self, btn: MouseButton, pos: &Point) {
+    fn handle_click_up(&self, btn: MouseButton, pos: Point) {
         if btn != MouseButton::Left {
             return
         }
@@ -484,7 +484,7 @@ impl EditBox {
         // releasing mouse button will end selection
         self.mouse_btn_held.store(false, Ordering::Relaxed);
     }
-    async fn handle_cursor_move(&self, pos: &Point) {
+    async fn handle_cursor_move(&self, pos: Point) {
         if !self.mouse_btn_held.load(Ordering::Relaxed) {
             return;
         }
@@ -504,7 +504,7 @@ impl EditBox {
         self.redraw().await;
     }
 
-    async fn handle_touch(&self, phase: TouchPhase, id: u64, touch_pos: &Point) {
+    async fn handle_touch(&self, phase: TouchPhase, id: u64, touch_pos: Point) {
         // Ignore multi-touch
         if id != 0 {
             return
@@ -1115,7 +1115,7 @@ impl UIObject for EditBox {
         &self,
         sg: &SceneGraph,
         btn: MouseButton,
-        mouse_pos: &Point,
+        mouse_pos: Point,
     ) -> bool {
         if !self.is_active.get() {
             return true
@@ -1129,7 +1129,7 @@ impl UIObject for EditBox {
         &self,
         sg: &SceneGraph,
         btn: MouseButton,
-        mouse_pos: &Point,
+        mouse_pos: Point,
     ) -> bool {
         if !self.is_active.get() {
             return true
@@ -1139,7 +1139,7 @@ impl UIObject for EditBox {
         true
     }
 
-    async fn handle_mouse_move(&self, sg: &SceneGraph, mouse_pos: &Point) -> bool {
+    async fn handle_mouse_move(&self, sg: &SceneGraph, mouse_pos: Point) -> bool {
         if !self.is_active.get() {
             return false
         }
@@ -1153,7 +1153,7 @@ impl UIObject for EditBox {
         sg: &SceneGraph,
         phase: TouchPhase,
         id: u64,
-        touch_pos: &Point,
+        touch_pos: Point,
     ) -> bool {
         if !self.is_active.get() {
             return true

+ 11 - 14
bin/darkwallet/src/ui/layer.rs

@@ -124,7 +124,6 @@ impl UIObject for Layer {
         self.z_index.get()
     }
 
-    //#[async_recursion]
     async fn draw(&self, sg: &SceneGraph, parent_rect: &Rectangle) -> Option<DrawUpdate> {
         debug!(target: "ui::layer", "Layer::draw()");
         let node = sg.get_node(self.node_id).unwrap();
@@ -135,22 +134,20 @@ impl UIObject for Layer {
         }
 
         self.rect.eval(parent_rect).ok()?;
-        let mut rect = self.rect.get();
 
-        rect.x += parent_rect.x;
-        rect.y += parent_rect.x;
+        let mut screen_rect = self.rect.get() + parent_rect.pos();
 
-        if !parent_rect.includes(&rect) {
+        if !parent_rect.includes(&screen_rect) {
             error!(
                 target: "ui::layer",
                 "layer '{}':{} rect {:?} is not inside parent {:?}",
-                node.name, node.id, rect, parent_rect
+                node.name, node.id, screen_rect, parent_rect
             );
             return None
         }
 
         debug!(target: "ui::layer", "Parent rect: {:?}", parent_rect);
-        debug!(target: "ui::layer", "Viewport rect: {:?}", rect);
+        debug!(target: "ui::layer", "Viewport rect: {:?}", screen_rect);
 
         // Apply viewport
 
@@ -162,7 +159,7 @@ impl UIObject for Layer {
         for child_id in get_child_nodes_ordered(&sg, self.node_id) {
             let node = sg.get_node(child_id).unwrap();
             let obj = get_ui_object(node);
-            let Some(mut draw_update) = obj.draw(sg, &rect).await else {
+            let Some(mut draw_update) = obj.draw(sg, &screen_rect).await else {
                 debug!(target: "ui::layer", "Skipped draw() of {node:?}");
                 continue
             };
@@ -174,7 +171,7 @@ impl UIObject for Layer {
         }
 
         let dc = GfxDrawCall {
-            instrs: vec![GfxDrawInstruction::ApplyViewport(rect)],
+            instrs: vec![GfxDrawInstruction::ApplyViewport(screen_rect)],
             dcs: child_calls,
             z_index: 0,
         };
@@ -224,7 +221,7 @@ impl UIObject for Layer {
         &self,
         sg: &SceneGraph,
         btn: MouseButton,
-        mouse_pos: &Point,
+        mouse_pos: Point,
     ) -> bool {
         for child_id in get_child_nodes_ordered(&sg, self.node_id) {
             let node = sg.get_node(child_id).unwrap();
@@ -239,7 +236,7 @@ impl UIObject for Layer {
         &self,
         sg: &SceneGraph,
         btn: MouseButton,
-        mouse_pos: &Point,
+        mouse_pos: Point,
     ) -> bool {
         for child_id in get_child_nodes_ordered(&sg, self.node_id) {
             let node = sg.get_node(child_id).unwrap();
@@ -250,7 +247,7 @@ impl UIObject for Layer {
         }
         false
     }
-    async fn handle_mouse_move(&self, sg: &SceneGraph, mouse_pos: &Point) -> bool {
+    async fn handle_mouse_move(&self, sg: &SceneGraph, mouse_pos: Point) -> bool {
         for child_id in get_child_nodes_ordered(&sg, self.node_id) {
             let node = sg.get_node(child_id).unwrap();
             let obj = get_ui_object(node);
@@ -260,7 +257,7 @@ impl UIObject for Layer {
         }
         false
     }
-    async fn handle_mouse_wheel(&self, sg: &SceneGraph, wheel_pos: &Point) -> bool {
+    async fn handle_mouse_wheel(&self, sg: &SceneGraph, wheel_pos: Point) -> bool {
         for child_id in get_child_nodes_ordered(&sg, self.node_id) {
             let node = sg.get_node(child_id).unwrap();
             let obj = get_ui_object(node);
@@ -275,7 +272,7 @@ impl UIObject for Layer {
         sg: &SceneGraph,
         phase: TouchPhase,
         id: u64,
-        touch_pos: &Point,
+        touch_pos: Point,
     ) -> bool {
         for child_id in get_child_nodes_ordered(&sg, self.node_id) {
             let node = sg.get_node(child_id).unwrap();

+ 5 - 5
bin/darkwallet/src/ui/mod.rs

@@ -80,7 +80,7 @@ pub trait UIObject: Sync {
         &self,
         sg: &SceneGraph,
         btn: MouseButton,
-        mouse_pos: &Point,
+        mouse_pos: Point,
     ) -> bool {
         false
     }
@@ -88,14 +88,14 @@ pub trait UIObject: Sync {
         &self,
         sg: &SceneGraph,
         btn: MouseButton,
-        mouse_pos: &Point,
+        mouse_pos: Point,
     ) -> bool {
         false
     }
-    async fn handle_mouse_move(&self, sg: &SceneGraph, mouse_pos: &Point) -> bool {
+    async fn handle_mouse_move(&self, sg: &SceneGraph, mouse_pos: Point) -> bool {
         false
     }
-    async fn handle_mouse_wheel(&self, sg: &SceneGraph, wheel_pos: &Point) -> bool {
+    async fn handle_mouse_wheel(&self, sg: &SceneGraph, wheel_pos: Point) -> bool {
         false
     }
     async fn handle_touch(
@@ -103,7 +103,7 @@ pub trait UIObject: Sync {
         sg: &SceneGraph,
         phase: TouchPhase,
         id: u64,
-        touch_pos: &Point,
+        touch_pos: Point,
     ) -> bool {
         false
     }

+ 20 - 17
bin/darkwallet/src/ui/win.rs

@@ -21,7 +21,7 @@ use std::sync::{Arc, Weak};
 
 use crate::{
     gfx::{GfxDrawCall, GraphicsEventPublisherPtr, Point, Rectangle, RenderApiPtr},
-    prop::{PropertyPtr, Role},
+    prop::{PropertyFloat32, PropertyPtr, Role},
     pubsub::Subscription,
     scene::{Pimpl, SceneGraph, SceneGraphPtr2, SceneNodeId},
     ExecutorPtr,
@@ -38,7 +38,8 @@ pub struct Window {
     // Task is dropped at the end of the scope for Window, hence ending it
     #[allow(dead_code)]
     tasks: Vec<smol::Task<()>>,
-    screen_size_prop: PropertyPtr,
+    screen_w: PropertyFloat32,
+    screen_h: PropertyFloat32,
     render_api: RenderApiPtr,
 }
 
@@ -55,7 +56,8 @@ impl Window {
         let scene_graph = sg.lock().await;
         let node = scene_graph.get_node(node_id).unwrap();
         let node_name = node.name.clone();
-        let screen_size_prop = node.get_property("screen_size").unwrap();
+        let screen_w = PropertyFloat32::wrap(node, Role::Internal, "screen_size", 0).unwrap();
+        let screen_h = PropertyFloat32::wrap(node, Role::Internal, "screen_size", 1).unwrap();
         let scale_prop = node.get_property("scale").unwrap();
         drop(scene_graph);
 
@@ -63,7 +65,8 @@ impl Window {
             // Start a task monitoring for window resize events
             // which updates screen_size
             let ev_sub = event_pub.subscribe_resize();
-            let screen_size_prop2 = screen_size_prop.clone();
+            let screen_w2 = screen_w.clone();
+            let screen_h2 = screen_h.clone();
             let me2 = me.clone();
             let sg2 = sg.clone();
             let resize_task = ex.spawn(async move {
@@ -75,8 +78,8 @@ impl Window {
 
                     debug!(target: "ui::win", "Window resized ({w}, {h})");
                     // Now update the properties
-                    screen_size_prop2.set_f32(Role::Internal, 0, w).unwrap();
-                    screen_size_prop2.set_f32(Role::Internal, 1, h).unwrap();
+                    screen_w2.set(w);
+                    screen_h2.set(h);
 
                     let Some(self_) = me2.upgrade() else {
                         // Should not happen
@@ -153,7 +156,7 @@ impl Window {
             ];
             tasks.append(&mut on_modify.tasks);
 
-            Self { node_id, sg, tasks, screen_size_prop, render_api }
+            Self { node_id, sg, tasks, screen_w, screen_h, render_api }
         });
 
         Pimpl::Window(self_)
@@ -333,7 +336,7 @@ impl Window {
         for child_id in get_child_nodes_ordered(&sg, self.node_id) {
             let node = sg.get_node(child_id).unwrap();
             let obj = get_ui_object(node);
-            if obj.handle_mouse_btn_down(&sg, btn.clone(), &mouse_pos).await {
+            if obj.handle_mouse_btn_down(&sg, btn.clone(), mouse_pos).await {
                 return
             }
         }
@@ -345,7 +348,7 @@ impl Window {
         for child_id in get_child_nodes_ordered(&sg, self.node_id) {
             let node = sg.get_node(child_id).unwrap();
             let obj = get_ui_object(node);
-            if obj.handle_mouse_btn_up(&sg, btn.clone(), &mouse_pos).await {
+            if obj.handle_mouse_btn_up(&sg, btn.clone(), mouse_pos).await {
                 return
             }
         }
@@ -357,7 +360,7 @@ impl Window {
         for child_id in get_child_nodes_ordered(&sg, self.node_id) {
             let node = sg.get_node(child_id).unwrap();
             let obj = get_ui_object(node);
-            if obj.handle_mouse_move(&sg, &mouse_pos).await {
+            if obj.handle_mouse_move(&sg, mouse_pos).await {
                 return
             }
         }
@@ -369,7 +372,7 @@ impl Window {
         for child_id in get_child_nodes_ordered(&sg, self.node_id) {
             let node = sg.get_node(child_id).unwrap();
             let obj = get_ui_object(node);
-            if obj.handle_mouse_wheel(&sg, &wheel_pos).await {
+            if obj.handle_mouse_wheel(&sg, wheel_pos).await {
                 return
             }
         }
@@ -381,21 +384,21 @@ impl Window {
         for child_id in get_child_nodes_ordered(&sg, self.node_id) {
             let node = sg.get_node(child_id).unwrap();
             let obj = get_ui_object(node);
-            if obj.handle_touch(&sg, phase, id, &touch_pos).await {
+            if obj.handle_touch(&sg, phase, id, touch_pos).await {
                 return
             }
         }
     }
 
     pub async fn draw(&self, sg: &SceneGraph) {
-        let screen_width = self.screen_size_prop.get_f32(0).unwrap();
-        let screen_height = self.screen_size_prop.get_f32(1).unwrap();
-        debug!(target: "ui::win", "Window::draw({screen_width}, {screen_height})");
+        let screen_w = self.screen_w.get();
+        let screen_h = self.screen_h.get();
+        debug!(target: "ui::win", "Window::draw({screen_w}, {screen_h})");
 
         // SceneGraph should remain locked for the entire draw
         let self_node = sg.get_node(self.node_id).unwrap();
 
-        let parent_rect = Rectangle::from_array([0., 0., screen_width, screen_height]);
+        let screen_rect = Rectangle::new(0., 0., screen_w, screen_h);
 
         let mut draw_calls = vec![];
         let mut child_calls = vec![];
@@ -405,7 +408,7 @@ impl Window {
         for child_id in get_child_nodes_ordered(&sg, self.node_id) {
             let node = sg.get_node(child_id).unwrap();
             let obj = get_ui_object(node);
-            let Some(mut draw_update) = obj.draw(sg, &parent_rect).await else {
+            let Some(mut draw_update) = obj.draw(sg, &screen_rect).await else {
                 error!(target: "ui::layer", "draw() of {node:?} failed");
                 continue
             };