Просмотр исходного кода

wallet: UI Text properties can be edited realtime

darkfi 2 лет назад
Родитель
Сommit
1ff57a6ecf

+ 5 - 3
bin/darkwallet/src/gfx2.rs

@@ -413,9 +413,11 @@ impl Stage {
         sendr: async_channel::Sender<TextureId>,
     ) {
         let texture = self.ctx.new_texture_from_rgba8(width, height, &data);
-        debug!(target: "gfx2", "Invoked method: new_texture({}, {}, ...) -> {:?}\n{}",
-               width, height, texture,
-               ansi_texture(width as usize, height as usize, &data));
+        debug!(target: "gfx2", "Invoked method: new_texture({}, {}, ...) -> {:?}",
+               width, height, texture);
+        //debug!(target: "gfx2", "Invoked method: new_texture({}, {}, ...) -> {:?}\n{}",
+        //       width, height, texture,
+        //       ansi_texture(width as usize, height as usize, &data));
         sendr.try_send(texture).unwrap();
     }
     fn method_delete_texture(&mut self, texture: TextureId) {

+ 4 - 3
bin/darkwallet/src/main.rs

@@ -37,20 +37,21 @@ mod util;
 
 use crate::{net::ZeroMQAdapter, scene::SceneGraph, text2::TextShaper};
 
-#[cfg(target_os = "android")]
 fn panic_hook(panic_info: &std::panic::PanicInfo) {
     error!("panic occurred: {panic_info}");
     //error!("panic: {}", std::backtrace::Backtrace::force_capture().to_string());
+    std::process::exit(1);
 }
 
 fn main() {
+    // Exit the application on panic right away
+    std::panic::set_hook(Box::new(panic_hook));
+
     #[cfg(target_os = "android")]
     {
         android_logger::init_once(
             android_logger::Config::default().with_max_level(LevelFilter::Debug).with_tag("darkfi"),
         );
-
-        std::panic::set_hook(Box::new(panic_hook));
     }
 
     #[cfg(target_os = "linux")]

+ 10 - 7
bin/darkwallet/src/mesh.rs

@@ -12,6 +12,13 @@ pub const COLOR_GREEN: Color = [0., 1., 0., 1.];
 pub const COLOR_BLUE: Color = [0., 0., 1., 1.];
 pub const COLOR_WHITE: Color = [1., 1., 1., 1.];
 
+#[derive(Clone)]
+pub struct MeshInfo {
+    pub vertex_buffer: BufferId,
+    pub index_buffer: BufferId,
+    pub num_elements: i32,
+}
+
 pub struct MeshBuilder {
     verts: Vec<Vertex>,
     indices: Vec<u16>,
@@ -67,18 +74,14 @@ impl MeshBuilder {
         self.draw_box(&Rectangle::new(x1, y2 - thickness, dist_x, thickness), color, &uv);
     }
 
-    // Needed by OpenGL
-    pub fn num_elements(&self) -> i32 {
-        self.indices.len() as i32
-    }
-
-    pub async fn alloc(self, render_api: &RenderApi) -> Result<(BufferId, BufferId)> {
+    pub async fn alloc(self, render_api: &RenderApi) -> Result<MeshInfo> {
         //debug!(target: "mesh", "allocating {} verts:", self.verts.len());
         //for vert in &self.verts {
         //    debug!(target: "mesh", "  {:?}", vert);
         //}
+        let num_elements = self.indices.len() as i32;
         let vertex_buffer = render_api.new_vertex_buffer(self.verts).await?;
         let index_buffer = render_api.new_index_buffer(self.indices).await?;
-        Ok((vertex_buffer, index_buffer))
+        Ok(MeshInfo { vertex_buffer, index_buffer, num_elements })
     }
 }

+ 25 - 5
bin/darkwallet/src/prop/wrap.rs

@@ -7,7 +7,7 @@ use crate::{
 };
 
 pub struct PropertyBool {
-    prop: Arc<Property>,
+    prop: PropertyPtr,
     idx: usize,
 }
 
@@ -28,10 +28,14 @@ impl PropertyBool {
     pub fn set(&self, val: bool) {
         self.prop.set_bool(self.idx, val).unwrap()
     }
+
+    pub fn prop(&self) -> PropertyPtr {
+        self.prop.clone()
+    }
 }
 
 pub struct PropertyUint32 {
-    prop: Arc<Property>,
+    prop: PropertyPtr,
     idx: usize,
 }
 
@@ -59,10 +63,14 @@ impl PropertyUint32 {
     pub fn set(&self, val: u32) {
         self.prop.set_u32(self.idx, val).unwrap()
     }
+
+    pub fn prop(&self) -> PropertyPtr {
+        self.prop.clone()
+    }
 }
 
 pub struct PropertyFloat32 {
-    prop: Arc<Property>,
+    prop: PropertyPtr,
     idx: usize,
 }
 
@@ -83,10 +91,14 @@ impl PropertyFloat32 {
     pub fn set(&self, val: f32) {
         self.prop.set_f32(self.idx, val).unwrap()
     }
+
+    pub fn prop(&self) -> PropertyPtr {
+        self.prop.clone()
+    }
 }
 
 pub struct PropertyStr {
-    prop: Arc<Property>,
+    prop: PropertyPtr,
     idx: usize,
 }
 
@@ -107,10 +119,14 @@ impl PropertyStr {
     pub fn set<S: Into<String>>(&self, val: S) {
         self.prop.set_str(self.idx, val.into()).unwrap()
     }
+
+    pub fn prop(&self) -> PropertyPtr {
+        self.prop.clone()
+    }
 }
 
 pub struct PropertyColor {
-    prop: Arc<Property>,
+    prop: PropertyPtr,
 }
 
 impl PropertyColor {
@@ -142,4 +158,8 @@ impl PropertyColor {
         self.prop.set_f32(2, val[2]).unwrap();
         self.prop.set_f32(3, val[3]).unwrap();
     }
+
+    pub fn prop(&self) -> PropertyPtr {
+        self.prop.clone()
+    }
 }

+ 7 - 3
bin/darkwallet/src/text2.rs

@@ -16,7 +16,7 @@ use std::{
 
 use crate::{
     error::Result,
-    gfx2::{Rectangle, RenderApiPtr},
+    gfx2::{Rectangle, RenderApi, RenderApiPtr},
     util::ansi_texture,
 };
 
@@ -53,7 +53,7 @@ pub struct RenderedAtlas {
 const ATLAS_GAP: usize = 2;
 
 pub async fn make_texture_atlas(
-    render_api: RenderApiPtr,
+    render_api: &RenderApi,
     font_size: f32,
     glyphs: &Vec<Glyph>,
 ) -> Result<RenderedAtlas> {
@@ -337,7 +337,9 @@ impl TextShaper {
             let mut prev_cluster = 0;
 
             //for (i, (position, info)) in positions.iter().zip(infos).enumerate() {
-            for (i, (position, info)) in glyph_pos_iter.iter().zip(glyph_infos_iter.iter()).enumerate() {
+            for (i, (position, info)) in
+                glyph_pos_iter.iter().zip(glyph_infos_iter.iter()).enumerate()
+            {
                 let glyph_id = info.codepoint as u32;
                 // Index within this substr
                 let curr_cluster = info.cluster as usize;
@@ -450,6 +452,7 @@ impl TextShaper {
                     bearing_x,
                     bearing_y,
                     has_fixed_sizes,
+                    has_color: face.has_color(),
                 });
 
                 cache.insert(cache_key, Arc::downgrade(&sprite));
@@ -510,6 +513,7 @@ pub struct Sprite {
     pub bearing_x: f32,
     pub bearing_y: f32,
     pub has_fixed_sizes: bool,
+    pub has_color: bool,
 }
 
 pub struct Glyph {

+ 97 - 70
bin/darkwallet/src/ui/text.rs

@@ -1,37 +1,46 @@
-use async_lock::Mutex;
+//use async_lock::Mutex;
 use miniquad::{BufferId, TextureId};
 use rand::{rngs::OsRng, Rng};
-use std::sync::{Arc, Weak};
+use std::sync::{Arc, Mutex, Weak};
 
 use crate::{
-    gfx2::{DrawCall, DrawInstruction, DrawMesh, Rectangle, RenderApiPtr, Vertex},
-    mesh::{MeshBuilder, COLOR_BLUE, COLOR_WHITE},
-    prop::{PropertyPtr, PropertyUint32},
+    gfx2::{DrawCall, DrawInstruction, DrawMesh, Rectangle, RenderApi, RenderApiPtr, Vertex},
+    mesh::{Color, MeshBuilder, MeshInfo, COLOR_BLUE, COLOR_WHITE},
+    prop::{
+        PropertyBool, PropertyColor, PropertyFloat32, PropertyPtr, PropertyStr, PropertyUint32,
+    },
     scene::{Pimpl, SceneGraph, SceneGraphPtr2, SceneNodeId},
-    text2::{self, Glyph, GlyphPositionIter, RenderedAtlas, SpritePtr, TextShaperPtr},
+    text2::{self, Glyph, GlyphPositionIter, RenderedAtlas, SpritePtr, TextShaper, TextShaperPtr},
 };
 
 use super::{eval_rect, get_parent_rect, read_rect, DrawUpdate, OnModify, Stoppable};
 
 pub type TextPtr = Arc<Text>;
 
+#[derive(Clone)]
+struct TextRenderInfo {
+    glyph_sprites: Vec<SpritePtr>,
+    mesh: MeshInfo,
+    texture_id: TextureId,
+}
+
 pub struct Text {
     sg: SceneGraphPtr2,
     render_api: RenderApiPtr,
     text_shaper: TextShaperPtr,
     tasks: Vec<smol::Task<()>>,
 
-    glyph_sprites: Mutex<Vec<SpritePtr>>,
-
-    texture_id: TextureId,
-    vertex_buffer: BufferId,
-    index_buffer: BufferId,
-    num_elements: i32,
+    render_info: Mutex<TextRenderInfo>,
     dc_key: u64,
 
     node_id: SceneNodeId,
     rect: PropertyPtr,
     z_index: PropertyUint32,
+    text: PropertyStr,
+    font_size: PropertyFloat32,
+    color: PropertyColor,
+    baseline: PropertyFloat32,
+    debug: PropertyBool,
 }
 
 impl Text {
@@ -46,83 +55,99 @@ impl Text {
         let node = scene_graph.get_node(node_id).unwrap();
         let node_name = node.name.clone();
         let rect = node.get_property("rect").expect("Text::rect");
-        let z_index_prop = node.get_property("z_index").expect("Text::z_index");
-        let z_index = PropertyUint32::from(z_index_prop.clone(), 0).unwrap();
-        let text = node.get_property("text").expect("Text::text");
-        let font_size = node.get_property("font_size").expect("Text::font_size");
-        let color = node.get_property("color").expect("Text::color");
-        let debug = node.get_property("debug").expect("Text::debug");
-        let baseline = node.get_property("baseline").expect("Text::baseline");
+        let z_index = PropertyUint32::wrap(node, "z_index", 0).unwrap();
+        let text = PropertyStr::wrap(node, "text", 0).unwrap();
+        let font_size = PropertyFloat32::wrap(node, "font_size", 0).unwrap();
+        let color = PropertyColor::wrap(node, "color").unwrap();
+        let debug = PropertyBool::wrap(node, "debug", 0).unwrap();
+        let baseline = PropertyFloat32::wrap(node, "baseline", 0).unwrap();
         drop(scene_graph);
 
-        let text_str = text.get_str(0).unwrap();
-        let font_size_val = font_size.get_f32(0).unwrap();
-        debug!(target: "ui::text", "Rendering label '{}'", text_str);
-        let glyphs = text_shaper.shape(text_str, font_size_val).await;
-        let atlas =
-            text2::make_texture_atlas(render_api.clone(), font_size_val, &glyphs).await.unwrap();
-
-        let (x1, y1) = (0., 0.);
-        let (x2, y2) = (1., 1.);
-        let verts = 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];
-        assert_eq!(atlas.uv_rects.len(), glyphs.len());
-
-        let baseline_y = baseline.get_f32(0).unwrap();
-
-        let mut mesh = MeshBuilder::new();
-        let mut glyph_pos_iter = GlyphPositionIter::new(font_size_val, &glyphs, baseline_y);
-        for (uv_rect, glyph_rect) in atlas.uv_rects.into_iter().zip(glyph_pos_iter) {
-            //mesh.draw_outline(&glyph_rect, COLOR_BLUE, 2.);
-            mesh.draw_box(&glyph_rect, COLOR_WHITE, &uv_rect);
-        }
-
-        let num_elements = mesh.num_elements();
-        let (vertex_buffer, index_buffer) = mesh.alloc(&render_api).await.unwrap();
-
-        let sprites = glyphs.into_iter().map(|glyph| glyph.sprite).collect();
+        let render_info = Self::regen_mesh(
+            &render_api,
+            &text_shaper,
+            text.get(),
+            font_size.get(),
+            color.get(),
+            baseline.get(),
+        )
+        .await;
 
         let self_ = Arc::new_cyclic(|me: &Weak<Self>| {
             let mut on_modify = OnModify::new(ex, node_name, node_id, me.clone());
             on_modify.when_change(rect.clone(), Self::redraw);
-            on_modify.when_change(z_index_prop, Self::redraw);
-            on_modify.when_change(text, Self::redraw);
-            on_modify.when_change(font_size, Self::redraw);
-            on_modify.when_change(color, Self::redraw);
-            on_modify.when_change(debug, Self::redraw);
-            on_modify.when_change(baseline, Self::redraw);
+            on_modify.when_change(z_index.prop(), Self::redraw);
+            on_modify.when_change(text.prop(), Self::redraw);
+            on_modify.when_change(font_size.prop(), Self::redraw);
+            on_modify.when_change(color.prop(), Self::redraw);
+            on_modify.when_change(debug.prop(), Self::redraw);
+            on_modify.when_change(baseline.prop(), Self::redraw);
 
             Self {
                 sg,
                 render_api,
                 text_shaper,
                 tasks: on_modify.tasks,
-                //glyphs: Mutex::new((glyphs, atlas)),
-                glyph_sprites: Mutex::new(sprites),
-                texture_id: atlas.texture_id,
-                vertex_buffer,
-                index_buffer,
-                num_elements,
+                render_info: Mutex::new(render_info),
                 dc_key: OsRng.gen(),
                 node_id,
                 rect,
                 z_index,
+                text,
+                font_size,
+                color,
+                baseline,
+                debug,
             }
         });
 
         Pimpl::Text(self_)
     }
 
+    async fn regen_mesh(
+        render_api: &RenderApi,
+        text_shaper: &TextShaper,
+        text: String,
+        font_size: f32,
+        text_color: Color,
+        baseline: f32,
+    ) -> TextRenderInfo {
+        debug!(target: "ui::text", "Rendering label '{}'", text);
+        let glyphs = text_shaper.shape(text, font_size).await;
+        let atlas = text2::make_texture_atlas(render_api, font_size, &glyphs).await.unwrap();
+
+        let mut mesh = MeshBuilder::new();
+        let mut glyph_pos_iter = GlyphPositionIter::new(font_size, &glyphs, baseline);
+        for ((uv_rect, glyph_rect), glyph) in
+            atlas.uv_rects.into_iter().zip(glyph_pos_iter).zip(glyphs.iter())
+        {
+            //mesh.draw_outline(&glyph_rect, COLOR_BLUE, 2.);
+            let mut color = text_color.clone();
+            if glyph.sprite.has_color {
+                color = COLOR_WHITE;
+            }
+            mesh.draw_box(&glyph_rect, color, &uv_rect);
+        }
+
+        let mesh = mesh.alloc(&render_api).await.unwrap();
+
+        let glyph_sprites = glyphs.into_iter().map(|glyph| glyph.sprite).collect();
+
+        TextRenderInfo { glyph_sprites, mesh, texture_id: atlas.texture_id }
+    }
+
     async fn redraw(self: Arc<Self>) {
+        let render_info = Self::regen_mesh(
+            &self.render_api,
+            &self.text_shaper,
+            self.text.get(),
+            self.font_size.get(),
+            self.color.get(),
+            self.baseline.get(),
+        )
+        .await;
+        *self.render_info.lock().unwrap() = render_info;
+
         let sg = self.sg.lock().await;
         let node = sg.get_node(self.node_id).unwrap();
 
@@ -143,11 +168,13 @@ impl Text {
         // Only used for debug messages
         let node = sg.get_node(self.node_id).unwrap();
 
+        let render_info = self.render_info.lock().unwrap().clone();
+
         let mesh = DrawMesh {
-            vertex_buffer: self.vertex_buffer,
-            index_buffer: self.index_buffer,
-            texture: Some(self.texture_id),
-            num_elements: self.num_elements,
+            vertex_buffer: render_info.mesh.vertex_buffer,
+            index_buffer: render_info.mesh.index_buffer,
+            texture: Some(render_info.texture_id),
+            num_elements: render_info.mesh.num_elements,
         };
 
         if let Err(err) = eval_rect(self.rect.clone(), parent_rect) {