mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
wallet: migrate widgets to src/ui/
This commit is contained in:
@@ -12,7 +12,9 @@ use crate::{
|
||||
error::{Error, Result},
|
||||
expr::{Op, SExprMachine, SExprVal},
|
||||
gfx::Rectangle,
|
||||
gfx2::{self, DrawCall, DrawInstruction, DrawMesh, GraphicsEventPublisherPtr, RenderApiPtr, Vertex},
|
||||
gfx2::{
|
||||
self, DrawCall, DrawInstruction, DrawMesh, GraphicsEventPublisherPtr, RenderApiPtr, Vertex,
|
||||
},
|
||||
prop::{
|
||||
Property, PropertyBool, PropertyColor, PropertyFloat32, PropertyPtr, PropertyStr,
|
||||
PropertySubType, PropertyType, PropertyUint32,
|
||||
@@ -22,12 +24,12 @@ use crate::{
|
||||
MethodResponseFn, Pimpl, SceneGraph, SceneGraphPtr2, SceneNode, SceneNodeId, SceneNodeInfo,
|
||||
SceneNodeType,
|
||||
},
|
||||
ui::{
|
||||
eval_rect, get_parent_rect, read_rect, DrawUpdate, Mesh, OnModify, RenderLayer,
|
||||
RenderLayerPtr, Stoppable, Window, WindowPtr,
|
||||
},
|
||||
};
|
||||
|
||||
trait Stoppable {
|
||||
async fn stop(&self);
|
||||
}
|
||||
|
||||
pub type AsyncRuntimePtr = Arc<AsyncRuntime>;
|
||||
|
||||
pub struct AsyncRuntime {
|
||||
@@ -299,501 +301,3 @@ impl App {
|
||||
fn print_type_of<T>(_: &T) {
|
||||
println!("{}", std::any::type_name::<T>())
|
||||
}
|
||||
|
||||
struct OnModify<T> {
|
||||
ex: Arc<smol::Executor<'static>>,
|
||||
node_name: String,
|
||||
node_id: SceneNodeId,
|
||||
me: Weak<T>,
|
||||
tasks: Vec<smol::Task<()>>,
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> OnModify<T> {
|
||||
fn new(
|
||||
ex: Arc<smol::Executor<'static>>,
|
||||
node_name: String,
|
||||
node_id: SceneNodeId,
|
||||
me: Weak<T>,
|
||||
) -> Self {
|
||||
Self { ex, node_name, node_id, me, tasks: vec![] }
|
||||
}
|
||||
|
||||
fn when_change<F>(&mut self, prop: PropertyPtr, f: impl Fn(Arc<T>) -> F + Send + 'static)
|
||||
where
|
||||
F: std::future::Future<Output = ()> + Send + 'static,
|
||||
{
|
||||
let node_name = self.node_name.clone();
|
||||
let node_id = self.node_id;
|
||||
let on_modify_sub = prop.subscribe_modify();
|
||||
let prop_name = prop.name.clone();
|
||||
let me = self.me.clone();
|
||||
let task = self.ex.spawn(async move {
|
||||
loop {
|
||||
let _ = on_modify_sub.receive().await;
|
||||
debug!(target: "app", "Property '{}':{}/'{}' modified", node_name, node_id, prop_name);
|
||||
|
||||
let Some(self_) = me.upgrade() else {
|
||||
// Should not happen
|
||||
panic!(
|
||||
"'{}':{}/'{}' self destroyed before modify_task was stopped!",
|
||||
node_name, node_id, prop_name
|
||||
);
|
||||
};
|
||||
|
||||
debug!(target: "app", "property modified");
|
||||
f(self_).await;
|
||||
}
|
||||
});
|
||||
self.tasks.push(task);
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_rect(rect: PropertyPtr, parent_rect: &Rectangle<f32>) -> Result<()> {
|
||||
if rect.array_len != 4 {
|
||||
return Err(Error::PropertyWrongLen)
|
||||
}
|
||||
|
||||
for i in 0..4 {
|
||||
if !rect.is_expr(i)? {
|
||||
continue
|
||||
}
|
||||
|
||||
let expr = rect.get_expr(i).unwrap();
|
||||
|
||||
let machine = SExprMachine {
|
||||
globals: vec![
|
||||
("w".to_string(), SExprVal::Float32(parent_rect.w)),
|
||||
("h".to_string(), SExprVal::Float32(parent_rect.h)),
|
||||
],
|
||||
stmts: &expr,
|
||||
};
|
||||
|
||||
let v = machine.call()?.as_f32()?;
|
||||
rect.set_cache_f32(i, v).unwrap();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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_parent_rect(sg: &SceneGraph, node: &SceneNode) -> Option<Rectangle<f32>> {
|
||||
// read our parent
|
||||
if node.parents.is_empty() {
|
||||
info!("RenderLayer {:?} has no parents so skipping", node);
|
||||
return None
|
||||
}
|
||||
if node.parents.len() != 1 {
|
||||
error!("RenderLayer {:?} has too many parents so skipping", node);
|
||||
return None
|
||||
}
|
||||
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 None
|
||||
};
|
||||
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 None
|
||||
};
|
||||
// read parent's rect
|
||||
let Ok(parent_rect) = read_rect(parent_rect) else {
|
||||
error!(
|
||||
"RenderLayer {:?} parent node {:?} malformed rect property",
|
||||
node, parent_node
|
||||
);
|
||||
return None
|
||||
};
|
||||
parent_rect
|
||||
}
|
||||
_ => {
|
||||
error!(
|
||||
"RenderLayer {:?} parent node {:?} wrong type {:?}",
|
||||
node, parent_node, parent_node.typ
|
||||
);
|
||||
return None
|
||||
}
|
||||
};
|
||||
Some(parent_rect)
|
||||
}
|
||||
|
||||
struct DrawUpdate {
|
||||
key: u64,
|
||||
draw_calls: Vec<(u64, DrawCall)>,
|
||||
}
|
||||
|
||||
pub type WindowPtr = Arc<Window>;
|
||||
|
||||
pub struct Window {
|
||||
node_id: SceneNodeId,
|
||||
tasks: Vec<smol::Task<()>>,
|
||||
screen_size_prop: PropertyPtr,
|
||||
render_api: RenderApiPtr,
|
||||
}
|
||||
|
||||
impl Window {
|
||||
pub async fn new(
|
||||
sg: SceneGraphPtr2,
|
||||
node_id: SceneNodeId,
|
||||
ex: Arc<smol::Executor<'static>>,
|
||||
render_api: RenderApiPtr,
|
||||
event_pub: GraphicsEventPublisherPtr,
|
||||
) -> Pimpl {
|
||||
debug!(target: "app", "Window::new()");
|
||||
|
||||
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 scale_prop = node.get_property("scale").unwrap();
|
||||
drop(scene_graph);
|
||||
|
||||
let self_ = Arc::new_cyclic(|me: &Weak<Self>| {
|
||||
// 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 me2 = me.clone();
|
||||
let sg2 = sg.clone();
|
||||
let resize_task = ex.spawn(async move {
|
||||
loop {
|
||||
let Ok((w, h)) = ev_sub.receive().await else {
|
||||
debug!(target: "app", "Event relayer closed");
|
||||
break
|
||||
};
|
||||
|
||||
debug!(target: "app", "Window resized ({w}, {h})");
|
||||
// Now update the properties
|
||||
screen_size_prop2.set_f32(0, w);
|
||||
screen_size_prop2.set_f32(1, h);
|
||||
|
||||
let Some(self_) = me2.upgrade() else {
|
||||
// Should not happen
|
||||
panic!("self destroyed before modify_task was stopped!");
|
||||
};
|
||||
|
||||
let sg = sg2.lock().await;
|
||||
self_.draw(&sg).await;
|
||||
}
|
||||
});
|
||||
|
||||
let sg2 = sg.clone();
|
||||
let redraw_fn = move |self_: Arc<Self>| {
|
||||
let sg = sg2.clone();
|
||||
async move {
|
||||
let sg = sg.lock().await;
|
||||
self_.draw(&sg).await;
|
||||
}
|
||||
};
|
||||
|
||||
let mut on_modify = OnModify::new(ex.clone(), node_name, node_id, me.clone());
|
||||
on_modify.when_change(scale_prop, redraw_fn);
|
||||
|
||||
let mut tasks = on_modify.tasks;
|
||||
tasks.push(resize_task);
|
||||
|
||||
Self { node_id, tasks, screen_size_prop, render_api }
|
||||
});
|
||||
|
||||
Pimpl::Window(self_)
|
||||
}
|
||||
|
||||
async fn draw(&self, sg: &SceneGraph) {
|
||||
debug!(target: "app", "Window::draw()");
|
||||
// SceneGraph should remain locked for the entire draw
|
||||
let self_node = sg.get_node(self.node_id).unwrap();
|
||||
|
||||
let screen_width = self.screen_size_prop.get_f32(0).unwrap();
|
||||
let screen_height = self.screen_size_prop.get_f32(1).unwrap();
|
||||
|
||||
let parent_rect = Rectangle { x: 0., y: 0., w: screen_width, h: screen_height };
|
||||
|
||||
let mut draw_calls = vec![];
|
||||
let mut child_calls = vec![];
|
||||
for child_inf in self_node.get_children2() {
|
||||
let node = sg.get_node(child_inf.id).unwrap();
|
||||
debug!(target: "app", "Window::draw() calling draw() for node '{}':{}", node.name, node.id);
|
||||
|
||||
let dcs = match &node.pimpl {
|
||||
Pimpl::RenderLayer(layer) => layer.draw(sg, &parent_rect).await,
|
||||
_ => {
|
||||
error!(target: "app", "unhandled pimpl type");
|
||||
continue
|
||||
}
|
||||
};
|
||||
let Some(mut draw_update) = dcs else { continue };
|
||||
draw_calls.append(&mut draw_update.draw_calls);
|
||||
child_calls.push(draw_update.key);
|
||||
}
|
||||
|
||||
let root_dc = DrawCall { instrs: vec![], dcs: child_calls };
|
||||
draw_calls.push((0, root_dc));
|
||||
//debug!(" => {:?}", draw_calls);
|
||||
|
||||
self.render_api.replace_draw_calls(draw_calls).await;
|
||||
debug!("Window::draw() - replaced draw call");
|
||||
}
|
||||
}
|
||||
|
||||
// Nodes should be stopped before being removed
|
||||
impl Stoppable for Window {
|
||||
async fn stop(&self) {}
|
||||
}
|
||||
|
||||
pub type RenderLayerPtr = Arc<RenderLayer>;
|
||||
|
||||
pub struct RenderLayer {
|
||||
sg: SceneGraphPtr2,
|
||||
node_id: SceneNodeId,
|
||||
tasks: Vec<smol::Task<()>>,
|
||||
render_api: RenderApiPtr,
|
||||
|
||||
dc_key: u64,
|
||||
|
||||
is_visible: PropertyBool,
|
||||
rect: PropertyPtr,
|
||||
|
||||
parent_rect: Mutex<Rectangle<f32>>,
|
||||
}
|
||||
|
||||
impl RenderLayer {
|
||||
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 node_name = node.name.clone();
|
||||
|
||||
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 mut on_modify = OnModify::new(ex.clone(), node_name, node_id, me.clone());
|
||||
on_modify.when_change(rect.clone(), Self::redraw);
|
||||
|
||||
Self {
|
||||
sg: sg_ptr,
|
||||
node_id,
|
||||
tasks: on_modify.tasks,
|
||||
render_api,
|
||||
dc_key: OsRng.gen(),
|
||||
is_visible,
|
||||
rect,
|
||||
parent_rect: Mutex::new(Rectangle { x: 0., y: 0., w: 0., h: 0. }),
|
||||
}
|
||||
});
|
||||
|
||||
Pimpl::RenderLayer(self_)
|
||||
}
|
||||
|
||||
async fn redraw(self: Arc<Self>) {
|
||||
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;
|
||||
};
|
||||
|
||||
let Some(draw_update) = self.draw(&sg, &parent_rect).await else {
|
||||
error!("RenderLayer {:?} failed to draw", node);
|
||||
return;
|
||||
};
|
||||
self.render_api.replace_draw_calls(draw_update.draw_calls).await;
|
||||
debug!("replace draw calls done");
|
||||
}
|
||||
|
||||
#[async_recursion]
|
||||
pub async fn draw(&self, sg: &SceneGraph, parent_rect: &Rectangle<f32>) -> Option<DrawUpdate> {
|
||||
debug!(target: "app", "RenderLayer::draw()");
|
||||
let node = sg.get_node(self.node_id).unwrap();
|
||||
|
||||
if !self.is_visible.get() {
|
||||
debug!(target: "app", "invisible layer node '{}':{}", node.name, node.id);
|
||||
return None
|
||||
}
|
||||
|
||||
if let Err(err) = eval_rect(self.rect.clone(), parent_rect) {
|
||||
panic!("Node {:?} bad rect property: {}", node, err);
|
||||
}
|
||||
|
||||
let Ok(mut rect) = read_rect(self.rect.clone()) else {
|
||||
panic!("Node {:?} bad rect property", node);
|
||||
};
|
||||
|
||||
rect.x += parent_rect.x;
|
||||
rect.y += parent_rect.x;
|
||||
|
||||
if !parent_rect.includes(&rect) {
|
||||
error!(
|
||||
target: "app",
|
||||
"layer '{}':{} rect {:?} is not inside parent {:?}",
|
||||
node.name, node.id, rect, parent_rect
|
||||
);
|
||||
return None
|
||||
}
|
||||
|
||||
debug!(target: "app", "Parent rect: {:?}", parent_rect);
|
||||
debug!(target: "app", "Viewport rect: {:?}", rect);
|
||||
|
||||
// Apply viewport
|
||||
|
||||
let mut draw_calls = vec![];
|
||||
let mut child_calls = vec![];
|
||||
for child_inf in node.get_children2() {
|
||||
let node = sg.get_node(child_inf.id).unwrap();
|
||||
|
||||
let dcs = match &node.pimpl {
|
||||
Pimpl::RenderLayer(layer) => layer.draw(&sg, &rect).await,
|
||||
Pimpl::Mesh(mesh) => mesh.draw(&sg, &rect),
|
||||
_ => {
|
||||
error!(target: "app", "unhandled pimpl type");
|
||||
continue
|
||||
}
|
||||
};
|
||||
let Some(mut draw_update) = dcs else { continue };
|
||||
draw_calls.append(&mut draw_update.draw_calls);
|
||||
child_calls.push(draw_update.key);
|
||||
}
|
||||
|
||||
let dc = DrawCall { instrs: vec![DrawInstruction::ApplyViewport(rect)], dcs: child_calls };
|
||||
draw_calls.push((self.dc_key, dc));
|
||||
Some(DrawUpdate { key: self.dc_key, draw_calls })
|
||||
}
|
||||
}
|
||||
|
||||
impl Stoppable for RenderLayer {
|
||||
async fn stop(&self) {}
|
||||
}
|
||||
|
||||
pub struct Mesh {
|
||||
render_api: RenderApiPtr,
|
||||
vertex_buffer: miniquad::BufferId,
|
||||
index_buffer: miniquad::BufferId,
|
||||
// Texture
|
||||
num_elements: i32,
|
||||
|
||||
dc_key: u64,
|
||||
|
||||
node_id: SceneNodeId,
|
||||
rect: PropertyPtr,
|
||||
}
|
||||
|
||||
impl Mesh {
|
||||
pub async fn new(
|
||||
sg: SceneGraphPtr2,
|
||||
node_id: SceneNodeId,
|
||||
render_api: RenderApiPtr,
|
||||
verts: Vec<Vertex>,
|
||||
indices: Vec<u16>,
|
||||
) -> Pimpl {
|
||||
let num_elements = indices.len() as i32;
|
||||
let vertex_buffer = render_api.new_vertex_buffer(verts).await.unwrap();
|
||||
let index_buffer = render_api.new_index_buffer(indices).await.unwrap();
|
||||
|
||||
let mut sg = sg.lock().await;
|
||||
let node = sg.get_node_mut(node_id).unwrap();
|
||||
let rect = node.get_property("rect").expect("RenderLayer::rect");
|
||||
|
||||
Pimpl::Mesh(Self {
|
||||
render_api,
|
||||
vertex_buffer,
|
||||
index_buffer,
|
||||
num_elements,
|
||||
dc_key: OsRng.gen(),
|
||||
node_id,
|
||||
rect,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn draw(&self, sg: &SceneGraph, parent_rect: &Rectangle<f32>) -> Option<DrawUpdate> {
|
||||
debug!(target: "app", "Mesh::draw()");
|
||||
// Only used for debug messages
|
||||
let node = sg.get_node(self.node_id).unwrap();
|
||||
|
||||
let mesh = DrawMesh {
|
||||
vertex_buffer: self.vertex_buffer,
|
||||
index_buffer: self.index_buffer,
|
||||
texture: None,
|
||||
num_elements: self.num_elements,
|
||||
};
|
||||
|
||||
if let Err(err) = eval_rect(self.rect.clone(), parent_rect) {
|
||||
panic!("Node {:?} bad rect property: {}", node, err);
|
||||
}
|
||||
|
||||
let Ok(mut rect) = read_rect(self.rect.clone()) else {
|
||||
panic!("Node {:?} bad rect property", node);
|
||||
};
|
||||
|
||||
rect.x += parent_rect.x;
|
||||
rect.y += parent_rect.x;
|
||||
|
||||
let off_x = rect.x / parent_rect.w;
|
||||
let off_y = rect.y / parent_rect.h;
|
||||
let scale_x = rect.w / parent_rect.w;
|
||||
let scale_y = rect.h / parent_rect.h;
|
||||
let model = glam::Mat4::from_translation(glam::Vec3::new(off_x, off_y, 0.)) *
|
||||
glam::Mat4::from_scale(glam::Vec3::new(scale_x, scale_y, 1.));
|
||||
|
||||
Some(DrawUpdate {
|
||||
key: self.dc_key,
|
||||
draw_calls: vec![(
|
||||
self.dc_key,
|
||||
DrawCall {
|
||||
instrs: vec![DrawInstruction::ApplyMatrix(model), DrawInstruction::Draw(mesh)],
|
||||
dcs: vec![],
|
||||
},
|
||||
)],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Stoppable for Mesh {
|
||||
async fn stop(&self) {
|
||||
// TODO: Delete own draw call
|
||||
|
||||
// Free buffers
|
||||
// Should this be in drop?
|
||||
self.render_api.delete_buffer(self.vertex_buffer);
|
||||
self.render_api.delete_buffer(self.index_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ fn create_chatview(sg: &mut SceneGraph, name: &str, layer_node_id: SceneNodeId)
|
||||
let mut arg_data = vec![];
|
||||
node_id.encode(&mut arg_data).unwrap();
|
||||
//let (tx, rx) = mpsc::sync_channel::<Result<Vec<u8>>>(0);
|
||||
let response_fn = Box::new(move |result| {
|
||||
let response_fn = Box::new(move |_result| {
|
||||
//tx.send(result).unwrap();
|
||||
});
|
||||
let win_node = sg.lookup_node_mut("/window").unwrap();
|
||||
|
||||
@@ -590,7 +590,7 @@ impl EditBox {
|
||||
"Delete" => {
|
||||
let cursor_pos = self.cursor_pos.get();
|
||||
|
||||
let text = if !self.selected.is_null(0).unwrap() {
|
||||
let _text = if !self.selected.is_null(0).unwrap() {
|
||||
self.delete_highlighted();
|
||||
} else {
|
||||
let glyphs = &*self.glyphs.lock().unwrap();
|
||||
@@ -618,7 +618,7 @@ impl EditBox {
|
||||
"Backspace" => {
|
||||
let cursor_pos = self.cursor_pos.get();
|
||||
|
||||
let text = if !self.selected.is_null(0).unwrap() {
|
||||
let _text = if !self.selected.is_null(0).unwrap() {
|
||||
self.delete_highlighted();
|
||||
} else {
|
||||
if cursor_pos == 0 {
|
||||
|
||||
@@ -230,10 +230,7 @@ pub struct GraphicsEventPublisher {
|
||||
|
||||
impl GraphicsEventPublisher {
|
||||
pub fn new() -> Arc<Self> {
|
||||
Arc::new(Self {
|
||||
key_down: Publisher::new(),
|
||||
resize: Publisher::new(),
|
||||
})
|
||||
Arc::new(Self { key_down: Publisher::new(), resize: Publisher::new() })
|
||||
}
|
||||
|
||||
fn notify_key_down(&self, key: KeyCode, mods: KeyMods, repeat: bool) {
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#![feature(deadline_api)]
|
||||
#![feature(str_split_whitespace_remainder)]
|
||||
|
||||
// Use these to incrementally fix warnings with cargo fix
|
||||
//#![allow(warnings, unused)]
|
||||
//#![deny(unused_imports)]
|
||||
|
||||
use async_lock::Mutex;
|
||||
use futures::{stream::FuturesUnordered, StreamExt};
|
||||
use std::{
|
||||
@@ -31,6 +35,7 @@ mod res;
|
||||
mod scene;
|
||||
mod shader;
|
||||
mod text;
|
||||
mod ui;
|
||||
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
|
||||
@@ -16,6 +16,7 @@ use crate::{
|
||||
app, chatview, editbox,
|
||||
error::{Error, Result},
|
||||
prop::{Property, PropertyPtr, PropertyType},
|
||||
ui,
|
||||
};
|
||||
|
||||
pub type SceneNodeId = u32;
|
||||
@@ -637,9 +638,9 @@ pub enum Pimpl {
|
||||
Null,
|
||||
EditBox(editbox::EditBoxPtr),
|
||||
ChatView(chatview::ChatViewPtr),
|
||||
Window(app::WindowPtr),
|
||||
RenderLayer(app::RenderLayerPtr),
|
||||
Mesh(app::Mesh),
|
||||
Window(ui::WindowPtr),
|
||||
RenderLayer(ui::RenderLayerPtr),
|
||||
Mesh(ui::Mesh),
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for SceneNode {
|
||||
|
||||
163
bin/darkwallet/src/ui/layer.rs
Normal file
163
bin/darkwallet/src/ui/layer.rs
Normal file
@@ -0,0 +1,163 @@
|
||||
use async_lock::Mutex;
|
||||
use async_recursion::async_recursion;
|
||||
use futures::{stream::FuturesUnordered, StreamExt};
|
||||
use rand::{rngs::OsRng, Rng};
|
||||
use std::{
|
||||
sync::{mpsc, Arc, Weak},
|
||||
thread,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
chatapp,
|
||||
error::{Error, Result},
|
||||
expr::{Op, SExprMachine, SExprVal},
|
||||
gfx::Rectangle,
|
||||
gfx2::{
|
||||
self, DrawCall, DrawInstruction, DrawMesh, GraphicsEventPublisherPtr, RenderApiPtr, Vertex,
|
||||
},
|
||||
prop::{
|
||||
Property, PropertyBool, PropertyColor, PropertyFloat32, PropertyPtr, PropertyStr,
|
||||
PropertySubType, PropertyType, PropertyUint32,
|
||||
},
|
||||
pubsub::PublisherPtr,
|
||||
scene::{
|
||||
MethodResponseFn, Pimpl, SceneGraph, SceneGraphPtr2, SceneNode, SceneNodeId, SceneNodeInfo,
|
||||
SceneNodeType,
|
||||
},
|
||||
};
|
||||
|
||||
use super::{eval_rect, get_parent_rect, read_rect, DrawUpdate, OnModify, Stoppable};
|
||||
|
||||
pub type RenderLayerPtr = Arc<RenderLayer>;
|
||||
|
||||
pub struct RenderLayer {
|
||||
sg: SceneGraphPtr2,
|
||||
node_id: SceneNodeId,
|
||||
tasks: Vec<smol::Task<()>>,
|
||||
render_api: RenderApiPtr,
|
||||
|
||||
dc_key: u64,
|
||||
|
||||
is_visible: PropertyBool,
|
||||
rect: PropertyPtr,
|
||||
|
||||
parent_rect: Mutex<Rectangle<f32>>,
|
||||
}
|
||||
|
||||
impl RenderLayer {
|
||||
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 node_name = node.name.clone();
|
||||
|
||||
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 mut on_modify = OnModify::new(ex.clone(), node_name, node_id, me.clone());
|
||||
on_modify.when_change(rect.clone(), Self::redraw);
|
||||
|
||||
Self {
|
||||
sg: sg_ptr,
|
||||
node_id,
|
||||
tasks: on_modify.tasks,
|
||||
render_api,
|
||||
dc_key: OsRng.gen(),
|
||||
is_visible,
|
||||
rect,
|
||||
parent_rect: Mutex::new(Rectangle { x: 0., y: 0., w: 0., h: 0. }),
|
||||
}
|
||||
});
|
||||
|
||||
Pimpl::RenderLayer(self_)
|
||||
}
|
||||
|
||||
async fn redraw(self: Arc<Self>) {
|
||||
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;
|
||||
};
|
||||
|
||||
let Some(draw_update) = self.draw(&sg, &parent_rect).await else {
|
||||
error!("RenderLayer {:?} failed to draw", node);
|
||||
return;
|
||||
};
|
||||
self.render_api.replace_draw_calls(draw_update.draw_calls).await;
|
||||
debug!("replace draw calls done");
|
||||
}
|
||||
|
||||
#[async_recursion]
|
||||
pub async fn draw(&self, sg: &SceneGraph, parent_rect: &Rectangle<f32>) -> Option<DrawUpdate> {
|
||||
debug!(target: "app", "RenderLayer::draw()");
|
||||
let node = sg.get_node(self.node_id).unwrap();
|
||||
|
||||
if !self.is_visible.get() {
|
||||
debug!(target: "app", "invisible layer node '{}':{}", node.name, node.id);
|
||||
return None
|
||||
}
|
||||
|
||||
if let Err(err) = eval_rect(self.rect.clone(), parent_rect) {
|
||||
panic!("Node {:?} bad rect property: {}", node, err);
|
||||
}
|
||||
|
||||
let Ok(mut rect) = read_rect(self.rect.clone()) else {
|
||||
panic!("Node {:?} bad rect property", node);
|
||||
};
|
||||
|
||||
rect.x += parent_rect.x;
|
||||
rect.y += parent_rect.x;
|
||||
|
||||
if !parent_rect.includes(&rect) {
|
||||
error!(
|
||||
target: "app",
|
||||
"layer '{}':{} rect {:?} is not inside parent {:?}",
|
||||
node.name, node.id, rect, parent_rect
|
||||
);
|
||||
return None
|
||||
}
|
||||
|
||||
debug!(target: "app", "Parent rect: {:?}", parent_rect);
|
||||
debug!(target: "app", "Viewport rect: {:?}", rect);
|
||||
|
||||
// Apply viewport
|
||||
|
||||
let mut draw_calls = vec![];
|
||||
let mut child_calls = vec![];
|
||||
for child_inf in node.get_children2() {
|
||||
let node = sg.get_node(child_inf.id).unwrap();
|
||||
|
||||
let dcs = match &node.pimpl {
|
||||
Pimpl::RenderLayer(layer) => layer.draw(&sg, &rect).await,
|
||||
Pimpl::Mesh(mesh) => mesh.draw(&sg, &rect),
|
||||
_ => {
|
||||
error!(target: "app", "unhandled pimpl type");
|
||||
continue
|
||||
}
|
||||
};
|
||||
let Some(mut draw_update) = dcs else { continue };
|
||||
draw_calls.append(&mut draw_update.draw_calls);
|
||||
child_calls.push(draw_update.key);
|
||||
}
|
||||
|
||||
let dc = DrawCall { instrs: vec![DrawInstruction::ApplyViewport(rect)], dcs: child_calls };
|
||||
draw_calls.push((self.dc_key, dc));
|
||||
Some(DrawUpdate { key: self.dc_key, draw_calls })
|
||||
}
|
||||
}
|
||||
|
||||
impl Stoppable for RenderLayer {
|
||||
async fn stop(&self) {}
|
||||
}
|
||||
123
bin/darkwallet/src/ui/mesh.rs
Normal file
123
bin/darkwallet/src/ui/mesh.rs
Normal file
@@ -0,0 +1,123 @@
|
||||
use async_lock::Mutex;
|
||||
use async_recursion::async_recursion;
|
||||
use futures::{stream::FuturesUnordered, StreamExt};
|
||||
use rand::{rngs::OsRng, Rng};
|
||||
use std::{
|
||||
sync::{mpsc, Arc, Weak},
|
||||
thread,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
chatapp,
|
||||
error::{Error, Result},
|
||||
expr::{Op, SExprMachine, SExprVal},
|
||||
gfx::Rectangle,
|
||||
gfx2::{
|
||||
self, DrawCall, DrawInstruction, DrawMesh, GraphicsEventPublisherPtr, RenderApiPtr, Vertex,
|
||||
},
|
||||
prop::{
|
||||
Property, PropertyBool, PropertyColor, PropertyFloat32, PropertyPtr, PropertyStr,
|
||||
PropertySubType, PropertyType, PropertyUint32,
|
||||
},
|
||||
pubsub::PublisherPtr,
|
||||
scene::{
|
||||
MethodResponseFn, Pimpl, SceneGraph, SceneGraphPtr2, SceneNode, SceneNodeId, SceneNodeInfo,
|
||||
SceneNodeType,
|
||||
},
|
||||
};
|
||||
|
||||
use super::{eval_rect, read_rect, DrawUpdate, Stoppable};
|
||||
|
||||
pub struct Mesh {
|
||||
render_api: RenderApiPtr,
|
||||
vertex_buffer: miniquad::BufferId,
|
||||
index_buffer: miniquad::BufferId,
|
||||
// Texture
|
||||
num_elements: i32,
|
||||
|
||||
dc_key: u64,
|
||||
|
||||
node_id: SceneNodeId,
|
||||
rect: PropertyPtr,
|
||||
}
|
||||
|
||||
impl Mesh {
|
||||
pub async fn new(
|
||||
sg: SceneGraphPtr2,
|
||||
node_id: SceneNodeId,
|
||||
render_api: RenderApiPtr,
|
||||
verts: Vec<Vertex>,
|
||||
indices: Vec<u16>,
|
||||
) -> Pimpl {
|
||||
let num_elements = indices.len() as i32;
|
||||
let vertex_buffer = render_api.new_vertex_buffer(verts).await.unwrap();
|
||||
let index_buffer = render_api.new_index_buffer(indices).await.unwrap();
|
||||
|
||||
let mut sg = sg.lock().await;
|
||||
let node = sg.get_node_mut(node_id).unwrap();
|
||||
let rect = node.get_property("rect").expect("RenderLayer::rect");
|
||||
|
||||
Pimpl::Mesh(Self {
|
||||
render_api,
|
||||
vertex_buffer,
|
||||
index_buffer,
|
||||
num_elements,
|
||||
dc_key: OsRng.gen(),
|
||||
node_id,
|
||||
rect,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn draw(&self, sg: &SceneGraph, parent_rect: &Rectangle<f32>) -> Option<DrawUpdate> {
|
||||
debug!(target: "app", "Mesh::draw()");
|
||||
// Only used for debug messages
|
||||
let node = sg.get_node(self.node_id).unwrap();
|
||||
|
||||
let mesh = DrawMesh {
|
||||
vertex_buffer: self.vertex_buffer,
|
||||
index_buffer: self.index_buffer,
|
||||
texture: None,
|
||||
num_elements: self.num_elements,
|
||||
};
|
||||
|
||||
if let Err(err) = eval_rect(self.rect.clone(), parent_rect) {
|
||||
panic!("Node {:?} bad rect property: {}", node, err);
|
||||
}
|
||||
|
||||
let Ok(mut rect) = read_rect(self.rect.clone()) else {
|
||||
panic!("Node {:?} bad rect property", node);
|
||||
};
|
||||
|
||||
rect.x += parent_rect.x;
|
||||
rect.y += parent_rect.x;
|
||||
|
||||
let off_x = rect.x / parent_rect.w;
|
||||
let off_y = rect.y / parent_rect.h;
|
||||
let scale_x = rect.w / parent_rect.w;
|
||||
let scale_y = rect.h / parent_rect.h;
|
||||
let model = glam::Mat4::from_translation(glam::Vec3::new(off_x, off_y, 0.)) *
|
||||
glam::Mat4::from_scale(glam::Vec3::new(scale_x, scale_y, 1.));
|
||||
|
||||
Some(DrawUpdate {
|
||||
key: self.dc_key,
|
||||
draw_calls: vec![(
|
||||
self.dc_key,
|
||||
DrawCall {
|
||||
instrs: vec![DrawInstruction::ApplyMatrix(model), DrawInstruction::Draw(mesh)],
|
||||
dcs: vec![],
|
||||
},
|
||||
)],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Stoppable for Mesh {
|
||||
async fn stop(&self) {
|
||||
// TODO: Delete own draw call
|
||||
|
||||
// Free buffers
|
||||
// Should this be in drop?
|
||||
self.render_api.delete_buffer(self.vertex_buffer);
|
||||
self.render_api.delete_buffer(self.index_buffer);
|
||||
}
|
||||
}
|
||||
190
bin/darkwallet/src/ui/mod.rs
Normal file
190
bin/darkwallet/src/ui/mod.rs
Normal file
@@ -0,0 +1,190 @@
|
||||
use async_lock::Mutex;
|
||||
use async_recursion::async_recursion;
|
||||
use futures::{stream::FuturesUnordered, StreamExt};
|
||||
use rand::{rngs::OsRng, Rng};
|
||||
use std::{
|
||||
sync::{mpsc, Arc, Weak},
|
||||
thread,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
chatapp,
|
||||
error::{Error, Result},
|
||||
expr::{Op, SExprMachine, SExprVal},
|
||||
gfx::Rectangle,
|
||||
gfx2::{
|
||||
self, DrawCall, DrawInstruction, DrawMesh, GraphicsEventPublisherPtr, RenderApiPtr, Vertex,
|
||||
},
|
||||
prop::{
|
||||
Property, PropertyBool, PropertyColor, PropertyFloat32, PropertyPtr, PropertyStr,
|
||||
PropertySubType, PropertyType, PropertyUint32,
|
||||
},
|
||||
pubsub::PublisherPtr,
|
||||
scene::{
|
||||
MethodResponseFn, Pimpl, SceneGraph, SceneGraphPtr2, SceneNode, SceneNodeId, SceneNodeInfo,
|
||||
SceneNodeType,
|
||||
},
|
||||
};
|
||||
|
||||
mod mesh;
|
||||
pub use mesh::Mesh;
|
||||
mod layer;
|
||||
pub use layer::{RenderLayer, RenderLayerPtr};
|
||||
mod win;
|
||||
pub use win::{Window, WindowPtr};
|
||||
|
||||
pub trait Stoppable {
|
||||
async fn stop(&self);
|
||||
}
|
||||
|
||||
pub struct DrawUpdate {
|
||||
pub key: u64,
|
||||
pub draw_calls: Vec<(u64, DrawCall)>,
|
||||
}
|
||||
|
||||
pub struct OnModify<T> {
|
||||
ex: Arc<smol::Executor<'static>>,
|
||||
node_name: String,
|
||||
node_id: SceneNodeId,
|
||||
me: Weak<T>,
|
||||
pub tasks: Vec<smol::Task<()>>,
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> OnModify<T> {
|
||||
pub fn new(
|
||||
ex: Arc<smol::Executor<'static>>,
|
||||
node_name: String,
|
||||
node_id: SceneNodeId,
|
||||
me: Weak<T>,
|
||||
) -> Self {
|
||||
Self { ex, node_name, node_id, me, tasks: vec![] }
|
||||
}
|
||||
|
||||
pub fn when_change<F>(&mut self, prop: PropertyPtr, f: impl Fn(Arc<T>) -> F + Send + 'static)
|
||||
where
|
||||
F: std::future::Future<Output = ()> + Send + 'static,
|
||||
{
|
||||
let node_name = self.node_name.clone();
|
||||
let node_id = self.node_id;
|
||||
let on_modify_sub = prop.subscribe_modify();
|
||||
let prop_name = prop.name.clone();
|
||||
let me = self.me.clone();
|
||||
let task = self.ex.spawn(async move {
|
||||
loop {
|
||||
let _ = on_modify_sub.receive().await;
|
||||
debug!(target: "app", "Property '{}':{}/'{}' modified", node_name, node_id, prop_name);
|
||||
|
||||
let Some(self_) = me.upgrade() else {
|
||||
// Should not happen
|
||||
panic!(
|
||||
"'{}':{}/'{}' self destroyed before modify_task was stopped!",
|
||||
node_name, node_id, prop_name
|
||||
);
|
||||
};
|
||||
|
||||
debug!(target: "app", "property modified");
|
||||
f(self_).await;
|
||||
}
|
||||
});
|
||||
self.tasks.push(task);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eval_rect(rect: PropertyPtr, parent_rect: &Rectangle<f32>) -> Result<()> {
|
||||
if rect.array_len != 4 {
|
||||
return Err(Error::PropertyWrongLen)
|
||||
}
|
||||
|
||||
for i in 0..4 {
|
||||
if !rect.is_expr(i)? {
|
||||
continue
|
||||
}
|
||||
|
||||
let expr = rect.get_expr(i).unwrap();
|
||||
|
||||
let machine = SExprMachine {
|
||||
globals: vec![
|
||||
("w".to_string(), SExprVal::Float32(parent_rect.w)),
|
||||
("h".to_string(), SExprVal::Float32(parent_rect.h)),
|
||||
],
|
||||
stmts: &expr,
|
||||
};
|
||||
|
||||
let v = machine.call()?.as_f32()?;
|
||||
rect.set_cache_f32(i, v).unwrap();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub 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))
|
||||
}
|
||||
|
||||
pub fn get_parent_rect(sg: &SceneGraph, node: &SceneNode) -> Option<Rectangle<f32>> {
|
||||
// read our parent
|
||||
if node.parents.is_empty() {
|
||||
info!("RenderLayer {:?} has no parents so skipping", node);
|
||||
return None
|
||||
}
|
||||
if node.parents.len() != 1 {
|
||||
error!("RenderLayer {:?} has too many parents so skipping", node);
|
||||
return None
|
||||
}
|
||||
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 None
|
||||
};
|
||||
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 None
|
||||
};
|
||||
// read parent's rect
|
||||
let Ok(parent_rect) = read_rect(parent_rect) else {
|
||||
error!(
|
||||
"RenderLayer {:?} parent node {:?} malformed rect property",
|
||||
node, parent_node
|
||||
);
|
||||
return None
|
||||
};
|
||||
parent_rect
|
||||
}
|
||||
_ => {
|
||||
error!(
|
||||
"RenderLayer {:?} parent node {:?} wrong type {:?}",
|
||||
node, parent_node, parent_node.typ
|
||||
);
|
||||
return None
|
||||
}
|
||||
};
|
||||
Some(parent_rect)
|
||||
}
|
||||
147
bin/darkwallet/src/ui/win.rs
Normal file
147
bin/darkwallet/src/ui/win.rs
Normal file
@@ -0,0 +1,147 @@
|
||||
use async_lock::Mutex;
|
||||
use async_recursion::async_recursion;
|
||||
use futures::{stream::FuturesUnordered, StreamExt};
|
||||
use rand::{rngs::OsRng, Rng};
|
||||
use std::{
|
||||
sync::{mpsc, Arc, Weak},
|
||||
thread,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
chatapp,
|
||||
error::{Error, Result},
|
||||
expr::{Op, SExprMachine, SExprVal},
|
||||
gfx::Rectangle,
|
||||
gfx2::{
|
||||
self, DrawCall, DrawInstruction, DrawMesh, GraphicsEventPublisherPtr, RenderApiPtr, Vertex,
|
||||
},
|
||||
prop::{
|
||||
Property, PropertyBool, PropertyColor, PropertyFloat32, PropertyPtr, PropertyStr,
|
||||
PropertySubType, PropertyType, PropertyUint32,
|
||||
},
|
||||
pubsub::PublisherPtr,
|
||||
scene::{
|
||||
MethodResponseFn, Pimpl, SceneGraph, SceneGraphPtr2, SceneNode, SceneNodeId, SceneNodeInfo,
|
||||
SceneNodeType,
|
||||
},
|
||||
};
|
||||
|
||||
use super::{eval_rect, read_rect, DrawUpdate, OnModify, Stoppable};
|
||||
|
||||
pub type WindowPtr = Arc<Window>;
|
||||
|
||||
pub struct Window {
|
||||
node_id: SceneNodeId,
|
||||
tasks: Vec<smol::Task<()>>,
|
||||
screen_size_prop: PropertyPtr,
|
||||
render_api: RenderApiPtr,
|
||||
}
|
||||
|
||||
impl Window {
|
||||
pub async fn new(
|
||||
sg: SceneGraphPtr2,
|
||||
node_id: SceneNodeId,
|
||||
ex: Arc<smol::Executor<'static>>,
|
||||
render_api: RenderApiPtr,
|
||||
event_pub: GraphicsEventPublisherPtr,
|
||||
) -> Pimpl {
|
||||
debug!(target: "app", "Window::new()");
|
||||
|
||||
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 scale_prop = node.get_property("scale").unwrap();
|
||||
drop(scene_graph);
|
||||
|
||||
let self_ = Arc::new_cyclic(|me: &Weak<Self>| {
|
||||
// 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 me2 = me.clone();
|
||||
let sg2 = sg.clone();
|
||||
let resize_task = ex.spawn(async move {
|
||||
loop {
|
||||
let Ok((w, h)) = ev_sub.receive().await else {
|
||||
debug!(target: "app", "Event relayer closed");
|
||||
break
|
||||
};
|
||||
|
||||
debug!(target: "app", "Window resized ({w}, {h})");
|
||||
// Now update the properties
|
||||
screen_size_prop2.set_f32(0, w);
|
||||
screen_size_prop2.set_f32(1, h);
|
||||
|
||||
let Some(self_) = me2.upgrade() else {
|
||||
// Should not happen
|
||||
panic!("self destroyed before modify_task was stopped!");
|
||||
};
|
||||
|
||||
let sg = sg2.lock().await;
|
||||
self_.draw(&sg).await;
|
||||
}
|
||||
});
|
||||
|
||||
let sg2 = sg.clone();
|
||||
let redraw_fn = move |self_: Arc<Self>| {
|
||||
let sg = sg2.clone();
|
||||
async move {
|
||||
let sg = sg.lock().await;
|
||||
self_.draw(&sg).await;
|
||||
}
|
||||
};
|
||||
|
||||
let mut on_modify = OnModify::new(ex.clone(), node_name, node_id, me.clone());
|
||||
on_modify.when_change(scale_prop, redraw_fn);
|
||||
|
||||
let mut tasks = on_modify.tasks;
|
||||
tasks.push(resize_task);
|
||||
|
||||
Self { node_id, tasks, screen_size_prop, render_api }
|
||||
});
|
||||
|
||||
Pimpl::Window(self_)
|
||||
}
|
||||
|
||||
pub async fn draw(&self, sg: &SceneGraph) {
|
||||
debug!(target: "app", "Window::draw()");
|
||||
// SceneGraph should remain locked for the entire draw
|
||||
let self_node = sg.get_node(self.node_id).unwrap();
|
||||
|
||||
let screen_width = self.screen_size_prop.get_f32(0).unwrap();
|
||||
let screen_height = self.screen_size_prop.get_f32(1).unwrap();
|
||||
|
||||
let parent_rect = Rectangle { x: 0., y: 0., w: screen_width, h: screen_height };
|
||||
|
||||
let mut draw_calls = vec![];
|
||||
let mut child_calls = vec![];
|
||||
for child_inf in self_node.get_children2() {
|
||||
let node = sg.get_node(child_inf.id).unwrap();
|
||||
debug!(target: "app", "Window::draw() calling draw() for node '{}':{}", node.name, node.id);
|
||||
|
||||
let dcs = match &node.pimpl {
|
||||
Pimpl::RenderLayer(layer) => layer.draw(sg, &parent_rect).await,
|
||||
_ => {
|
||||
error!(target: "app", "unhandled pimpl type");
|
||||
continue
|
||||
}
|
||||
};
|
||||
let Some(mut draw_update) = dcs else { continue };
|
||||
draw_calls.append(&mut draw_update.draw_calls);
|
||||
child_calls.push(draw_update.key);
|
||||
}
|
||||
|
||||
let root_dc = DrawCall { instrs: vec![], dcs: child_calls };
|
||||
draw_calls.push((0, root_dc));
|
||||
//debug!(" => {:?}", draw_calls);
|
||||
|
||||
self.render_api.replace_draw_calls(draw_calls).await;
|
||||
debug!("Window::draw() - replaced draw call");
|
||||
}
|
||||
}
|
||||
|
||||
// Nodes should be stopped before being removed
|
||||
impl Stoppable for Window {
|
||||
async fn stop(&self) {}
|
||||
}
|
||||
Reference in New Issue
Block a user