diff --git a/bin/darkwallet/gui/print_tree.py b/bin/darkwallet/gui/print_tree.py index bb275038e..a60ee695e 100644 --- a/bin/darkwallet/gui/print_tree.py +++ b/bin/darkwallet/gui/print_tree.py @@ -43,6 +43,8 @@ def print_node_info(parent_id, indent): child_type = "chat_view" case SceneNodeType.EDIT_BOX: child_type = "edit_box" + case SceneNodeType.BUTTON: + child_type = "button" desc = f"{ws}{child_name}:{child_id}/" desc += " "*(50 - len(desc)) diff --git a/bin/darkwallet/pydrk/api.py b/bin/darkwallet/pydrk/api.py index 630515c95..a8a506307 100644 --- a/bin/darkwallet/pydrk/api.py +++ b/bin/darkwallet/pydrk/api.py @@ -60,6 +60,7 @@ class SceneNodeType: PLUGIN = 15 CHAT_VIEW = 16 EDIT_BOX = 17 + BUTTON = 18 class PropertyType: NULL = 0 diff --git a/bin/darkwallet/src/app.rs b/bin/darkwallet/src/app.rs index 407f1964d..6ecf8fa9d 100644 --- a/bin/darkwallet/src/app.rs +++ b/bin/darkwallet/src/app.rs @@ -27,7 +27,7 @@ use crate::{ prop::{Property, PropertySubType, PropertyType}, scene::{Pimpl, SceneGraph, SceneGraphPtr2, SceneNodeId, SceneNodeType}, text2::TextShaperPtr, - ui::{chatview, ChatView, EditBox, Image, Mesh, RenderLayer, Stoppable, Text, Window}, + ui::{chatview, Button, ChatView, EditBox, Image, Mesh, RenderLayer, Stoppable, Text, Window}, }; //fn print_type_of(_: &T) { @@ -278,6 +278,87 @@ impl App { sg.link(node_id, layer_node_id).unwrap(); + // Create button bg + let node_id = create_mesh(&mut sg, "btnbg"); + + let node = sg.get_node_mut(node_id).unwrap(); + let prop = node.get_property("rect").unwrap(); + let code = vec![Op::Sub(( + Box::new(Op::LoadVar("w".to_string())), + Box::new(Op::ConstFloat32(220.)), + ))]; + prop.set_expr(0, code).unwrap(); + prop.set_f32(1, 10.).unwrap(); + prop.set_f32(2, 200.).unwrap(); + prop.set_f32(3, 60.).unwrap(); + + // Setup the pimpl + let (x1, y1) = (0., 0.); + let (x2, y2) = (1., 1.); + let verts = if LIGHTMODE { + vec![ + // top left + Vertex { pos: [x1, y1], color: [1., 0., 0., 1.], uv: [0., 0.] }, + // top right + Vertex { pos: [x2, y1], color: [1., 0., 0., 1.], uv: [1., 0.] }, + // bottom left + Vertex { pos: [x1, y2], color: [1., 0., 0., 1.], uv: [0., 1.] }, + // bottom right + Vertex { pos: [x2, y2], color: [1., 0., 0., 1.], uv: [1., 1.] }, + ] + } else { + vec![ + // top left + Vertex { pos: [x1, y1], color: [1., 0., 0., 1.], uv: [0., 0.] }, + // top right + Vertex { pos: [x2, y1], color: [1., 0., 1., 1.], uv: [1., 0.] }, + // bottom left + Vertex { pos: [x1, y2], color: [0., 0., 1., 1.], uv: [0., 1.] }, + // bottom right + Vertex { pos: [x2, y2], color: [1., 1., 0., 1.], uv: [1., 1.] }, + ] + }; + let indices = vec![0, 2, 1, 1, 2, 3]; + drop(sg); + let pimpl = Mesh::new( + self.ex.clone(), + self.sg.clone(), + node_id, + self.render_api.clone(), + verts, + indices, + ) + .await; + let mut sg = self.sg.lock().await; + let node = sg.get_node_mut(node_id).unwrap(); + node.pimpl = pimpl; + + sg.link(node_id, layer_node_id).unwrap(); + + // Create the button + let node_id = create_button(&mut sg, "btn"); + + let node = sg.get_node_mut(node_id).unwrap(); + node.set_property_bool("is_active", true).unwrap(); + let prop = node.get_property("rect").unwrap(); + let code = vec![Op::Sub(( + Box::new(Op::LoadVar("w".to_string())), + Box::new(Op::ConstFloat32(220.)), + ))]; + prop.set_expr(0, code).unwrap(); + prop.set_f32(1, 10.).unwrap(); + prop.set_f32(2, 200.).unwrap(); + prop.set_f32(3, 60.).unwrap(); + + drop(sg); + let pimpl = + Button::new(self.ex.clone(), self.sg.clone(), node_id, self.event_pub.clone()).await; + let mut sg = self.sg.lock().await; + let node = sg.get_node_mut(node_id).unwrap(); + node.pimpl = pimpl; + + sg.link(node_id, layer_node_id).unwrap(); + // Create another mesh let node_id = create_mesh(&mut sg, "box"); @@ -706,6 +787,22 @@ pub fn create_mesh(sg: &mut SceneGraph, name: &str) -> SceneNodeId { node.id } +pub fn create_button(sg: &mut SceneGraph, name: &str) -> SceneNodeId { + debug!(target: "app", "create_button({name})"); + let node = sg.add_node(name, SceneNodeType::Button); + + let mut prop = Property::new("is_active", PropertyType::Bool, PropertySubType::Null); + prop.set_ui_text("Is Active", "An active Button can be clicked"); + node.add_property(prop).unwrap(); + + let mut prop = Property::new("rect", PropertyType::Float32, PropertySubType::Pixel); + prop.set_array_len(4); + prop.allow_exprs(); + node.add_property(prop).unwrap(); + + node.id +} + pub fn create_image(sg: &mut SceneGraph, name: &str) -> SceneNodeId { debug!(target: "app", "create_image({name})"); let node = sg.add_node(name, SceneNodeType::RenderMesh); diff --git a/bin/darkwallet/src/scene.rs b/bin/darkwallet/src/scene.rs index 8a22d853d..10f2683f1 100644 --- a/bin/darkwallet/src/scene.rs +++ b/bin/darkwallet/src/scene.rs @@ -51,6 +51,7 @@ pub enum SceneNodeType { ChatView = 16, EditBox = 17, Image = 18, + Button = 19, } pub struct ScenePath(Vec); @@ -653,6 +654,7 @@ pub enum Pimpl { EditBox(ui::EditBoxPtr), ChatView(ui::ChatViewPtr), Image(ui::ImagePtr), + Button(ui::ButtonPtr), } impl std::fmt::Debug for SceneNode { diff --git a/bin/darkwallet/src/ui/button.rs b/bin/darkwallet/src/ui/button.rs new file mode 100644 index 000000000..ea8b2869d --- /dev/null +++ b/bin/darkwallet/src/ui/button.rs @@ -0,0 +1,219 @@ +/* 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 . + */ + +use miniquad::{window, BufferId, KeyCode, KeyMods, MouseButton, TextureId, TouchPhase}; +use rand::{rngs::OsRng, Rng}; +use std::sync::{ + atomic::{AtomicBool, Ordering}, + Arc, Weak, +}; + +use crate::{ + gfx2::{ + DrawCall, DrawInstruction, DrawMesh, GraphicsEventPublisherPtr, Point, Rectangle, + RenderApiPtr, Vertex, + }, + prop::{PropertyBool, PropertyPtr, PropertyUint32}, + pubsub::Subscription, + scene::{Pimpl, SceneGraph, SceneGraphPtr2, SceneNodeId}, +}; + +use super::{eval_rect, get_parent_rect, read_rect, DrawUpdate, OnModify, Stoppable}; + +pub type ButtonPtr = Arc