wallet: make Point copy and allow Point arithmetic.

This commit is contained in:
darkfi
2024-09-16 15:40:23 +02:00
parent c76d792208
commit 752a085513
10 changed files with 277 additions and 176 deletions

View File

@@ -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 }
}
}

View File

@@ -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 {

View File

@@ -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>>;

View File

@@ -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,

View File

@@ -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

View File

@@ -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 {

View File

@@ -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

View File

@@ -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();

View File

@@ -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
}

View File

@@ -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
};