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

editbox: make cursor a separate drawcall

darkfi 1 год назад
Родитель
Сommit
9812ea9641

+ 1 - 1
bin/darkwallet/src/app/mod.rs

@@ -169,7 +169,7 @@ impl App {
             })
             .await;
         self.sg_root.link(window.clone());
-        schema::make(&self, window).await;
+        schema::make_test(&self, window).await;
 
         debug!(target: "app", "Schema loaded");
 

+ 0 - 45
bin/darkwallet/src/gfx/mod.rs

@@ -147,8 +147,6 @@ pub enum GfxDrawInstruction {
     SetScale(f32),
     Move(Point),
     ApplyView(Rectangle),
-    ApplyViewport(Rectangle),
-    ApplyMatrix(glam::Mat4),
     Draw(GfxDrawMesh),
 }
 
@@ -162,8 +160,6 @@ impl GfxDrawInstruction {
             Self::SetScale(scale) => DrawInstruction::SetScale(scale),
             Self::Move(off) => DrawInstruction::Move(off),
             Self::ApplyView(view) => DrawInstruction::ApplyView(view),
-            Self::ApplyViewport(rect) => DrawInstruction::ApplyViewport(rect),
-            Self::ApplyMatrix(mat) => DrawInstruction::ApplyMatrix(mat),
             Self::Draw(mesh) => DrawInstruction::Draw(mesh.compile(textures, buffers)),
         }
     }
@@ -203,8 +199,6 @@ enum DrawInstruction {
     SetScale(f32),
     Move(Point),
     ApplyView(Rectangle),
-    ApplyViewport(Rectangle),
-    ApplyMatrix(glam::Mat4),
     Draw(DrawMesh),
 }
 
