app: various cleanups to Editor used by BaseEdit with main one being moving from async to purely sync. other changes:

* Removed `Option` wrapper from editor
* Removed `EditorHandle` wrapper
* Changed all editor locks to synchronous
* Made all Editor methods synchronous
* Created `ParleyDriverWrapper`. This makes using the driver much easier.
This commit is contained in:
darkfi
2026-01-06 15:27:39 +01:00
parent 68e73036af
commit 38e5829196
6 changed files with 173 additions and 229 deletions

View File

@@ -73,16 +73,16 @@ impl Editor {
}
}
pub async fn on_text_prop_changed(&mut self) {
pub fn on_text_prop_changed(&mut self) {
// Update GameTextInput state
self.state.text = self.text.get();
self.state.select = (0, 0);
self.state.compose = None;
self.input.set_state(self.state.clone());
// Refresh our layout
self.refresh().await;
self.refresh();
}
pub async fn on_buffer_changed(&mut self, atom: &mut PropertyAtomicGuard) {
pub fn on_buffer_changed(&mut self, atom: &mut PropertyAtomicGuard) {
// Only refresh layout if text content actually changed
// Avoid triggering expensive recomputes of layout and property tree.
let old_text = self.text.get();
@@ -90,7 +90,7 @@ impl Editor {
return
}
self.refresh().await;
self.refresh();
// Update the text attribute
self.text.set(atom, &self.state.text);
}
@@ -102,7 +102,7 @@ impl Editor {
self.input.hide();
}
pub async fn refresh(&mut self) {
pub fn refresh(&mut self) {
let font_size = self.font_size.get();
let text_color = self.text_color.get();
let window_scale = self.window_scale.get();
@@ -139,7 +139,7 @@ impl Editor {
self.input.set_select(cursor_idx, cursor_idx);
}
pub async fn select_word_at_point(&mut self, pos: Point) {
pub fn select_word_at_point(&mut self, pos: Point) {
let select = parley::Selection::word_from_point(&self.layout, pos.x, pos.y);
assert!(!select.is_collapsed());
let select = select.text_range();
@@ -163,7 +163,7 @@ impl Editor {
Point::new(cursor_rect.x0 as f32, cursor_rect.y0 as f32)
}
pub async fn insert(&mut self, txt: &str, atom: &mut PropertyAtomicGuard) {
pub fn insert(&mut self, txt: &str, atom: &mut PropertyAtomicGuard) {
// TODO: need to verify this is correct
// Insert text by updating the state
self.state.text.push_str(txt);
@@ -214,7 +214,7 @@ impl Editor {
parley::Selection::new(anchor, focus)
}
pub async fn set_selection(&mut self, select_start: usize, select_end: usize) {
pub fn set_selection(&mut self, select_start: usize, select_end: usize) {
assert!(select_start <= self.state.text.len());
assert!(select_end <= self.state.text.len());
assert_eq!(self.state.text, self.text.get());

View File

@@ -21,6 +21,7 @@ mod android;
mod driver;
#[cfg(target_os = "android")]
pub use android::Editor;
pub use driver::ParleyDriverWrapper;
#[cfg(not(target_os = "android"))]
mod parley;

View File

@@ -57,19 +57,19 @@ impl Editor {
pub fn focus(&self) {}
pub fn unfocus(&self) {}
pub async fn on_text_prop_changed(&mut self) {
pub fn on_text_prop_changed(&mut self) {
// Get modified text property
let txt = self.text.get();
// Update Parley text buffer
self.editor.set_text(&txt);
// Refresh our layout
self.refresh().await;
self.refresh();
}
pub async fn on_buffer_changed(&mut self, atom: &mut PropertyAtomicGuard) {
pub fn on_buffer_changed(&mut self, atom: &mut PropertyAtomicGuard) {
self.text.set(atom, self.editor.raw_text());
}
pub async fn refresh(&mut self) {
pub fn refresh(&mut self) {
let font_size = self.font_size.get();
let text_color = self.text_color.get();
let window_scale = self.window_scale.get();
@@ -99,7 +99,7 @@ impl Editor {
pub fn move_to_pos(&self, _pos: Point) {
unimplemented!()
}
pub async fn select_word_at_point(&mut self, _pos: Point) {
pub fn select_word_at_point(&mut self, _pos: Point) {
unimplemented!()
}
@@ -109,9 +109,9 @@ impl Editor {
cursor_pos
}
pub async fn insert(&mut self, txt: &str, atom: &mut PropertyAtomicGuard) {
pub fn insert(&mut self, txt: &str, atom: &mut PropertyAtomicGuard) {
self.driver().insert_or_replace_selection(&txt);
self.on_buffer_changed(atom).await;
self.on_buffer_changed(atom);
}
pub fn driver(&mut self) -> ParleyDriverWrapper {
@@ -137,7 +137,7 @@ impl Editor {
}
/// Android uses byte indexes whereas parley has its own things. So this API is a compromise
/// between them both.
pub async fn set_selection(&mut self, select_start: usize, select_end: usize) {
pub fn set_selection(&mut self, select_start: usize, select_end: usize) {
self.driver().select_byte_range(select_start, select_end);
}

View File

@@ -16,14 +16,18 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use std::{cell::RefCell, ops::Range, sync::{Arc, LazyLock}};
use parley::fontique::{Collection, CollectionOptions, SourceCache, SourceCacheOptions};
use std::{
cell::RefCell,
ops::Range,
sync::{Arc, LazyLock},
};
use crate::{mesh::Color, util::spawn_thread};
pub mod atlas;
mod editor;
pub use editor::Editor;
pub use editor::{Editor, ParleyDriverWrapper};
mod render;
pub use render::{render_layout, render_layout_with_opts, DebugRenderOptions};

View File

@@ -15,7 +15,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use async_lock::Mutex as AsyncMutex;
use async_trait::async_trait;
use atomic_float::AtomicF32;
use parking_lot::Mutex as SyncMutex;
@@ -27,8 +26,6 @@ use crate::{
text::Editor,
};
use super::EditorHandle;
//macro_rules! t { ($($arg:tt)*) => { trace!(target: "ui::edit::behave", $($arg)*); } }
pub enum BaseEditType {
@@ -87,17 +84,12 @@ pub(super) struct MultiLine {
pub padding: PropertyPtr,
pub cursor_descent: PropertyFloat32,
pub parent_rect: Arc<SyncMutex<Option<Rectangle>>>,
pub editor: Arc<AsyncMutex<Option<Editor>>>,
pub editor: Arc<SyncMutex<Editor>>,
pub content_height: AtomicF32,
pub scroll: Arc<AtomicF32>,
}
impl MultiLine {
/// Lazy-initializes the editor and returns a handle to it
async fn lock_editor<'a>(&'a self) -> EditorHandle<'a> {
EditorHandle { guard: self.editor.lock().await }
}
fn bounded_height(&self, height: f32) -> f32 {
height.clamp(self.min_height.get(), self.max_height.get())
}
@@ -112,7 +104,7 @@ impl MultiLine {
/// Gets the real cursor pos within the rect.
async fn get_cursor_pos(&self) -> Point {
// This is the position within the content.
let cursor_pos = self.lock_editor().await.get_cursor_pos();
let cursor_pos = self.editor.lock().get_cursor_pos();
// Apply the inner padding
cursor_pos + self.inner_pos()
}
@@ -140,9 +132,9 @@ impl EditorBehavior for MultiLine {
// Use the width to adjust the height calcs
let rect_w = self.rect.get_width() - pad_left - pad_right;
let content_height = {
let mut editor = self.lock_editor().await;
let mut editor = self.editor.lock();
editor.set_width(rect_w);
editor.refresh().await;
editor.refresh();
editor.height()
};
self.content_height.store(content_height, Ordering::Relaxed);
@@ -242,24 +234,17 @@ pub(super) struct SingleLine {
pub padding: PropertyPtr,
pub cursor_width: PropertyFloat32,
pub parent_rect: Arc<SyncMutex<Option<Rectangle>>>,
pub editor: Arc<AsyncMutex<Option<Editor>>>,
pub editor: Arc<SyncMutex<Editor>>,
pub content_height: AtomicF32,
pub scroll: Arc<AtomicF32>,
}
impl SingleLine {
/// Lazy-initializes the editor and returns a handle to it
async fn lock_editor<'a>(&'a self) -> EditorHandle<'a> {
EditorHandle { guard: self.editor.lock().await }
}
}
#[async_trait]
impl EditorBehavior for SingleLine {
async fn eval_rect(&self, atom: &mut PropertyAtomicGuard) {
let content_height = {
let mut editor = self.lock_editor().await;
editor.refresh().await;
let mut editor = self.editor.lock();
editor.refresh();
editor.height()
};
self.content_height.store(content_height, Ordering::Relaxed);
@@ -283,7 +268,7 @@ impl EditorBehavior for SingleLine {
let pad_left = self.padding.get_f32(3).unwrap();
let scroll = self.scroll.load(Ordering::Relaxed);
let rect_w = self.rect.get_width() - pad_right;
let cursor_x0 = self.lock_editor().await.get_cursor_pos().x + pad_left;
let cursor_x0 = self.editor.lock().get_cursor_pos().x + pad_left;
let cursor_x1 = cursor_x0 + self.cursor_width.get();
if cursor_x0 < scroll {
@@ -304,7 +289,7 @@ impl EditorBehavior for SingleLine {
let pad_right = self.padding.get_f32(1).unwrap();
let pad_left = self.padding.get_f32(3).unwrap();
let rect_w = self.rect.get_width();
let content_w = self.lock_editor().await.width() + self.cursor_width.get();
let content_w = self.editor.lock().width() + self.cursor_width.get();
(pad_left + pad_right + content_w - rect_w).max(0.)
}

View File

@@ -16,7 +16,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use async_lock::Mutex as AsyncMutex;
use async_trait::async_trait;
use atomic_float::AtomicF32;
use darkfi::system::msleep;
@@ -179,23 +178,6 @@ impl std::fmt::Debug for Editor {
}
*/
struct EditorHandle<'a> {
guard: async_lock::MutexGuard<'a, Option<Editor>>,
}
impl<'a> Deref for EditorHandle<'a> {
type Target = Editor;
fn deref(&self) -> &Self::Target {
self.guard.as_ref().unwrap()
}
}
impl<'a> DerefMut for EditorHandle<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.guard.as_mut().unwrap()
}
}
pub type BaseEditPtr = Arc<BaseEdit>;
pub struct BaseEdit {
@@ -258,7 +240,7 @@ pub struct BaseEdit {
parent_rect: Arc<SyncMutex<Option<Rectangle>>>,
is_mouse_hover: AtomicBool,
editor: Arc<AsyncMutex<Option<Editor>>>,
editor: Arc<SyncMutex<Editor>>,
behave: Box<dyn EditorBehavior>,
}
@@ -309,8 +291,16 @@ impl BaseEdit {
let debug = PropertyBool::wrap(node_ref, Role::Internal, "debug", 0).unwrap();
let parent_rect = Arc::new(SyncMutex::new(None));
let editor = Arc::new(AsyncMutex::new(None));
let scroll = Arc::new(AtomicF32::new(0.));
let editor = Arc::new(SyncMutex::new(Editor::new(
text.clone(),
font_size.clone(),
text_color.clone(),
window_scale.clone(),
lineheight.clone(),
)));
let behave: Box<dyn EditorBehavior> = match edit_type {
BaseEditType::SingleLine => Box::new(SingleLine {
rect: rect.clone(),
@@ -420,16 +410,11 @@ impl BaseEdit {
/// Gets the real cursor pos within the rect.
async fn get_cursor_pos(&self) -> Point {
// This is the position within the content.
let cursor_pos = self.lock_editor().await.get_cursor_pos();
let cursor_pos = self.editor.lock().get_cursor_pos();
// Apply the inner padding
cursor_pos + self.behave.inner_pos()
}
/// Lazy-initializes the editor and returns a handle to it
async fn lock_editor<'a>(&'a self) -> EditorHandle<'a> {
EditorHandle { guard: self.editor.lock().await }
}
fn regen_cursor_mesh(&self) -> DrawMesh {
let cursor_width = self.cursor_width.get();
let cursor_ascent = self.cursor_ascent.get();
@@ -516,7 +501,7 @@ impl BaseEdit {
match key {
'a' => {
if action_mod {
let mut editor = self.lock_editor().await;
let mut editor = self.editor.lock();
editor.driver().select_all();
if let Some(seltext) = editor.selected_text() {
self.select_text.clone().set_str(atom, Role::Internal, 0, seltext).unwrap();
@@ -525,7 +510,7 @@ impl BaseEdit {
}
'c' => {
if action_mod {
let editor = self.lock_editor().await;
let editor = self.editor.lock();
if let Some(txt) = editor.selected_text() {
miniquad::window::clipboard_set(&txt);
}
@@ -534,7 +519,7 @@ impl BaseEdit {
'v' => {
if action_mod {
if let Some(txt) = miniquad::window::clipboard_get() {
self.insert(&txt, atom).await;
self.editor.lock().insert(&txt, atom);
// Maybe insert should call this?
self.behave.apply_cursor_scroll().await;
}
@@ -556,135 +541,132 @@ impl BaseEdit {
) -> bool {
#[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 editor = self.editor.lock();
match key {
KeyCode::Left => {
if action_mod {
if mods.shift {
editor.driver().select_word_left();
} else {
editor.driver().move_word_left();
}
} else if mods.shift {
editor.driver().select_left();
} else {
editor.driver().move_left();
}
}
KeyCode::Right => {
if action_mod {
if mods.shift {
editor.driver().select_word_right();
} else {
editor.driver().move_word_right();
}
} else if mods.shift {
editor.driver().select_right();
} else {
editor.driver().move_right();
}
}
KeyCode::Up => {
if mods.shift {
editor.driver().select_up();
} else {
editor.driver().move_up();
}
}
KeyCode::Down => {
if mods.shift {
editor.driver().select_down();
} else {
editor.driver().move_down();
}
}
KeyCode::Enter | KeyCode::KpEnter => {
if mods.shift {
if self.behave.allow_endl() {
editor.driver().insert_or_replace_selection("\n");
editor.on_buffer_changed(atom);
}
} else {
//let node = self.node.upgrade().unwrap();
//node.trigger("enter_pressed", vec![]).await.unwrap();
return false;
}
}
KeyCode::Delete => {
if action_mod {
editor.driver().delete_word();
} else {
editor.driver().delete();
}
editor.on_buffer_changed(atom);
}
KeyCode::Backspace => {
if action_mod {
editor.driver().backdelete_word();
} else {
editor.driver().backdelete();
}
editor.on_buffer_changed(atom);
}
KeyCode::Home => {
if action_mod {
if mods.shift {
editor.driver().select_to_text_start();
} else {
editor.driver().move_to_text_start();
}
} else if mods.shift {
editor.driver().select_to_line_start();
} else {
editor.driver().move_to_line_start();
}
}
KeyCode::End => {
if action_mod {
if mods.shift {
editor.driver().select_to_text_end();
} else {
editor.driver().move_to_text_end();
}
} else if mods.shift {
editor.driver().select_to_line_end();
} else {
editor.driver().move_to_line_end();
}
}
_ => return false,
}
let mut editor = self.lock_editor().await;
match key {
KeyCode::Left => {
if action_mod {
if mods.shift {
editor.driver().select_word_left();
} else {
editor.driver().move_word_left();
}
} else if mods.shift {
editor.driver().select_left();
} else {
editor.driver().move_left();
}
if let Some(seltext) = editor.selected_text() {
self.select_text.clone().set_str(atom, Role::Internal, 0, seltext).unwrap();
} else {
self.select_text.clone().set_null(atom, Role::Internal, 0).unwrap();
}
KeyCode::Right => {
if action_mod {
if mods.shift {
editor.driver().select_word_right();
} else {
editor.driver().move_word_right();
}
} else if mods.shift {
editor.driver().select_right();
} else {
editor.driver().move_right();
}
}
KeyCode::Up => {
if mods.shift {
editor.driver().select_up();
} else {
editor.driver().move_up();
}
}
KeyCode::Down => {
if mods.shift {
editor.driver().select_down();
} else {
editor.driver().move_down();
}
}
KeyCode::Enter | KeyCode::KpEnter => {
if mods.shift {
if self.behave.allow_endl() {
editor.driver().insert_or_replace_selection("\n");
editor.on_buffer_changed(atom).await;
}
} else {
//let node = self.node.upgrade().unwrap();
//node.trigger("enter_pressed", vec![]).await.unwrap();
return false;
}
}
KeyCode::Delete => {
if action_mod {
editor.driver().delete_word();
} else {
editor.driver().delete();
}
editor.on_buffer_changed(atom).await;
}
KeyCode::Backspace => {
if action_mod {
editor.driver().backdelete_word();
} else {
editor.driver().backdelete();
}
editor.on_buffer_changed(atom).await;
}
KeyCode::Home => {
if action_mod {
if mods.shift {
editor.driver().select_to_text_start();
} else {
editor.driver().move_to_text_start();
}
} else if mods.shift {
editor.driver().select_to_line_start();
} else {
editor.driver().move_to_line_start();
}
}
KeyCode::End => {
if action_mod {
if mods.shift {
editor.driver().select_to_text_end();
} else {
editor.driver().move_to_text_end();
}
} else if mods.shift {
editor.driver().select_to_line_end();
} else {
editor.driver().move_to_line_end();
}
}
_ => return false,
}
if let Some(seltext) = editor.selected_text() {
self.select_text.clone().set_str(atom, Role::Internal, 0, seltext).unwrap();
} else {
self.select_text.clone().set_null(atom, Role::Internal, 0).unwrap();
}
drop(editor);
self.eval_rect().await;
self.behave.apply_cursor_scroll().await;
self.pause_blinking();
self.redraw(atom).await;
return true
true
}
/// This will select the entire word rather than move the cursor to that location
async fn start_touch_select(&self, touch_pos: Point, atom: &mut PropertyAtomicGuard) {
t!("start_touch_select({touch_pos:?})");
let mut editor = self.lock_editor().await;
editor.select_word_at_point(touch_pos).await;
editor.refresh().await;
let mut editor = self.editor.lock();
editor.select_word_at_point(touch_pos);
editor.refresh();
let seltext = editor.selected_text().unwrap();
d!("Selected {seltext:?} from {touch_pos:?}");
@@ -717,7 +699,7 @@ impl BaseEdit {
true
}
async fn get_select_handles(&self, editor: &Editor) -> Option<(Point, Point)> {
fn get_select_handles(&self, editor: &Editor) -> Option<(Point, Point)> {
let layout = editor.layout();
let sel = editor.selection(1);
@@ -732,10 +714,8 @@ impl BaseEdit {
}
async fn try_handle_drag(&self, mut touch_pos: Point) -> bool {
let editor = self.lock_editor().await;
let Some((mut first, mut last)) = self.get_select_handles(&editor).await else {
return false
};
let editor = self.editor.lock();
let Some((mut first, mut last)) = self.get_select_handles(&editor) else { return false };
self.abs_to_local(&mut touch_pos);
t!("localize touch_pos = {touch_pos:?}");
@@ -878,9 +858,9 @@ impl BaseEdit {
async fn touch_set_cursor_pos(&self, atom: &mut PropertyAtomicGuard, touch_pos: Point) {
t!("touch_set_cursor_pos({touch_pos:?})");
let mut editor = self.lock_editor().await;
let mut editor = self.editor.lock();
editor.move_to_pos(touch_pos);
editor.refresh().await;
editor.refresh();
drop(editor);
self.pause_blinking();
@@ -926,7 +906,7 @@ impl BaseEdit {
}
let seltext = {
let mut editor = self.lock_editor().await;
let mut editor = self.editor.lock();
// The below lines rely on parley driver which android does not use
//let mut txt_ctx = text::TEXT_CTX.get().await;
@@ -970,8 +950,8 @@ impl BaseEdit {
assert!(start < end);
//t!("handle_select(): set_selection({start}, {end})");
editor.set_selection(start, end).await;
editor.refresh().await;
editor.set_selection(start, end);
editor.refresh();
editor.selected_text()
};
@@ -1096,7 +1076,7 @@ impl BaseEdit {
async fn regen_txt_mesh(&self) -> Vec<DrawInstruction> {
let mut instrs = vec![DrawInstruction::Move(self.behave.inner_pos())];
let editor = self.lock_editor().await;
let editor = self.editor.lock();
let layout = editor.layout();
let mut render_instrs =
@@ -1109,7 +1089,7 @@ impl BaseEdit {
async fn regen_select_mesh(&self) -> Vec<DrawInstruction> {
let mut instrs = vec![DrawInstruction::Move(self.behave.inner_pos())];
let editor = self.lock_editor().await;
let editor = self.editor.lock();
let layout = editor.layout();
let sel = editor.selection(1);
@@ -1131,8 +1111,8 @@ impl BaseEdit {
//t!("regen_phone_select_handle_mesh() [DISABLED]");
return vec![]
}
let editor = self.lock_editor().await;
let (first, last) = self.get_select_handles(&editor).await.unwrap();
let editor = self.editor.lock();
let (first, last) = self.get_select_handles(&editor).unwrap();
let sel = editor.selection(1);
assert!(!sel.is_collapsed());
@@ -1214,11 +1194,6 @@ impl BaseEdit {
}
}
async fn insert(&self, txt: &str, atom: &mut PropertyAtomicGuard) {
let mut editor = self.lock_editor().await;
editor.insert(txt, atom).await;
}
async fn process_insert_text_method(me: &Weak<Self>, sub: &MethodCallSub) -> bool {
let Ok(method_call) = sub.receive().await else {
debug!(target: "ui::chatedit", "Event relayer closed");
@@ -1246,7 +1221,7 @@ impl BaseEdit {
let atom =
&mut self_.render_api.make_guard(gfxtag!("BaseEdit::process_insert_text_method"));
self_.insert(&text, atom).await;
self_.editor.lock().insert(&text, atom);
self_.eval_rect().await;
self_.redraw(atom).await;
true
@@ -1267,8 +1242,7 @@ impl BaseEdit {
panic!("self destroyed before insert_text_method_task was stopped!");
};
let mut editor = self_.lock_editor().await;
editor.focus();
self_.editor.lock().focus();
true
}
async fn process_unfocus_method(me: &Weak<Self>, sub: &MethodCallSub) -> bool {
@@ -1286,8 +1260,7 @@ impl BaseEdit {
panic!("self destroyed before insert_text_method_task was stopped!");
};
let mut editor = self_.lock_editor().await;
editor.unfocus();
self_.editor.lock().unfocus();
true
}
@@ -1300,7 +1273,7 @@ impl BaseEdit {
t!("handle_android_event({state:?})");
let atom = &mut self.render_api.make_guard(gfxtag!("BaseEdit::handle_android_event"));
let mut editor = self.lock_editor().await;
let mut editor = self.editor.lock();
// Diff old and new state so we know what changed
let is_text_changed = editor.state.text != state.text;
let is_select_changed = editor.state.select != state.select;
@@ -1357,22 +1330,7 @@ impl UIObject for BaseEdit {
self.priority.get()
}
fn init(&self) {
let mut guard = self.editor.lock_blocking();
assert!(guard.is_none());
let editor = Editor::new(
self.text.clone(),
self.font_size.clone(),
self.text_color.clone(),
self.window_scale.clone(),
self.lineheight.clone(),
);
// For Android you can do this:
//let atom = &mut PropertyAtomicGuard::none();
//self.text.set(atom, "the quick brown fox jumped over the");
//smol::block_on(editor.on_text_prop_changed());
*guard = Some(editor);
}
fn init(&self) {}
async fn start(self: Arc<Self>, ex: ExecutorPtr) {
let me = Arc::downgrade(&self);
@@ -1414,7 +1372,7 @@ impl UIObject for BaseEdit {
self_.redraw(atom).await;
}
async fn set_text(self_: Arc<BaseEdit>, batch: BatchGuardPtr) {
self_.lock_editor().await.on_text_prop_changed().await;
self_.editor.lock().on_text_prop_changed();
let atom = &mut batch.spawn();
self_.eval_rect().await;
self_.redraw(atom).await;
@@ -1549,7 +1507,6 @@ impl UIObject for BaseEdit {
*self.parent_rect.lock() = None;
self.key_repeat.lock().clear();
*self.cursor_mesh.lock() = None;
*self.editor.lock_blocking() = None;
}
#[instrument(target = "ui::edit")]
@@ -1598,7 +1555,7 @@ impl UIObject for BaseEdit {
t!("Key {:?} has {} actions", key, actions);
let key_str = key.to_string().repeat(actions as usize);
self.insert(&key_str, atom).await;
self.editor.lock().insert(&key_str, atom);
self.eval_rect().await;
self.behave.apply_cursor_scroll().await;
self.redraw(atom).await;
@@ -1672,10 +1629,7 @@ impl UIObject for BaseEdit {
// Move mouse pos within this widget
self.abs_to_local(&mut mouse_pos);
{
let mut editor = self.lock_editor().await;
editor.driver().move_to_point(mouse_pos.x, mouse_pos.y);
}
self.editor.lock().driver().move_to_point(mouse_pos.x, mouse_pos.y);
if !self.select_text.is_null(0).unwrap() {
self.select_text.clone().set_null(atom, Role::Internal, 0).unwrap();