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

wallet: editbox clipping rect when regenerating mesh

darkfi 2 лет назад
Родитель
Сommit
750935e156
3 измененных файлов с 91 добавлено и 51 удалено
  1. 34 0
      bin/darkwallet/src/gfx2.rs
  2. 13 1
      bin/darkwallet/src/mesh.rs
  3. 44 50
      bin/darkwallet/src/ui/editbox.rs

+ 34 - 0
bin/darkwallet/src/gfx2.rs

@@ -31,6 +31,15 @@ pub struct Vertex {
     pub uv: [f32; 2],
     pub uv: [f32; 2],
 }
 }
 
 
+impl Vertex {
+    pub fn pos(&self) -> Point {
+        self.pos.into()
+    }
+    pub fn set_pos(&mut self, pos: &Point) {
+        self.pos = pos.as_arr();
+    }
+}
+
 pub struct Point {
 pub struct Point {
     pub x: f32,
     pub x: f32,
     pub y: f32,
     pub y: f32,
@@ -41,6 +50,10 @@ impl Point {
         (self.x, self.y)
         (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 {
     pub fn offset(&self, off_x: f32, off_y: f32) -> Self {
         Self { x: self.x + off_x, y: self.y + off_y }
         Self { x: self.x + off_x, y: self.y + off_y }
     }
     }
@@ -50,6 +63,12 @@ impl Point {
     }
     }
 }
 }
 
 
+impl From<[f32; 2]> for Point {
+    fn from(pos: [f32; 2]) -> Self {
+        Self { x: pos[0], y: pos[1] }
+    }
+}
+
 #[derive(Debug, Clone)]
 #[derive(Debug, Clone)]
 pub struct Rectangle {
 pub struct Rectangle {
     pub x: f32,
     pub x: f32,
@@ -98,6 +117,21 @@ impl Rectangle {
         Some(clipped)
         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 {
     pub fn contains(&self, point: &Point) -> bool {
         self.x <= point.x &&
         self.x <= point.x &&
             point.x <= self.x + self.w &&
             point.x <= self.x + self.w &&

+ 13 - 1
bin/darkwallet/src/mesh.rs

@@ -22,14 +22,26 @@ pub struct MeshInfo {
 pub struct MeshBuilder {
 pub struct MeshBuilder {
     verts: Vec<Vertex>,
     verts: Vec<Vertex>,
     indices: Vec<u16>,
     indices: Vec<u16>,
+    clipper: Option<Rectangle>,
 }
 }
 
 
 impl MeshBuilder {
 impl MeshBuilder {
     pub fn new() -> Self {
     pub fn new() -> Self {
-        Self { verts: vec![], indices: vec![] }
+        Self { verts: vec![], indices: vec![], clipper: None }
+    }
+    pub fn with_clip(clipper: Rectangle) -> Self {
+        Self { verts: vec![], indices: vec![], clipper: Some(clipper) }
     }
     }
 
 
     pub fn append(&mut self, mut verts: Vec<Vertex>, indices: Vec<u16>) {
     pub fn append(&mut self, mut verts: Vec<Vertex>, indices: Vec<u16>) {
+        if let Some(clipper) = &self.clipper {
+            for vert in &mut verts {
+                let mut vpos = vert.pos();
+                clipper.clip_point(&mut vpos);
+                vert.set_pos(&vpos);
+            }
+        }
+
         let mut indices = indices.into_iter().map(|i| i + self.verts.len() as u16).collect();
         let mut indices = indices.into_iter().map(|i| i + self.verts.len() as u16).collect();
         self.verts.append(&mut verts);
         self.verts.append(&mut verts);
         self.indices.append(&mut indices);
         self.indices.append(&mut indices);

+ 44 - 50
bin/darkwallet/src/ui/editbox.rs

@@ -103,7 +103,6 @@ impl RepeatingKeyTimer {
 
 
 #[derive(Clone)]
 #[derive(Clone)]
 struct TextRenderInfo {
 struct TextRenderInfo {
-    glyphs: Vec<Glyph>,
     mesh: MeshInfo,
     mesh: MeshInfo,
     texture_id: TextureId,
     texture_id: TextureId,
 }
 }
@@ -120,7 +119,8 @@ pub struct EditBox {
     text_shaper: TextShaperPtr,
     text_shaper: TextShaperPtr,
     key_repeat: SyncMutex<PressedKeysSmoothRepeat>,
     key_repeat: SyncMutex<PressedKeysSmoothRepeat>,
 
 
-    render_info: SyncMutex<TextRenderInfo>,
+    render_info: SyncMutex<Option<TextRenderInfo>>,
+    glyphs: SyncMutex<Vec<Glyph>>,
     dc_key: u64,
     dc_key: u64,
 
 
     is_active: PropertyBool,
     is_active: PropertyBool,
@@ -164,20 +164,11 @@ impl EditBox {
         let debug = PropertyBool::wrap(node, "debug", 0).unwrap();
         let debug = PropertyBool::wrap(node, "debug", 0).unwrap();
         drop(scene_graph);
         drop(scene_graph);
 
 
-        let render_info = Self::regen_mesh(
-            &render_api,
-            &text_shaper,
-            text.get(),
-            font_size.get(),
-            text_color.get(),
-            baseline.get(),
-            debug.get(),
-        )
-        .await;
-
         // testing
         // testing
         window::show_keyboard(true);
         window::show_keyboard(true);
 
 
+        let glyphs = text_shaper.shape(text.get(), font_size.get()).await;
+
         let self_ = Arc::new_cyclic(|me: &Weak<Self>| {
         let self_ = Arc::new_cyclic(|me: &Weak<Self>| {
             // Start a task monitoring for key down events
             // Start a task monitoring for key down events
             let ev_sub = event_pub.subscribe_char();
             let ev_sub = event_pub.subscribe_char();
@@ -230,7 +221,8 @@ impl EditBox {
                 text_shaper,
                 text_shaper,
                 key_repeat: SyncMutex::new(PressedKeysSmoothRepeat::new(400, 50)),
                 key_repeat: SyncMutex::new(PressedKeysSmoothRepeat::new(400, 50)),
 
 
-                render_info: SyncMutex::new(render_info),
+                render_info: SyncMutex::new(None),
+                glyphs: SyncMutex::new(glyphs),
                 dc_key: OsRng.gen(),
                 dc_key: OsRng.gen(),
 
 
                 is_active,
                 is_active,
@@ -254,18 +246,16 @@ impl EditBox {
 
 
     /// Called whenever the text or any text property changes.
     /// Called whenever the text or any text property changes.
     /// Not related to cursor, text highlighting or bounding (clip) rects.
     /// Not related to cursor, text highlighting or bounding (clip) rects.
-    async fn regen_mesh(
-        render_api: &RenderApi,
-        text_shaper: &TextShaper,
-        text: String,
-        font_size: f32,
-        text_color: Color,
-        baseline: f32,
-        debug: bool,
-    ) -> TextRenderInfo {
+    async fn regen_mesh(&self, clip: &Rectangle) -> TextRenderInfo {
+        let text = self.text.get();
+        let font_size = self.font_size.get();
+        let text_color = self.text_color.get();
+        let baseline = self.baseline.get();
+        let debug = self.debug.get();
         debug!(target: "ui::editbox", "Rendering text '{}'", text);
         debug!(target: "ui::editbox", "Rendering text '{}'", text);
-        let glyphs = text_shaper.shape(text, font_size).await;
-        let atlas = text2::make_texture_atlas(render_api, font_size, &glyphs).await.unwrap();
+
+        let glyphs = self.glyphs.lock().unwrap().clone();
+        let atlas = text2::make_texture_atlas(&self.render_api, font_size, &glyphs).await.unwrap();
 
 
         let mut mesh = MeshBuilder::new();
         let mut mesh = MeshBuilder::new();
         let mut glyph_pos_iter = GlyphPositionIter::new(font_size, &glyphs, baseline);
         let mut glyph_pos_iter = GlyphPositionIter::new(font_size, &glyphs, baseline);
@@ -280,9 +270,9 @@ impl EditBox {
             mesh.draw_box(&glyph_rect, color, &uv_rect);
             mesh.draw_box(&glyph_rect, color, &uv_rect);
         }
         }
 
 
-        let mesh = mesh.alloc(&render_api).await.unwrap();
+        let mesh = mesh.alloc(&self.render_api).await.unwrap();
 
 
-        TextRenderInfo { glyphs, mesh, texture_id: atlas.texture_id }
+        TextRenderInfo { mesh, texture_id: atlas.texture_id }
     }
     }
 
 
     async fn do_key_action(&self, key: char, mods: &KeyMods) {
     async fn do_key_action(&self, key: char, mods: &KeyMods) {
@@ -351,7 +341,7 @@ impl EditBox {
 
 
         let cursor_pos = self.cursor_pos.get();
         let cursor_pos = self.cursor_pos.get();
 
 
-        let glyphs = self.render_info.lock().unwrap().glyphs.clone();
+        let glyphs = self.glyphs.lock().unwrap().clone();
 
 
         // We rebuild the string but insert our substr at cursor_pos.
         // We rebuild the string but insert our substr at cursor_pos.
         // The substr is inserted before cursor_pos, and appending to the end
         // The substr is inserted before cursor_pos, and appending to the end
@@ -407,17 +397,11 @@ impl EditBox {
     async fn redraw(&self) {
     async fn redraw(&self) {
         let old = self.render_info.lock().unwrap().clone();
         let old = self.render_info.lock().unwrap().clone();
 
 
-        let render_info = Self::regen_mesh(
-            &self.render_api,
-            &self.text_shaper,
-            self.text.get(),
-            self.font_size.get(),
-            self.text_color.get(),
-            self.baseline.get(),
-            self.debug.get(),
-        )
-        .await;
-        *self.render_info.lock().unwrap() = render_info;
+        let glyphs = self.text_shaper.shape(self.text.get(), self.font_size.get()).await;
+        *self.glyphs.lock().unwrap() = glyphs;
+
+        // draw will recalc this when it's None
+        *self.render_info.lock().unwrap() = None;
 
 
         let sg = self.sg.lock().await;
         let sg = self.sg.lock().await;
         let node = sg.get_node(self.node_id).unwrap();
         let node = sg.get_node(self.node_id).unwrap();
@@ -434,9 +418,11 @@ impl EditBox {
         debug!(target: "ui::editbox", "replace draw calls done");
         debug!(target: "ui::editbox", "replace draw calls done");
 
 
         // We're finished with these so clean up.
         // We're finished with these so clean up.
-        self.render_api.delete_buffer(old.mesh.vertex_buffer);
-        self.render_api.delete_buffer(old.mesh.index_buffer);
-        self.render_api.delete_texture(old.texture_id);
+        if let Some(old) = old {
+            self.render_api.delete_buffer(old.mesh.vertex_buffer);
+            self.render_api.delete_buffer(old.mesh.index_buffer);
+            self.render_api.delete_texture(old.texture_id);
+        }
     }
     }
 
 
     pub async fn draw(&self, sg: &SceneGraph, parent_rect: &Rectangle) -> Option<DrawUpdate> {
     pub async fn draw(&self, sg: &SceneGraph, parent_rect: &Rectangle) -> Option<DrawUpdate> {
@@ -444,7 +430,23 @@ impl EditBox {
         // Only used for debug messages
         // Only used for debug messages
         let node = sg.get_node(self.node_id).unwrap();
         let node = sg.get_node(self.node_id).unwrap();
 
 
+        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);
+        };
+
         let render_info = self.render_info.lock().unwrap().clone();
         let render_info = self.render_info.lock().unwrap().clone();
+        let render_info = match render_info {
+            Some(render_info) => render_info,
+            None => {
+                let render_info = self.regen_mesh(&rect).await;
+                *self.render_info.lock().unwrap() = Some(render_info.clone());
+                render_info
+            }
+        };
 
 
         let mesh = DrawMesh {
         let mesh = DrawMesh {
             vertex_buffer: render_info.mesh.vertex_buffer,
             vertex_buffer: render_info.mesh.vertex_buffer,
@@ -453,14 +455,6 @@ impl EditBox {
             num_elements: render_info.mesh.num_elements,
             num_elements: render_info.mesh.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.x += parent_rect.x;
         rect.y += parent_rect.x;
         rect.y += parent_rect.x;