@@ -274,8 +268,6 @@ impl<'a> RenderContext<'a> {
     fn draw_call(&mut self, draw_call: &DrawCall, indent: u32) {
         let ws = if DEBUG_RENDER { " ".repeat(indent as usize * 4) } else { String::new() };
 
-        //// This is buggy since it does not reset back to parent
-        //let mut prev_view = None;
         let old_view = self.view;
         let old_cursor = self.cursor;
 
@@ -307,33 +299,6 @@ impl<'a> RenderContext<'a> {
                     }
                     self.apply_view();
                 }
-                DrawInstruction::ApplyViewport(view) => {
-                    /*
-                    if DEBUG_RENDER {
-                        debug!(target: "gfx", "{}apply_viewport({:?})", ws, view);
-                    }
-                    prev_view = Some(view.clone());
-                    self.apply_view(view);
-                    */
-                }
-                DrawInstruction::ApplyMatrix(model) => {
-                    /*
-                    if DEBUG_RENDER {
-                        debug!(target: "gfx", "{}apply_matrix(", ws);
-                        debug!(target: "gfx", "{}    {:?}", ws, model.row(0).to_array());
-                        debug!(target: "gfx", "{}    {:?}", ws, model.row(1).to_array());
-                        debug!(target: "gfx", "{}    {:?}", ws, model.row(2).to_array());
-                        debug!(target: "gfx", "{}    {:?}", ws, model.row(3).to_array());
-                        debug!(target: "gfx", "{})", ws);
-                    }
-                    let data: [u8; 64] = unsafe { std::mem::transmute_copy(model) };
-                    self.uniforms_data[64..].copy_from_slice(&data);
-                    self.ctx.apply_uniforms_from_bytes(
-                        self.uniforms_data.as_ptr(),
-                        self.uniforms_data.len(),
-                    );
-                    */
-                }
                 DrawInstruction::Draw(mesh) => {
                     if DEBUG_RENDER {
                         debug!(target: "gfx", "{ws}draw({mesh:?})");
@@ -362,16 +327,6 @@ impl<'a> RenderContext<'a> {
                 debug!(target: "gfx", "{ws}drawcall {dc_key}");
             }
             self.draw_call(dc, indent + 1);
-
-            /*
-            // Reset view back again in case the draw call changed it
-            if let Some(view) = &prev_view {
-                if DEBUG_RENDER {
-                    debug!(target: "gfx", "{}reset viewport to {:?}", ws, view);
-                }
-                self.apply_view(view);
-            }
-            */
         }
 
         self.cursor = old_cursor;

+ 2 - 0
bin/darkwallet/src/main.rs

@@ -142,6 +142,7 @@ fn main() {
     let cv_started = app.is_started.clone();
     let sg_root = app.sg_root.clone();
     let ex2 = ex.clone();
+    /*
     let darkirc_task = ex.spawn(async move {
         cv_started.wait().await;
         let darkirc_evgr = LocalDarkIRC::new(sg_root.clone(), ex2.clone()).await.unwrap();
@@ -151,6 +152,7 @@ fn main() {
         }
     });
     async_runtime.push_task(darkirc_task);
+    */
 
     /*
     // Nice to see which events exist

+ 112 - 51
bin/darkwallet/src/ui/editbox.rs

@@ -157,9 +157,13 @@ pub struct EditBox {
     text_shaper: TextShaperPtr,
     key_repeat: SyncMutex<PressedKeysSmoothRepeat>,
 
-    render_info: SyncMutex<Option<TextRenderInfo>>,
+    text_render_info: SyncMutex<Option<TextRenderInfo>>,
     glyphs: SyncMutex<Vec<Glyph>>,
-    dc_key: u64,
+    /// DC key for the text
+    text_dc_key: u64,
+    cursor_render_mesh: SyncMutex<Option<MeshInfo>>,
+    /// DC key for the cursor. Allows updating cursor independently.
+    cursor_dc_key: u64,
 
     is_active: PropertyBool,
     is_focused: PropertyBool,
@@ -258,9 +262,11 @@ impl EditBox {
                 text_shaper,
                 key_repeat: SyncMutex::new(PressedKeysSmoothRepeat::new(400, 50)),
 
-                render_info: SyncMutex::new(None),
+                text_render_info: SyncMutex::new(None),
                 glyphs: SyncMutex::new(glyphs),
-                dc_key: OsRng.gen(),
+                text_dc_key: OsRng.gen(),
+                cursor_render_mesh: SyncMutex::new(None),
+                cursor_dc_key: OsRng.gen(),
 
                 is_active,
                 is_focused,
@@ -298,8 +304,7 @@ impl EditBox {
     }
 
     /// Called whenever the text or any text property changes.
-    /// Not related to cursor, text highlighting or bounding (clip) rects.
-    fn regen_mesh(&self, mut clip: Rectangle) -> TextRenderInfo {
+    fn regen_text_mesh(&self, mut clip: Rectangle) -> TextRenderInfo {
         clip.x = 0.;
         clip.y = 0.;
 
@@ -323,8 +328,6 @@ impl EditBox {
         self.draw_selected(&mut mesh, &glyphs, clip.h).unwrap();
 
         let glyph_pos_iter = GlyphPositionIter::new(font_size, window_scale, &glyphs, baseline);
-        // Used for drawing the cursor when it's at the end of the line.
-        let mut rhs = 0.;
 
         for (glyph_idx, (mut glyph_rect, glyph)) in glyph_pos_iter.zip(glyphs.iter()).enumerate() {
             let uv_rect = atlas.fetch_uv(glyph.glyph_id).expect("missing glyph UV rect");
@@ -337,23 +340,6 @@ impl EditBox {
                 color = COLOR_WHITE;
             }
             mesh.draw_box(&glyph_rect, color, uv_rect);
-
-            if is_focused && cursor_pos != 0 && cursor_pos == glyph_idx {
-                let cursor_rect = Rectangle { x: glyph_rect.x, y: 0., w: CURSOR_WIDTH, h: clip.h };
-                mesh.draw_box(&cursor_rect, cursor_color, &Rectangle::zero());
-            }
-
-            rhs = glyph_rect.rhs();
-        }
-
-        if is_focused && cursor_pos == 0 {
-            let cursor_rect = Rectangle { x: 0., y: 0., w: CURSOR_WIDTH, h: clip.h };
-            mesh.draw_box(&cursor_rect, cursor_color, &Rectangle::zero());
-        } else if is_focused && cursor_pos == glyphs.len() {
-            rhs += eol_nudge(font_size, &glyphs);
-
-            let cursor_rect = Rectangle { x: rhs, y: 0., w: CURSOR_WIDTH, h: clip.h };
-            mesh.draw_box(&cursor_rect, cursor_color, &Rectangle::zero());
         }
 
         if debug {
@@ -365,6 +351,49 @@ impl EditBox {
         TextRenderInfo { mesh, texture_id: atlas.texture_id }
     }
 
+    fn regen_cursor_mesh(&self) -> MeshInfo {
+        let rect_h = self.rect.get().h;
+        let cursor_rect = Rectangle { x: 0., y: 0., w: CURSOR_WIDTH, h: rect_h };
+        let cursor_color = self.cursor_color.get();
+
+        let mut mesh = MeshBuilder::new();
+        mesh.draw_filled_box(&cursor_rect, cursor_color);
+        mesh.alloc(&self.render_api)
+    }
+
+    fn cursor_px_offset(&self) -> f32 {
+        assert!(self.is_focused.get());
+
+        let font_size = self.font_size.get();
+        let window_scale = self.window_scale.get();
+        let baseline = self.baseline.get();
+        let scroll = self.scroll.get();
+        let cursor_pos = self.cursor_pos.get() as usize;
+        let glyphs = self.glyphs.lock().unwrap().clone();
+        let glyph_pos_iter = GlyphPositionIter::new(font_size, window_scale, &glyphs, baseline);
+        // Used for drawing the cursor when it's at the end of the line.
+        let mut rhs = 0.;
+
+        if cursor_pos == 0 {
+            return 0.;
+        }
+
+        for (glyph_idx, (mut glyph_rect, glyph)) in glyph_pos_iter.zip(glyphs.iter()).enumerate() {
+            glyph_rect.x -= scroll;
+
+            if cursor_pos == glyph_idx {
+                return glyph_rect.x;
+            }
+
+            rhs = glyph_rect.rhs();
+        }
+
+        assert!(cursor_pos == glyphs.len());
+
+        rhs += eol_nudge(font_size, &glyphs);
+        rhs
+    }
+
     fn draw_selected(
         &self,
         mesh: &mut MeshBuilder,
@@ -955,51 +984,83 @@ impl EditBox {
         let mut freed_textures = vec![];
         let mut freed_buffers = vec![];
 
+        // Force complete redraw if the window scale changed
         let window_scale = self.window_scale.get();
         if self.old_window_scale.swap(window_scale, Ordering::Relaxed) != window_scale {
             self.regen_glyphs().await;
 
-            let render_info = std::mem::replace(&mut *self.render_info.lock().unwrap(), None);
+            let text_render_info =
+                std::mem::replace(&mut *self.text_render_info.lock().unwrap(), None);
             // We're finished with these so clean up.
-            if let Some(old) = render_info {
+            if let Some(old) = text_render_info {
                 freed_textures.push(old.texture_id);
                 freed_buffers.push(old.mesh.vertex_buffer);
                 freed_buffers.push(old.mesh.index_buffer);
             }
         }
 
-        // draw will recalc this when it's None
-        let render_info = self.regen_mesh(rect.clone());
-        let old_render_info =
-            std::mem::replace(&mut *self.render_info.lock().unwrap(), Some(render_info.clone()));
+        let text_render_info = self.regen_text_mesh(rect.clone());
+        let old_text_render_info = std::mem::replace(
+            &mut *self.text_render_info.lock().unwrap(),
+            Some(text_render_info.clone()),
+        );
+
+        let cursor_render_mesh = {
+            let mut cursor_render_mesh = self.cursor_render_mesh.lock().unwrap();
+            if cursor_render_mesh.is_none() {
+                *cursor_render_mesh = Some(self.regen_cursor_mesh());
+            }
+            cursor_render_mesh.clone().unwrap()
+        };
 
         // We're finished with these so clean up.
-        if let Some(old) = old_render_info {
+        if let Some(old) = old_text_render_info {
             freed_textures.push(old.texture_id);
             freed_buffers.push(old.mesh.vertex_buffer);
             freed_buffers.push(old.mesh.index_buffer);
         }
 
-        let mesh = GfxDrawMesh {
-            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,
+        let text_mesh = GfxDrawMesh {
+            vertex_buffer: text_render_info.mesh.vertex_buffer,
+            index_buffer: text_render_info.mesh.index_buffer,
+            texture: Some(text_render_info.texture_id),
+            num_elements: text_render_info.mesh.num_elements,
         };
 
+        let mut cursor_instrs = vec![];
+        if self.is_focused.get() {
+            let mut cursor_pos = Point::zero();
+            cursor_pos.x += self.cursor_px_offset();
+            cursor_instrs.push(GfxDrawInstruction::Move(cursor_pos));
+
+            let cursor_mesh = GfxDrawMesh {
+                vertex_buffer: cursor_render_mesh.vertex_buffer,
+                index_buffer: cursor_render_mesh.index_buffer,
+                texture: None,
+                num_elements: cursor_render_mesh.num_elements,
+            };
+            cursor_instrs.push(GfxDrawInstruction::Draw(cursor_mesh));
+        }
+
         Some(DrawUpdate {
-            key: self.dc_key,
-            draw_calls: vec![(
-                self.dc_key,
-                GfxDrawCall {
-                    instrs: vec![
-                        GfxDrawInstruction::Move(rect.pos()),
-                        GfxDrawInstruction::Draw(mesh),
-                    ],
-                    dcs: vec![],
-                    z_index: self.z_index.get(),
-                },
-            )],
+            key: self.text_dc_key,
+            draw_calls: vec![
+                (
+                    self.text_dc_key,
+                    GfxDrawCall {
+                        instrs: vec![
+                            GfxDrawInstruction::Move(rect.pos()),
+                            GfxDrawInstruction::Draw(text_mesh),
+                        ],
+                        dcs: vec![self.cursor_dc_key],
+                        z_index: self.z_index.get(),
+                    },
+                ),
+                (
+                    self.cursor_dc_key,
+                    GfxDrawCall { instrs: cursor_instrs, dcs: vec![], z_index: self.z_index.get() },
+                ),
+            ],
             freed_textures,
             freed_buffers,
         })
@@ -1008,9 +1069,9 @@ impl EditBox {
 
 impl Drop for EditBox {
     fn drop(&mut self) {
-        let render_info = std::mem::replace(&mut *self.render_info.lock().unwrap(), None);
+        let text_render_info = std::mem::replace(&mut *self.text_render_info.lock().unwrap(), None);
         // We're finished with these so clean up.
-        if let Some(old) = render_info {
+        if let Some(old) = text_render_info {
             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);