diff --git a/bin/app/Cargo.toml b/bin/app/Cargo.toml index 4ef2926bf..080eac6fe 100644 --- a/bin/app/Cargo.toml +++ b/bin/app/Cargo.toml @@ -76,6 +76,7 @@ enable-netdebug = [] schema-app = [] # Dev schema for testing schema-test = [] +schema-test-scroll-layer = [] [patch.crates-io] halo2_proofs = { git="https://github.com/parazyd/halo2", branch="v032" } diff --git a/bin/app/Makefile b/bin/app/Makefile index d0e44e737..39384a843 100644 --- a/bin/app/Makefile +++ b/bin/app/Makefile @@ -22,7 +22,7 @@ DEBUG_FEATURES = --features=enable-filelog,enable-plugins #DEV_FEATURES = --features=enable-filelog,enable-netdebug,emulate-android #DEV_FEATURES = --features=enable-filelog,enable-netdebug,enable-plugins -DEV_FEATURES = --features=schema-app,enable-netdebug +DEV_FEATURES = --features=schema-test-scroll-layer,enable-netdebug default: build-release ./darkfi-app diff --git a/bin/app/src/app/mod.rs b/bin/app/src/app/mod.rs index 4dc14fdd1..0e88ca26a 100644 --- a/bin/app/src/app/mod.rs +++ b/bin/app/src/app/mod.rs @@ -141,6 +141,9 @@ impl App { #[cfg(feature = "schema-test")] schema::test::make(&self, window.clone(), &i18n_fish).await; + #[cfg(feature = "schema-test-scroll-layer")] + schema::test_scroll_layer::make(&self, window.clone(), &i18n_fish).await; + #[cfg(all(feature = "schema-app", feature = "schema-test"))] compile_error!("Only one schema can be selected"); diff --git a/bin/app/src/app/schema/mod.rs b/bin/app/src/app/schema/mod.rs index b01b98969..86a07740e 100644 --- a/bin/app/src/app/schema/mod.rs +++ b/bin/app/src/app/schema/mod.rs @@ -39,6 +39,7 @@ mod chat; mod menu; //mod settings; pub mod test; +pub mod test_scroll_layer; macro_rules! i { ($($arg:tt)*) => { info!(target: "app::schema", $($arg)*); } } macro_rules! e { ($($arg:tt)*) => { error!(target: "app::schema", $($arg)*); } } diff --git a/bin/app/src/app/schema/test_scroll_layer.rs b/bin/app/src/app/schema/test_scroll_layer.rs new file mode 100644 index 000000000..651dbc6a3 --- /dev/null +++ b/bin/app/src/app/schema/test_scroll_layer.rs @@ -0,0 +1,76 @@ +/* This file is part of DarkFi (https://dark.fi) + * + * Copyright (C) 2020-2026 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 . + */ + +#![allow(unused_imports, unused_variables, dead_code)] + +use crate::{ + app::{ + node::{create_chatview, create_layer, create_text, create_vector_art, create_video}, + App, + }, + expr::{self, Compiler}, + mesh::COLOR_PURPLE, + prop::{PropertyAtomicGuard, PropertyFloat32, Role}, + scene::SceneNodePtr, + ui::{ChatView, Layer, Text, VectorArt, VectorShape, Video}, + util::i18n::I18nBabelFish, +}; + +#[allow(dead_code)] +pub async fn make(app: &App, window: SceneNodePtr, i18n_fish: &I18nBabelFish) { + let atom = &mut PropertyAtomicGuard::none(); + + // Create a layer called view + let layer_node = create_layer("view"); + let prop = layer_node.get_property("rect").unwrap(); + prop.set_f32(atom, Role::App, 0, 0.).unwrap(); + prop.set_f32(atom, Role::App, 1, 0.).unwrap(); + prop.set_expr(atom, Role::App, 2, expr::load_var("w")).unwrap(); + prop.set_expr(atom, Role::App, 3, expr::load_var("h")).unwrap(); + layer_node.set_property_bool(atom, Role::App, "is_visible", true).unwrap(); + let layer_node = layer_node.setup(|me| Layer::new(me, app.renderer.clone())).await; + window.link(layer_node.clone()); + + // Create a bg mesh + let node = create_vector_art("bg"); + let prop = node.get_property("rect").unwrap(); + prop.set_f32(atom, Role::App, 0, 0.).unwrap(); + prop.set_f32(atom, Role::App, 1, 0.).unwrap(); + prop.set_expr(atom, Role::App, 2, expr::load_var("w")).unwrap(); + prop.set_expr(atom, Role::App, 3, expr::load_var("h")).unwrap(); + node.set_property_u32(atom, Role::App, "z_index", 0).unwrap(); + + let mut shape = VectorShape::new(); + shape.add_filled_box( + expr::const_f32(0.), + expr::const_f32(0.), + expr::load_var("w"), + expr::load_var("h"), + [0., 0., 0., 1.], + ); + shape.add_outline( + expr::const_f32(200.), + expr::const_f32(200.), + expr::const_f32(1000.), + expr::const_f32(1000.), + 1., + COLOR_PURPLE, + ); + let node = node.setup(|me| VectorArt::new(me, shape, app.renderer.clone())).await; + layer_node.link(node); +} diff --git a/bin/app/src/scene.rs b/bin/app/src/scene.rs index c0589ac34..857e95757 100644 --- a/bin/app/src/scene.rs +++ b/bin/app/src/scene.rs @@ -568,6 +568,7 @@ pub enum Pimpl { Null, Window(ui::WindowPtr), Layer(ui::LayerPtr), + ScrollLayer(ui::ScrollLayerPtr), VectorArt(ui::VectorArtPtr), Text(ui::TextPtr), Edit(ui::BaseEditPtr), diff --git a/bin/app/src/ui/mod.rs b/bin/app/src/ui/mod.rs index 0ef5b21ec..177e4e1e7 100644 --- a/bin/app/src/ui/mod.rs +++ b/bin/app/src/ui/mod.rs @@ -52,6 +52,8 @@ pub use vector_art::{ }; mod layer; pub use layer::{Layer, LayerPtr}; +mod scroll_layer; +pub use scroll_layer::{ScrollLayer, ScrollLayerPtr}; mod shortcut; pub use shortcut::{Shortcut, ShortcutPtr}; mod menu; @@ -209,6 +211,7 @@ impl OnModify { pub fn get_ui_object_ptr(node: &SceneNode3) -> Arc { match node.pimpl() { Pimpl::Layer(obj) => obj.clone(), + Pimpl::ScrollLayer(obj) => obj.clone(), Pimpl::VectorArt(obj) => obj.clone(), Pimpl::Text(obj) => obj.clone(), Pimpl::Edit(obj) => obj.clone(), @@ -226,6 +229,7 @@ pub fn get_ui_object_ptr(node: &SceneNode3) -> Arc { pub fn get_ui_object3<'a>(node: &'a SceneNode3) -> &'a dyn UIObject { match node.pimpl() { Pimpl::Layer(obj) => obj.as_ref(), + Pimpl::ScrollLayer(obj) => obj.as_ref(), Pimpl::VectorArt(obj) => obj.as_ref(), Pimpl::Text(obj) => obj.as_ref(), Pimpl::Edit(obj) => obj.as_ref(), diff --git a/bin/app/src/ui/scroll_layer.rs b/bin/app/src/ui/scroll_layer.rs new file mode 100644 index 000000000..c757b1f44 --- /dev/null +++ b/bin/app/src/ui/scroll_layer.rs @@ -0,0 +1,128 @@ +/* This file is part of DarkFi (https://dark.fi) + * + * Copyright (C) 2020-2026 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 async_trait::async_trait; +use miniquad::{KeyCode, KeyMods, MouseButton, TouchPhase}; +use std::sync::Arc; + +use crate::{ + gfx::{DrawCall, Point, Rectangle, RendererSync}, + prop::{BatchGuardPtr, PropertyAtomicGuard}, + scene::{Pimpl, SceneNodeWeak}, + util::i18n::I18nBabelFish, + ExecutorPtr, +}; + +use super::{DrawUpdate, Layer, LayerPtr, UIObject}; + +pub type ScrollLayerPtr = Arc; + +pub struct ScrollLayer { + inner: LayerPtr, +} + +impl ScrollLayer { + pub async fn new(node: SceneNodeWeak, renderer: crate::gfx::Renderer) -> Pimpl { + let layer = Layer::new(node.clone(), renderer).await; + let inner = match layer { + Pimpl::Layer(l) => l, + _ => unreachable!(), + }; + + Pimpl::ScrollLayer(Arc::new(Self { inner })) + } +} + +#[async_trait] +impl UIObject for ScrollLayer { + fn priority(&self) -> u32 { + self.inner.priority() + } + + fn init(&self) { + self.inner.init(); + } + + async fn start(self: Arc, ex: ExecutorPtr) { + self.inner.clone().start(ex).await; + } + + fn stop(&self) { + self.inner.stop(); + } + + async fn draw( + &self, + parent_rect: Rectangle, + atom: &mut PropertyAtomicGuard, + ) -> Option { + self.inner.draw(parent_rect, atom).await + } + + async fn handle_char(&self, key: char, mods: KeyMods, repeat: bool) -> bool { + self.inner.handle_char(key, mods, repeat).await + } + + async fn handle_key_down(&self, key: KeyCode, mods: KeyMods, repeat: bool) -> bool { + self.inner.handle_key_down(key, mods, repeat).await + } + + async fn handle_key_up(&self, key: KeyCode, mods: KeyMods) -> bool { + self.inner.handle_key_up(key, mods).await + } + + async fn handle_mouse_btn_down(&self, btn: MouseButton, mouse_pos: Point) -> bool { + self.inner.handle_mouse_btn_down(btn, mouse_pos).await + } + + async fn handle_mouse_btn_up(&self, btn: MouseButton, mouse_pos: Point) -> bool { + self.inner.handle_mouse_btn_up(btn, mouse_pos).await + } + + async fn handle_mouse_move(&self, mouse_pos: Point) -> bool { + self.inner.handle_mouse_move(mouse_pos).await + } + + async fn handle_mouse_wheel(&self, wheel_pos: Point) -> bool { + self.inner.handle_mouse_wheel(wheel_pos).await + } + + async fn handle_touch(&self, phase: TouchPhase, id: u64, touch_pos: Point) -> bool { + self.inner.handle_touch(phase, id, touch_pos).await + } + + fn handle_touch_sync( + &self, + renderer: &RendererSync, + phase: TouchPhase, + id: u64, + touch_pos: Point, + ) -> bool { + self.inner.handle_touch_sync(renderer, phase, id, touch_pos) + } + + fn set_i18n(&self, i18n_fish: &I18nBabelFish) { + self.inner.set_i18n(i18n_fish); + } +} + +impl std::fmt::Debug for ScrollLayer { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + self.inner.fmt(f) + } +}