Przeglądaj źródła

wallet: support upscaling in the core text lib itself

darkfi 1 rok temu
rodzic
commit
3dead803ad

+ 14 - 2
bin/darkwallet/src/app/schema.rs

@@ -350,7 +350,13 @@ pub(super) async fn make_test(app: &App, window: SceneNodePtr) {
 
     let node = node
         .setup(|me| {
-            EditBox::new(me, app.render_api.clone(), app.text_shaper.clone(), app.ex.clone())
+            EditBox::new(
+                me,
+                window_scale.clone(),
+                app.render_api.clone(),
+                app.text_shaper.clone(),
+                app.ex.clone(),
+            )
         })
         .await;
     layer_node.link(node);
@@ -772,7 +778,13 @@ pub(super) async fn make(app: &App, window: SceneNodePtr) {
 
     let node = node
         .setup(|me| {
-            EditBox::new(me, app.render_api.clone(), app.text_shaper.clone(), app.ex.clone())
+            EditBox::new(
+                me,
+                window_scale.clone(),
+                app.render_api.clone(),
+                app.text_shaper.clone(),
+                app.ex.clone(),
+            )
         })
         .await;
     layer_node.link(node);

+ 21 - 8
bin/darkwallet/src/text/mod.rs

@@ -69,6 +69,7 @@ pub use wrap::{glyph_str, wrap};
 
 pub struct GlyphPositionIter<'a> {
     font_size: f32,
+    window_scale: f32,
     glyphs: &'a Vec<Glyph>,
     current_x: f32,
     current_y: f32,
@@ -76,8 +77,15 @@ pub struct GlyphPositionIter<'a> {
 }
 
 impl<'a> GlyphPositionIter<'a> {
-    pub fn new(font_size: f32, glyphs: &'a Vec<Glyph>, baseline_y: f32) -> Self {
-        Self { font_size, glyphs, current_x: 0., current_y: baseline_y, i: 0 }
+    pub fn new(font_size: f32, window_scale: f32, glyphs: &'a Vec<Glyph>, baseline_y: f32) -> Self {
+        Self {
+            font_size,
+            window_scale,
+            glyphs,
+            current_x: 0.,
+            current_y: baseline_y * window_scale,
+            i: 0,
+        }
     }
 }
 
@@ -121,6 +129,8 @@ impl<'a> Iterator for GlyphPositionIter<'a> {
             Rectangle { x, y, w, h }
         };
 
+        let mut rect = rect / self.window_scale;
+
         self.i += 1;
         Some(rect)
     }
@@ -186,7 +196,7 @@ impl TextShaper {
         substrs
     }
 
-    pub async fn shape(&self, text: String, font_size: f32) -> Vec<Glyph> {
+    pub async fn shape(&self, text: String, font_size: f32, window_scale: f32) -> Vec<Glyph> {
         //debug!(target: "text", "shape('{}', {})", text, font_size);
         // Lock font faces
         // Freetype faces are not threadsafe
@@ -205,7 +215,8 @@ impl TextShaper {
                 //face.set_char_size(109 * 64, 0, 72, 72).unwrap();
                 face.select_size(0).unwrap();
             } else {
-                face.set_char_size(font_size as isize * 64, 0, 96, 96).unwrap();
+                let size = font_size * window_scale;
+                face.set_char_size(size as isize * 64, 0, 96, 96).unwrap();
             }
 
             /*
@@ -284,7 +295,7 @@ impl TextShaper {
                     font_size: if face.has_fixed_sizes() {
                         FontSize::Fixed
                     } else {
-                        FontSize::from(font_size)
+                        FontSize::from((font_size, window_scale))
                     },
                     face_idx,
                 };
@@ -408,13 +419,15 @@ impl TextShaper {
 #[derive(Eq, Hash, PartialEq, Debug)]
 enum FontSize {
     Fixed,
-    Size(u32),
+    Size((u32, u32)),
 }
 
 impl FontSize {
     /// You can't use f32 in Hash and Eq impls
-    fn from(size: f32) -> Self {
-        Self::Size((size * 1000.).round() as u32)
+    fn from(size: (f32, f32)) -> Self {
+        let font_size = (size.0 * 1000.).round() as u32;
+        let scale = (size.1 * 1000.).round() as u32;
+        Self::Size((font_size, scale))
     }
 }
 

+ 9 - 4
bin/darkwallet/src/text/wrap.rs

@@ -27,8 +27,8 @@ pub fn glyph_str(glyphs: &Vec<Glyph>) -> String {
     glyphs.iter().map(|g| g.substr.as_str()).collect::<Vec<_>>().join("")
 }
 
-fn tokenize(font_size: f32, glyphs: &Vec<Glyph>) -> Vec<Token> {
-    let glyph_pos_iter = GlyphPositionIter::new(font_size, glyphs, 0.);
+fn tokenize(font_size: f32, window_scale: f32, glyphs: &Vec<Glyph>) -> Vec<Token> {
+    let glyph_pos_iter = GlyphPositionIter::new(font_size, window_scale, glyphs, 0.);
 
     let mut tokens = vec![];
     let mut token_glyphs = vec![];
@@ -133,8 +133,13 @@ fn apply_wrap(line_width: f32, tokens: Vec<Token>) -> Vec<Vec<Glyph>> {
     lines
 }
 
-pub fn wrap(line_width: f32, font_size: f32, glyphs: &Vec<Glyph>) -> Vec<Vec<Glyph>> {
-    let tokens = tokenize(font_size, glyphs);
+pub fn wrap(
+    line_width: f32,
+    font_size: f32,
+    window_scale: f32,
+    glyphs: &Vec<Glyph>,
+) -> Vec<Vec<Glyph>> {
+    let tokens = tokenize(font_size, window_scale, glyphs);
 
     //debug!(target: "text::wrap", "tokenized words {:?}",
     //       words.iter().map(|w| w.as_str()).collect::<Vec<_>>());

+ 10 - 14
bin/darkwallet/src/ui/chatview/page.rs

@@ -86,7 +86,7 @@ impl PrivMessage {
         render_api: &RenderApi,
     ) -> Message {
         let linetext = Self::gen_line_text(timestamp, &nick, &text);
-        let unwrapped_glyphs = text_shaper.shape(linetext, font_size * window_scale).await;
+        let unwrapped_glyphs = text_shaper.shape(linetext, font_size, window_scale).await;
 
         let mut atlas = text::Atlas::new(render_api);
         atlas.push(&unwrapped_glyphs);
@@ -211,14 +211,9 @@ impl PrivMessage {
             section = 0;
         }
 
-        let glyph_pos_iter = GlyphPositionIter::new(
-            self.font_size * self.window_scale,
-            line,
-            baseline * self.window_scale,
-        );
-        for (glyph_rect, glyph) in glyph_pos_iter.zip(line.iter()) {
-            let mut glyph_rect = glyph_rect / self.window_scale;
-
+        let glyph_pos_iter =
+            GlyphPositionIter::new(self.font_size, self.window_scale, line, baseline);
+        for (mut glyph_rect, glyph) in glyph_pos_iter.zip(line.iter()) {
             let uv_rect = self.atlas.fetch_uv(glyph.glyph_id).expect("missing glyph UV rect");
             glyph_rect.y -= off_y;
 
@@ -250,7 +245,7 @@ impl PrivMessage {
         self.window_scale = window_scale;
 
         let linetext = Self::gen_line_text(self.timestamp, &self.nick, &self.text);
-        self.unwrapped_glyphs = text_shaper.shape(linetext, self.font_size * window_scale).await;
+        self.unwrapped_glyphs = text_shaper.shape(linetext, self.font_size, window_scale).await;
 
         let texture_id = self.atlas.texture_id;
 
@@ -265,7 +260,7 @@ impl PrivMessage {
     fn adjust_width(&mut self, line_width: f32) {
         // Invalidate wrapped_glyphs and recalc
         self.wrapped_lines =
-            text::wrap(line_width * self.window_scale, self.font_size, &self.unwrapped_glyphs);
+            text::wrap(line_width, self.font_size, self.window_scale, &self.unwrapped_glyphs);
     }
 
     fn clear_mesh(&mut self) -> Option<GfxDrawMesh> {
@@ -310,7 +305,7 @@ impl DateMessage {
         let datestr = Self::datestr(timestamp);
         let timestamp = Self::timest_to_midnight(timestamp);
 
-        let glyphs = text_shaper.shape(datestr, font_size).await;
+        let glyphs = text_shaper.shape(datestr, font_size, window_scale).await;
 
         let mut atlas = text::Atlas::new(render_api);
         atlas.push(&glyphs);
@@ -343,7 +338,7 @@ impl DateMessage {
         self.window_scale = window_scale;
 
         let datestr = Self::datestr(self.timestamp);
-        self.glyphs = text_shaper.shape(datestr, self.font_size * window_scale).await;
+        self.glyphs = text_shaper.shape(datestr, self.font_size, window_scale).await;
 
         let texture_id = self.atlas.texture_id;
 
@@ -373,7 +368,8 @@ impl DateMessage {
     ) -> GfxDrawMesh {
         let mut mesh = MeshBuilder::new();
 
-        let glyph_pos_iter = GlyphPositionIter::new(self.font_size, &self.glyphs, baseline);
+        let glyph_pos_iter =
+            GlyphPositionIter::new(self.font_size, self.window_scale, &self.glyphs, baseline);
         for (mut glyph_rect, glyph) in glyph_pos_iter.zip(self.glyphs.iter()) {
             let uv_rect = self.atlas.fetch_uv(glyph.glyph_id).expect("missing glyph UV rect");
             glyph_rect.y -= line_height;

+ 33 - 8
bin/darkwallet/src/ui/editbox.rs

@@ -17,6 +17,7 @@
  */
 
 use async_trait::async_trait;
+use atomic_float::AtomicF32;
 use miniquad::{window, KeyCode, KeyMods, MouseButton, TouchPhase};
 use rand::{rngs::OsRng, Rng};
 use std::{
@@ -177,12 +178,15 @@ pub struct EditBox {
 
     mouse_btn_held: AtomicBool,
 
+    old_window_scale: AtomicF32,
+    window_scale: PropertyFloat32,
     parent_rect: SyncMutex<Option<Rectangle>>,
 }
 
 impl EditBox {
     pub async fn new(
         node: SceneNodeWeak,
+        window_scale: PropertyFloat32,
         render_api: RenderApiPtr,
         text_shaper: TextShaperPtr,
         ex: ExecutorPtr,
@@ -209,7 +213,7 @@ impl EditBox {
         let node_id = node_ref.id;
 
         // Must do this whenever the text changes
-        let glyphs = text_shaper.shape(text.get(), font_size.get()).await;
+        let glyphs = text_shaper.shape(text.get(), font_size.get(), window_scale.get()).await;
 
         let self_ = Arc::new_cyclic(|me: &Weak<Self>| {
             let mut on_modify = OnModify::new(ex, node_name, node_id, me.clone());
@@ -275,6 +279,8 @@ impl EditBox {
 
                 mouse_btn_held: AtomicBool::new(false),
 
+                old_window_scale: AtomicF32::new(window_scale.get()),
+                window_scale,
                 parent_rect: SyncMutex::new(None),
             }
         });
@@ -284,7 +290,9 @@ impl EditBox {
 
     /// This MUST be called whenever the text property is changed.
     async fn regen_glyphs(&self) {
-        let glyphs = self.text_shaper.shape(self.text.get(), self.font_size.get()).await;
+        let font_size = self.font_size.get();
+        let window_scale = self.window_scale.get();
+        let glyphs = self.text_shaper.shape(self.text.get(), font_size, window_scale).await;
         // TODO: we aren't freeing textures
         *self.glyphs.lock().unwrap() = glyphs;
     }
@@ -298,6 +306,7 @@ impl EditBox {
         let is_focused = self.is_focused.get();
         let text = self.text.get();
         let font_size = self.font_size.get();
+        let window_scale = self.window_scale.get();
         let text_color = self.text_color.get();
         let baseline = self.baseline.get();
         let scroll = self.scroll.get();
@@ -313,7 +322,7 @@ impl EditBox {
         let mut mesh = MeshBuilder::with_clip(clip.clone());
         self.draw_selected(&mut mesh, &glyphs, clip.h).unwrap();
 
-        let glyph_pos_iter = GlyphPositionIter::new(font_size, &glyphs, baseline);
+        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.;
 
@@ -378,10 +387,11 @@ impl EditBox {
         let sel_end = std::cmp::max(start, end);
 
         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 hi_bg_color = self.hi_bg_color.get();
-        let glyph_pos_iter = GlyphPositionIter::new(font_size, &glyphs, baseline);
+        let glyph_pos_iter = GlyphPositionIter::new(font_size, window_scale, &glyphs, baseline);
 
         let mut start_x = 0.;
         let mut end_x = 0.;
@@ -505,6 +515,7 @@ impl EditBox {
     /// of the closest glyph to that x coord.
     fn find_closest_glyph_idx(&self, x: f32, rect: &Rectangle) -> u32 {
         let font_size = self.font_size.get();
+        let window_scale = self.window_scale.get();
         let baseline = self.baseline.get();
         let glyphs = self.glyphs.lock().unwrap().clone();
 
@@ -525,7 +536,7 @@ impl EditBox {
         let lhs = 0.;
         let mut last_d = (lhs - mouse_x).abs();
 
-        let glyph_pos_iter = GlyphPositionIter::new(font_size, &glyphs, baseline);
+        let glyph_pos_iter = GlyphPositionIter::new(font_size, window_scale, &glyphs, baseline);
         let mut rhs = 0.;
 
         for (i, glyph_rect) in glyph_pos_iter.skip(1).enumerate() {
@@ -878,10 +889,12 @@ impl EditBox {
 
         let cursor_x = {
             let font_size = self.font_size.get();
+            let window_scale = self.window_scale.get();
             let baseline = self.baseline.get();
             let glyphs = self.glyphs.lock().unwrap().clone();
 
-            let mut glyph_pos_iter = GlyphPositionIter::new(font_size, &glyphs, baseline);
+            let mut glyph_pos_iter =
+                GlyphPositionIter::new(font_size, window_scale, &glyphs, baseline);
 
             if cursor_pos == 0 {
                 0.
@@ -935,14 +948,26 @@ impl EditBox {
     fn draw_cached(&self) -> Option<DrawUpdate> {
         let rect = self.rect.get();
 
+        let mut freed_textures = vec![];
+        let mut freed_buffers = vec![];
+
+        let window_scale = self.window_scale.get();
+        if self.old_window_scale.swap(window_scale, Ordering::Relaxed) != window_scale {
+            let render_info = std::mem::replace(&mut *self.render_info.lock().unwrap(), None);
+            // We're finished with these so clean up.
+            if let Some(old) = 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()));
 
         // We're finished with these so clean up.
-        let mut freed_textures = vec![];
-        let mut freed_buffers = vec![];
         if let Some(old) = old_render_info {
             freed_textures.push(old.texture_id);
             freed_buffers.push(old.mesh.vertex_buffer);

+ 2 - 5
bin/darkwallet/src/ui/text.rs

@@ -145,15 +145,12 @@ impl Text {
         window_scale: f32,
     ) -> TextRenderInfo {
         debug!(target: "ui::text", "Rendering label '{}'", text);
-        let glyphs = text_shaper.shape(text, font_size * window_scale).await;
+        let glyphs = text_shaper.shape(text, font_size, window_scale).await;
         let atlas = text::make_texture_atlas(render_api, &glyphs);
 
         let mut mesh = MeshBuilder::new();
-        let glyph_pos_iter =
-            GlyphPositionIter::new(font_size * window_scale, &glyphs, baseline * window_scale);
+        let glyph_pos_iter = GlyphPositionIter::new(font_size, window_scale, &glyphs, baseline);
         for (mut glyph_rect, glyph) in glyph_pos_iter.zip(glyphs.iter()) {
-            let glyph_rect = glyph_rect / window_scale;
-
             let uv_rect = atlas.fetch_uv(glyph.glyph_id).expect("missing glyph UV rect");
 
             if debug {