فهرست منبع

app: add editor actions and inner padding

darkfi 1 سال پیش
والد
کامیت
1c2bd72d67

+ 1 - 1
bin/app/Makefile

@@ -19,7 +19,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=enable-filelog,enable-netdebug
+DEV_FEATURES =
 
 default: build-release
 	./darkfi-app

+ 11 - 5
bin/app/src/app/schema/test.rs

@@ -487,14 +487,20 @@ pub async fn make(app: &App, window: SceneNodePtr) {
     node.set_property_bool(atom, Role::App, "is_focused", true).unwrap();
 
     let prop = node.get_property("height_range").unwrap();
-    prop.clone().set_f32(atom, Role::App, 0, 100.).unwrap();
+    prop.clone().set_f32(atom, Role::App, 0, 0.).unwrap();
     prop.clone().set_f32(atom, Role::App, 1, 400.).unwrap();
 
     let prop = node.get_property("rect").unwrap();
     prop.clone().set_f32(atom, Role::App, 0, 100.).unwrap();
     prop.clone().set_f32(atom, Role::App, 1, 300.).unwrap();
     prop.clone().set_expr(atom, Role::App, 2, expr::load_var("parent_w")).unwrap();
-    prop.clone().set_f32(atom, Role::App, 3, 50.).unwrap();
+    //prop.clone().set_f32(atom, Role::App, 3, 50.).unwrap();
+
+    node.set_property_bool(atom, Role::App, "debug", true).unwrap();
+
+    let prop = node.get_property("padding").unwrap();
+    prop.clone().set_f32(atom, Role::App, 0, 20.).unwrap();
+    prop.clone().set_f32(atom, Role::App, 1, 20.).unwrap();
 
     node.set_property_f32(atom, Role::App, "baseline", 34.).unwrap();
     node.set_property_f32(atom, Role::App, "linespacing", 50.).unwrap();
@@ -516,10 +522,10 @@ pub async fn make(app: &App, window: SceneNodePtr) {
     prop.clone().set_f32(atom, Role::App, 1, 0.627).unwrap();
     prop.clone().set_f32(atom, Role::App, 2, 1.).unwrap();
     prop.clone().set_f32(atom, Role::App, 3, 1.).unwrap();
-    node.set_property_f32(atom, Role::App, "cursor_ascent", 50.).unwrap();
+    node.set_property_f32(atom, Role::App, "cursor_ascent", 35.).unwrap();
     node.set_property_f32(atom, Role::App, "cursor_descent", 20.).unwrap();
-    node.set_property_f32(atom, Role::App, "select_ascent", 40.).unwrap();
-    node.set_property_f32(atom, Role::App, "select_descent", 8.).unwrap();
+    node.set_property_f32(atom, Role::App, "select_ascent", 35.).unwrap();
+    node.set_property_f32(atom, Role::App, "select_descent", 20.).unwrap();
     node.set_property_f32(atom, Role::App, "handle_descent", 25.).unwrap();
     let prop = node.get_property("hi_bg_color").unwrap();
     prop.clone().set_f32(atom, Role::App, 0, 0.5).unwrap();

+ 1 - 0
bin/app/src/main.rs

@@ -81,6 +81,7 @@ fn main() {
     // Abort the application on panic right away
     std::panic::set_hook(Box::new(panic_hook));
 
+    text2::init_txt_ctx();
     logger::setup_logging();
 
     #[cfg(target_os = "android")]

+ 4 - 0
bin/app/src/prop/wrap.rs

@@ -339,6 +339,10 @@ impl PropertyRect {
         ])
     }
 
+    pub fn get_width(&self) -> f32 {
+        self.prop.get_f32(2).unwrap()
+    }
+
     pub fn get_opt(&self) -> Option<Rectangle> {
         Some(Rectangle::from_array([
             self.prop.get_f32(0).ok()?,

+ 18 - 7
bin/app/src/text2/editor/android.rs

@@ -21,7 +21,7 @@ use crate::{
     gfx::Point,
     mesh::Color,
     prop::{PropertyColor, PropertyFloat32},
-    text2::get_ctx,
+    text2::{TextContext, TEXT_CTX},
 };
 
 macro_rules! t { ($($arg:tt)*) => { trace!(target: "text::editor::android", $($arg)*); } }
@@ -44,6 +44,7 @@ pub struct Editor {
     is_init: bool,
 
     layout: parley::Layout<Color>,
+    width: Option<f32>,
 
     font_size: PropertyFloat32,
     text_color: PropertyColor,
@@ -63,6 +64,8 @@ impl Editor {
             is_init: false,
 
             layout: Default::default(),
+            width: None,
+
             font_size,
             text_color,
             window_scale,
@@ -90,14 +93,14 @@ impl Editor {
         let edit = android::get_editable(self.composer_id).unwrap();
         t!("refesh buffer = {}", edit.buffer);
 
-        let mut txt_ctx = get_ctx().await;
+        let mut txt_ctx = TEXT_CTX.get().await;
         self.layout = txt_ctx.make_layout(
             &edit.buffer,
             text_color,
             font_size,
             lineheight,
             window_scale,
-            None,
+            self.width,
         );
     }
 
@@ -144,9 +147,17 @@ impl Editor {
         Some(cursor_pos)
     }
 
-    pub fn driver<F>(&mut self, f: F)
-    where
-        F: FnOnce(&mut parley::PlainEditorDriver<'_, Color>),
-    {
+    pub async fn driver<'a>(
+        &'a mut self,
+        txt_ctx: &'a mut TextContext,
+    ) -> Option<parley::PlainEditorDriver<'a, Color>> {
+        None
+    }
+
+    pub fn set_width(&mut self, w: f32) {
+        self.width = Some(w);
+    }
+    pub fn height(&self) -> f32 {
+        self.layout().height()
     }
 }

+ 22 - 16
bin/app/src/text2/editor/parley.rs

@@ -20,7 +20,7 @@ use crate::{
     gfx::Point,
     mesh::Color,
     prop::{PropertyColor, PropertyFloat32},
-    text2::{TextContext, FONT_STACK, TEXT_CTX2},
+    text2::{TextContext, FONT_STACK, TEXT_CTX},
 };
 
 macro_rules! t { ($($arg:tt)*) => { trace!(target: "text::editor", $($arg)*); } }
@@ -63,10 +63,9 @@ impl Editor {
         styles.insert(parley::StyleProperty::Brush(text_color));
         *self.editor.edit_styles() = styles;
 
-        TEXT_CTX2.with_borrow_mut(|txt_ctx| {
-            let (font_ctx, layout_ctx) = txt_ctx.borrow();
-            self.editor.refresh_layout(font_ctx, layout_ctx);
-        });
+        let mut txt_ctx = TEXT_CTX.get().await;
+        let (font_ctx, layout_ctx) = txt_ctx.borrow();
+        self.editor.refresh_layout(font_ctx, layout_ctx);
     }
 
     pub fn layout(&self) -> &parley::Layout<Color> {
@@ -76,20 +75,27 @@ impl Editor {
     pub fn move_to_pos(&self, pos: Point) {}
 
     pub fn get_cursor_pos(&self) -> Option<Point> {
-        let lineheight = self.lineheight.get();
-        let cursor_rect = self.editor.cursor_geometry(lineheight).unwrap();
+        let cursor_rect = self.editor.cursor_geometry(0.).unwrap();
         let cursor_pos = Point::new(cursor_rect.x0 as f32, cursor_rect.y0 as f32);
         Some(cursor_pos)
     }
 
-    pub fn driver<F>(&mut self, f: F)
-    where
-        F: FnOnce(parley::PlainEditorDriver<'_, Color>),
-    {
-        TEXT_CTX2.with_borrow_mut(|txt_ctx| {
-            let (font_ctx, layout_ctx) = txt_ctx.borrow();
-            let drv = self.editor.driver(font_ctx, layout_ctx);
-            f(drv);
-        });
+    pub async fn driver<'a>(
+        &'a mut self,
+        txt_ctx: &'a mut TextContext,
+    ) -> Option<parley::PlainEditorDriver<'a, Color>> {
+        let (font_ctx, layout_ctx) = txt_ctx.borrow();
+        Some(self.editor.driver(font_ctx, layout_ctx))
+    }
+
+    pub fn set_width(&mut self, w: f32) {
+        self.editor.set_width(Some(w));
+    }
+    pub fn height(&self) -> f32 {
+        self.layout().height()
+    }
+
+    pub fn selected_text(&self) -> Option<&str> {
+        self.editor.selected_text()
     }
 }

+ 35 - 7
bin/app/src/text2/mod.rs

@@ -17,9 +17,11 @@
  */
 
 use async_lock::Mutex as AsyncMutex;
+use futures::stream::{FuturesUnordered, StreamExt};
 use std::{
     cell::RefCell,
-    sync::{Arc, OnceLock},
+    fmt::Debug,
+    sync::{atomic::AtomicBool, Arc, OnceLock},
 };
 
 use crate::mesh::Color;
@@ -30,16 +32,41 @@ pub use editor::Editor;
 mod render;
 pub use render::{render_layout, DebugRenderOptions};
 
-thread_local! {
-    static TEXT_CTX2: RefCell<TextContext> = RefCell::new(TextContext::new());
+use darkfi::system::CondVar;
+
+pub struct AsyncGlobal<T> {
+    cv: CondVar,
+    val: OnceLock<AsyncMutex<T>>,
+}
+
+impl<T> AsyncGlobal<T> {
+    const fn new() -> Self {
+        Self { cv: CondVar::new(), val: OnceLock::new() }
+    }
+
+    fn set(&self, val: T) {
+        self.val.set(AsyncMutex::new(val)).ok().unwrap();
+        self.cv.notify();
+    }
+
+    pub async fn get<'a>(&'a self) -> async_lock::MutexGuard<'a, T> {
+        self.cv.wait().await;
+        self.val.get().unwrap().lock().await
+    }
 }
 
-static TEXT_CTX: OnceLock<AsyncMutex<TextContext>> = OnceLock::new();
+pub static TEXT_CTX: AsyncGlobal<TextContext> = AsyncGlobal::new();
 
-pub async fn get_ctx() -> async_lock::MutexGuard<'static, TextContext> {
-    TEXT_CTX.get_or_init(|| AsyncMutex::new(TextContext::new())).lock().await
+pub fn init_txt_ctx() {
+    std::thread::spawn(|| {
+        // This is quite slow. It takes 300ms
+        let txt_ctx = TextContext::new();
+        TEXT_CTX.set(txt_ctx);
+    });
 }
 
+/// Initializing this is expensive ~300ms, but storage is ~2kb.
+/// It has to be created once and reused. Currently we use thread local storage.
 pub struct TextContext {
     font_ctx: parley::FontContext,
     layout_ctx: parley::LayoutContext<Color>,
@@ -47,6 +74,7 @@ pub struct TextContext {
 
 impl TextContext {
     fn new() -> Self {
+        let layout_ctx = parley::LayoutContext::new();
         let mut font_ctx = parley::FontContext::new();
 
         let font_data = include_bytes!("../../ibm-plex-mono-regular.otf") as &[u8];
@@ -62,7 +90,7 @@ impl TextContext {
             trace!(target: "text", "Loaded font: {family_name}");
         }
 
-        Self { font_ctx, layout_ctx: Default::default() }
+        Self { font_ctx, layout_ctx }
     }
 
     pub fn borrow(&mut self) -> (&mut parley::FontContext, &mut parley::LayoutContext<Color>) {

+ 208 - 137
bin/app/src/ui/chatedit.rs

@@ -422,17 +422,17 @@ impl ChatEdit {
         self.node.upgrade().unwrap()
     }
 
-    fn wrap_width(&self) -> f32 {
-        let w = self.rect.prop().get_f32(2).unwrap() - self.cursor_width.get();
-        if w < 0. {
-            return 0.
-        }
-        w
+    fn padding_top(&self) -> f32 {
+        self.padding.get_f32(0).unwrap()
+    }
+    fn padding_bottom(&self) -> f32 {
+        self.padding.get_f32(1).unwrap()
     }
 
     fn abs_to_local(&self, point: &mut Point) {
         let rect = self.rect.get();
         *point -= rect.pos();
+        point.y -= self.padding_top();
         point.y += self.scroll.get();
     }
 
@@ -538,8 +538,10 @@ impl ChatEdit {
         let mut tmp = [0; 4];
         let key_str = key.encode_utf8(&mut tmp);
 
+        let mut txt_ctx = text2::TEXT_CTX.get().await;
         let mut editor = self.editor.lock().await;
-        editor.driver(|mut drv| drv.insert_or_replace_selection(&key_str));
+        let mut drv = editor.driver(&mut txt_ctx).await.unwrap();
+        drv.insert_or_replace_selection(&key_str);
     }
 
     async fn handle_shortcut(
@@ -556,37 +558,38 @@ impl ChatEdit {
         #[cfg(target_os = "macos")]
         let action_mod = mods.logo;
 
+        let mut txt_ctx = text2::TEXT_CTX.get().await;
+        let mut editor = self.editor.lock().await;
+        let mut drv = editor.driver(&mut txt_ctx).await.unwrap();
+
         match key {
             'a' => {
                 if action_mod {
-                    {
-                        //let mut editor = self.editor.lock();
-                        //let mut drv = editor.driver();
-                        //drv.select_all();
-                    }
-
-                    self.redraw().await;
-                    return true
+                    drv.select_all();
                 }
             }
             'c' => {
                 if action_mod {
-                    return true
+                    if let Some(text) = editor.selected_text() {
+                        miniquad::window::clipboard_set(text);
+                    }
                 }
             }
             'v' => {
                 if action_mod {
-                    //if let Some(text) = miniquad::window::clipboard_get() {
-                    //    let mut editor = self.editor.lock();
-                    //    let mut drv = editor.driver();
-                    //    drv.insert_or_replace_selection(&text);
-                    //}
-                    return true
+                    if let Some(text) = miniquad::window::clipboard_get() {
+                        drv.insert_or_replace_selection(&text);
+                    }
                 }
             }
-            _ => {}
+            _ => return false,
         }
-        false
+
+        drop(editor);
+        drop(txt_ctx);
+
+        self.redraw().await;
+        true
     }
 
     async fn handle_key(
@@ -595,114 +598,114 @@ impl ChatEdit {
         mods: &KeyMods,
         atom: &mut PropertyAtomicGuard,
     ) -> bool {
-        t!("handle_key({:?}, {:?})", key, mods);
+        #[cfg(not(target_os = "macos"))]
+        let action_mod = mods.ctrl;
+
+        #[cfg(target_os = "macos")]
+        let action_mod = mods.logo;
+
+        t!("handle_key({:?}, {:?}) action_mod={action_mod}", key, mods);
+
+        let mut txt_ctx = text2::TEXT_CTX.get().await;
+        let mut editor = self.editor.lock().await;
+        let mut drv = editor.driver(&mut txt_ctx).await.unwrap();
+
         match key {
             KeyCode::Left => {
-                //if !self.adjust_cursor(&mods, |editable| editable.move_cursor(-1), atom) {
-                //    return false
-                //}
-                self.pause_blinking();
-                //self.apply_cursor_scrolling();
-                self.redraw().await;
-                return true
+                if action_mod {
+                    if mods.shift {
+                        drv.select_word_left();
+                    } else {
+                        drv.move_word_left();
+                    }
+                } else if mods.shift {
+                    drv.select_left();
+                } else {
+                    drv.move_left();
+                }
             }
             KeyCode::Right => {
-                //if !self.adjust_cursor(&mods, |editable| editable.move_cursor(1), atom) {
-                //    return false
-                //}
-                self.pause_blinking();
-                //self.apply_cursor_scrolling();
-                self.redraw().await;
-                return true
-            }
-            KeyCode::Kp0 => {
-                self.insert_char('0').await;
-                return true
-            }
-            KeyCode::Kp1 => {
-                self.insert_char('1').await;
-                return true
-            }
-            KeyCode::Kp2 => {
-                self.insert_char('2').await;
-                return true
-            }
-            KeyCode::Kp3 => {
-                self.insert_char('3').await;
-                return true
-            }
-            KeyCode::Kp4 => {
-                self.insert_char('4').await;
-                return true
-            }
-            KeyCode::Kp5 => {
-                self.insert_char('5').await;
-                return true
-            }
-            KeyCode::Kp6 => {
-                self.insert_char('6').await;
-                return true
-            }
-            KeyCode::Kp7 => {
-                self.insert_char('7').await;
-                return true
-            }
-            KeyCode::Kp8 => {
-                self.insert_char('8').await;
-                return true
+                if action_mod {
+                    if mods.shift {
+                        drv.select_word_right();
+                    } else {
+                        drv.move_word_right();
+                    }
+                } else if mods.shift {
+                    drv.select_right();
+                } else {
+                    drv.move_right();
+                }
             }
-            KeyCode::Kp9 => {
-                self.insert_char('9').await;
-                return true
+            KeyCode::Up => {
+                if mods.shift {
+                    drv.select_up();
+                } else {
+                    drv.move_up();
+                }
             }
-            KeyCode::KpDecimal => {
-                self.insert_char('.').await;
-                return true
+            KeyCode::Down => {
+                if mods.shift {
+                    drv.select_down();
+                } else {
+                    drv.move_down();
+                }
             }
             KeyCode::Enter | KeyCode::KpEnter => {
                 if mods.shift {
-                    // Does nothing for now. Later will enable multiline.
+                    drv.insert_or_replace_selection("\n");
                 }
             }
             KeyCode::Delete => {
-                //self.delete(0, 1, atom);
-                //self.clamp_scroll(&mut self.text_wrap.lock(), atom);
-                self.pause_blinking();
-                self.redraw().await;
-                return true
+                if action_mod {
+                    drv.delete_word();
+                } else {
+                    drv.delete();
+                }
             }
             KeyCode::Backspace => {
-                //self.delete(1, 0, atom);
-                //self.clamp_scroll(&mut self.text_wrap.lock(), atom);
-                t!("KeyCode::Backspace");
-                {
-                    //let mut editor = self.editor.lock();
-                    //t!("  editor (before): {editor:?}");
-                    //let mut drv = editor.driver();
-                    //drv.backdelete();
-                    //t!("  editor (after): {editor:?}");
+                if action_mod {
+                    drv.backdelete_word();
+                } else {
+                    drv.backdelete();
                 }
-                self.pause_blinking();
-                self.redraw().await;
-                return true
             }
             KeyCode::Home => {
-                //self.adjust_cursor(&mods, |editable| editable.move_start(), atom);
-                self.pause_blinking();
-                //self.apply_cursor_scrolling();
-                self.redraw().await;
-                return true
+                if action_mod {
+                    if mods.shift {
+                        drv.select_to_text_start();
+                    } else {
+                        drv.move_to_text_start();
+                    }
+                } else if mods.shift {
+                    drv.select_to_line_start();
+                } else {
+                    drv.move_to_line_start();
+                }
             }
             KeyCode::End => {
-                //self.adjust_cursor(&mods, |editable| editable.move_end(), atom);
-                self.pause_blinking();
-                //self.apply_cursor_scrolling();
-                self.redraw().await;
-                return true
+                if action_mod {
+                    if mods.shift {
+                        drv.select_to_text_end();
+                    } else {
+                        drv.move_to_text_end();
+                    }
+                } else if mods.shift {
+                    drv.select_to_line_end();
+                } else {
+                    drv.move_to_line_end();
+                }
             }
-            _ => {}
+            _ => return false,
         }
-        false
+
+        drop(editor);
+        drop(txt_ctx);
+
+        self.pause_blinking();
+        self.redraw().await;
+
+        return true
     }
 
     /*
@@ -1217,15 +1220,9 @@ impl ChatEdit {
 
         let mut cursor_instrs = vec![];
 
-        let Some(cursor_pos) = self.editor.lock().await.get_cursor_pos() else { return vec![] };
-        //let cursor_pos = self.get_cursor_pos();
+        let Some(mut cursor_pos) = self.editor.lock().await.get_cursor_pos() else { return vec![] };
 
-        // There is some mess here since ApplyView is in abs screen coords but should be
-        // relative, and also work together with Move. We will fix this later in gfx subsys.
-        let mut view_rect = self.rect.get();
-        view_rect.h = self.max_height.get();
-
-        cursor_instrs.push(GfxDrawInstruction::ApplyView(view_rect));
+        cursor_pos.y += self.padding_top();
         cursor_instrs.push(GfxDrawInstruction::Move(cursor_pos));
 
         let cursor_mesh = {
@@ -1241,15 +1238,97 @@ impl ChatEdit {
         cursor_instrs
     }
 
-    async fn regen_mesh(&self) -> Vec<GfxDrawInstruction> {
+    async fn regen_txt_mesh(&self) -> Vec<GfxDrawInstruction> {
         let font_size = self.font_size.get();
         let text_color = self.text_color.get();
         let window_scale = self.window_scale.get();
         let lineheight = self.lineheight.get();
+        let padding_top = self.padding_top();
+        let padding_bottom = self.padding_bottom();
+
+        let mut instrs = vec![];
+        // BUG FIXME SHOULDNT NEED THIS!
+        instrs.push(GfxDrawInstruction::Move(Point::zero()));
+
+        if self.debug.get() {
+            let mut rect = self.rect.get();
+            rect.x = 0.;
+            rect.y = 0.;
+            let mut mesh = MeshBuilder::new();
+            mesh.draw_outline(&rect, [0., 1., 0., 1.], 1.);
+            instrs.push(GfxDrawInstruction::Draw(mesh.alloc(&self.render_api).draw_untextured()));
+
+            rect.y = padding_top;
+            rect.h -= padding_top + padding_bottom;
+            let mut mesh = MeshBuilder::new();
+            mesh.draw_outline(&rect, [0., 1., 0., 0.5], 1.);
+            instrs.push(GfxDrawInstruction::Draw(mesh.alloc(&self.render_api).draw_untextured()));
+        }
+
+        let mut inner_pos = Point::zero();
+        inner_pos.y += padding_top;
+        inner_pos.y -= self.scroll.get();
+        instrs.push(GfxDrawInstruction::Move(inner_pos));
 
         let editor = self.editor.lock().await;
         let layout = editor.layout();
-        text2::render_layout(layout, &self.render_api)
+        let mut render_instrs = text2::render_layout(layout, &self.render_api);
+        instrs.append(&mut render_instrs);
+
+        instrs
+    }
+
+    fn bounded_height(&self, mut height: f32) -> f32 {
+        let min_height = self.min_height.get();
+        let max_height = self.max_height.get();
+
+        if height < min_height {
+            height = min_height;
+        }
+        if height > max_height {
+            height = max_height;
+        }
+
+        height
+    }
+
+    async fn eval_rect(&self, atom: &mut PropertyAtomicGuard) {
+        let parent_rect = self.parent_rect.lock().clone().unwrap();
+        // First we evaluate the width based off the parent dimensions
+        self.rect
+            .eval_with(
+                vec![2],
+                vec![
+                    ("parent_w".to_string(), parent_rect.w),
+                    ("parent_h".to_string(), parent_rect.h),
+                ],
+            )
+            .unwrap();
+
+        // Use the width to adjust the height calcs
+        let rect_w = self.rect.get_width();
+        let inner_height = {
+            let mut editor = self.editor.lock().await;
+            editor.set_width(rect_w);
+            editor.refresh().await;
+            editor.height()
+        };
+        let content_height = inner_height + self.padding_top() + self.padding_bottom();
+        let rect_h = self.bounded_height(content_height);
+        self.rect.prop().set_f32(atom, Role::Internal, 3, rect_h);
+
+        // Finally calculate the position
+        self.rect
+            .eval_with(
+                vec![0, 1],
+                vec![
+                    ("parent_w".to_string(), parent_rect.w),
+                    ("parent_h".to_string(), parent_rect.h),
+                    ("rect_w".to_string(), rect_w),
+                    ("rect_h".to_string(), rect_h),
+                ],
+            )
+            .unwrap();
     }
 
     async fn make_draw_calls(
@@ -1257,20 +1336,11 @@ impl ChatEdit {
         trace_id: u32,
         atom: &mut PropertyAtomicGuard,
     ) -> Option<DrawUpdate> {
-        let parent_rect = self.parent_rect.lock().clone().unwrap();
-        self.rect.eval_with(
-            vec![2],
-            vec![("parent_w".to_string(), parent_rect.w), ("parent_h".to_string(), parent_rect.h)],
-        );
-        self.rect.prop().set_f32(atom, Role::Internal, 3, 2000.);
-
-        //let text_mesh = self.regen_text_mesh(trace_id, atom);
-        let cursor_instrs = self.get_cursor_instrs().await;
+        self.eval_rect(atom).await;
 
         let rect = self.rect.get();
-
-        let mut instrs = vec![GfxDrawInstruction::Move(rect.pos())];
-        instrs.append(&mut self.regen_mesh().await);
+        let cursor_instrs = self.get_cursor_instrs().await;
+        let txt_instrs = self.regen_txt_mesh().await;
 
         Some(DrawUpdate {
             key: self.main_dc_key,
@@ -1278,14 +1348,14 @@ impl ChatEdit {
                 (
                     self.main_dc_key,
                     GfxDrawCall {
-                        instrs: vec![],
+                        instrs: vec![GfxDrawInstruction::ApplyView(rect)],
                         dcs: vec![self.text_dc_key, self.cursor_dc_key],
                         z_index: self.z_index.get(),
                     },
                 ),
                 (
                     self.text_dc_key,
-                    GfxDrawCall { instrs, dcs: vec![], z_index: self.z_index.get() },
+                    GfxDrawCall { instrs: txt_instrs, dcs: vec![], z_index: self.z_index.get() },
                 ),
                 (
                     self.cursor_dc_key,
@@ -1610,10 +1680,11 @@ impl UIObject for ChatEdit {
         // Move mouse pos within this widget
         self.abs_to_local(&mut mouse_pos);
 
+        /*
         let width = self.wrap_width();
 
-        /*
         {
+
             let mut text_wrap = self.text_wrap.lock();
             let cursor_pos = text_wrap.set_cursor_with_point(mouse_pos, width);
             self.update_cursor_pos(&mut text_wrap, atom);
@@ -1668,9 +1739,9 @@ impl UIObject for ChatEdit {
         // Move mouse pos within this widget
         self.abs_to_local(&mut mouse_pos);
 
+        /*
         let width = self.wrap_width();
 
-        /*
         {
             let mut text_wrap = self.text_wrap.lock();
             let cursor_pos = text_wrap.set_cursor_with_point(mouse_pos, width);

+ 2 - 2
bin/app/src/ui/text.rs

@@ -32,7 +32,7 @@ use crate::{
     },
     scene::{Pimpl, SceneNodePtr, SceneNodeWeak},
     text::{self, GlyphPositionIter, TextShaper, TextShaperPtr},
-    text2,
+    text2::{self, TEXT_CTX},
     util::unixtime,
     ExecutorPtr,
 };
@@ -124,7 +124,7 @@ impl Text {
         let window_scale = self.window_scale.get();
 
         let layout = {
-            let mut txt_ctx = text2::get_ctx().await;
+            let mut txt_ctx = TEXT_CTX.get().await;
             txt_ctx.make_layout(&text, text_color, font_size, 0., window_scale, None)
         };
 

+ 1 - 1
src/system/condvar.rs

@@ -52,7 +52,7 @@ struct CondVarState {
 }
 
 impl CondVar {
-    pub fn new() -> Self {
+    pub const fn new() -> Self {
         Self { state: Mutex::new(CondVarState { is_awake: false, wakers: Vec::new() }) }
     }