diff --git a/bin/app/src/gfx/mod.rs b/bin/app/src/gfx/mod.rs index 856ae5c75..56f520b44 100644 --- a/bin/app/src/gfx/mod.rs +++ b/bin/app/src/gfx/mod.rs @@ -621,6 +621,10 @@ impl<'a> RenderContext<'a> { for instr in overlay.instrs { match instr { + GfxDrawInstruction::Move(off) => { + self.cursor += off; + self.apply_model(); + } GfxDrawInstruction::Draw(mesh) => { if DEBUG_RENDER { d!(" draw_overlay({mesh:?})"); diff --git a/bin/app/src/text/editor/parley.rs b/bin/app/src/text/editor/parley.rs index 655329fc2..09bb87ae3 100644 --- a/bin/app/src/text/editor/parley.rs +++ b/bin/app/src/text/editor/parley.rs @@ -96,7 +96,7 @@ impl Editor { self.editor.try_layout().unwrap() } - pub fn move_to_pos(&self, _pos: Point) { + pub fn move_to_pos(&mut self, pos: Point) { unimplemented!() } pub fn select_word_at_point(&mut self, _pos: Point) { diff --git a/bin/app/src/ui/edit/mod.rs b/bin/app/src/ui/edit/mod.rs index 89304e6a0..c119b0a58 100644 --- a/bin/app/src/ui/edit/mod.rs +++ b/bin/app/src/ui/edit/mod.rs @@ -81,6 +81,7 @@ enum TouchStateAction { Started { pos: Point, instant: std::time::Instant }, StartSelect, Select, + Pasta, DragSelectHandle { side: isize }, ScrollVert { start_pos: Point, scroll_start: f32 }, SetCursorPos, @@ -480,15 +481,10 @@ impl BaseEdit { let atom = &mut batch.spawn(); // Cursor visibility will change so just redraw everything lol - self.redraw(atom).await; + self.redraw(atom); } - async fn handle_shortcut( - &self, - key: char, - mods: &KeyMods, - atom: &mut PropertyAtomicGuard, - ) -> bool { + fn handle_shortcut(&self, key: char, mods: &KeyMods, atom: &mut PropertyAtomicGuard) -> bool { t!("handle_shortcut({:?}, {:?})", key, mods); #[cfg(not(target_os = "macos"))] @@ -528,16 +524,11 @@ impl BaseEdit { } self.eval_rect(); - self.redraw(atom).await; + self.redraw(atom); true } - async fn handle_key( - &self, - key: &KeyCode, - mods: &KeyMods, - atom: &mut PropertyAtomicGuard, - ) -> bool { + fn handle_key(&self, key: &KeyCode, mods: &KeyMods, atom: &mut PropertyAtomicGuard) -> bool { #[cfg(not(target_os = "macos"))] let action_mod = mods.ctrl; #[cfg(target_os = "macos")] @@ -654,13 +645,13 @@ impl BaseEdit { self.eval_rect(); self.behave.apply_cursor_scroll(); self.pause_blinking(); - self.redraw(atom).await; + self.redraw(atom); 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) { + fn start_touch_select(&self, touch_pos: Point, atom: &mut PropertyAtomicGuard) { t!("start_touch_select({touch_pos:?})"); let mut editor = self.editor.lock(); @@ -680,7 +671,7 @@ impl BaseEdit { // } } - async fn handle_touch_start(&self, touch_pos: Point) -> bool { + fn handle_touch_start(&self, touch_pos: Point) -> bool { t!("handle_touch_start({touch_pos:?})"); let rect = self.rect.get(); @@ -781,18 +772,27 @@ impl BaseEdit { match &touch_state { TouchStateAction::Inactive => return false, TouchStateAction::StartSelect => { + let atom = &mut self + .render_api + .make_guard(gfxtag!("BaseEdit::TouchStateAction::StartSelect")); + if self.text.get().is_empty() { self.node().trigger("paste_request", vec![]).await.unwrap(); + /* + self.draw_pasta_overlay(atom.batch_id); + + d!("touch state: StartSelect -> Pasta"); + self.touch_info.lock().state = TouchStateAction::Pasta; + */ } else { self.abs_to_local(&mut touch_pos); - let atom = - &mut self.render_api.make_guard(gfxtag!("BaseEdit::handle_touch_move")); - self.start_touch_select(touch_pos, atom).await; - self.redraw_select(atom.batch_id).await; + self.start_touch_select(touch_pos, atom); + self.redraw_select(atom.batch_id); + + d!("touch state: StartSelect -> Select"); + self.touch_info.lock().state = TouchStateAction::Select; } - d!("touch state: StartSelect -> Select"); - self.touch_info.lock().state = TouchStateAction::Select; } TouchStateAction::DragSelectHandle { side } => { let rect = self.rect.get(); @@ -808,7 +808,7 @@ impl BaseEdit { // Stop any existing select/scroll process sel_sender.send(None).await.unwrap(); // Mouse is inside so just select the text once and be done. - self.handle_select(touch_pos, Some(*side)).await; + self.handle_select(touch_pos, Some(*side)); } } TouchStateAction::ScrollVert { start_pos, scroll_start } => { @@ -819,8 +819,10 @@ impl BaseEdit { return true } self.scroll.store(scroll, Ordering::Release); - let atom = &mut self.render_api.make_guard(gfxtag!("BaseEdit::handle_touch_move")); - self.redraw_scroll(atom.batch_id).await; + let atom = &mut self + .render_api + .make_guard(gfxtag!("BaseEdit::TouchStateAction::ScrollVert")); + self.redraw_scroll(atom.batch_id); } TouchStateAction::SetCursorPos => { // TBH I can't even see the cursor under my thumb so I'll just @@ -840,7 +842,7 @@ impl BaseEdit { TouchStateAction::Started { pos: _, instant: _ } | TouchStateAction::SetCursorPos => { let atom = &mut self.render_api.make_guard(gfxtag!("BaseEdit::handle_touch_end")); self.touch_set_cursor_pos(atom, touch_pos); - self.redraw(atom).await; + self.redraw(atom); } _ => {} } @@ -872,7 +874,7 @@ impl BaseEdit { self.select_text.clone().set_null(atom, Role::Internal, 0).unwrap(); } - async fn handle_select(&self, mouse_pos: Point, side: Option) { + fn handle_select(&self, mouse_pos: Point, side: Option) { //t!("handle_select({mouse_pos:?}, {side:?})"); let rect = self.rect.get(); let is_mouse_hover = rect.contains(mouse_pos); @@ -893,7 +895,7 @@ impl BaseEdit { let scroll = (self.scroll.load(Ordering::Relaxed) + delta).clamp(0., max_scroll); self.scroll.store(scroll, Ordering::Release); - self.redraw_scroll(atom.batch_id).await; + self.redraw_scroll(atom.batch_id); } // Move mouse pos within this widget @@ -973,8 +975,8 @@ impl BaseEdit { self.pause_blinking(); //self.behave.apply_cursor_scroll(); - self.redraw_cursor(atom.batch_id).await; - self.redraw_select(atom.batch_id).await; + self.redraw_cursor(atom.batch_id); + self.redraw_select(atom.batch_id); } fn pause_blinking(&self) { @@ -983,13 +985,13 @@ impl BaseEdit { } #[instrument(target = "ui::edit")] - async fn redraw(&self, atom: &mut PropertyAtomicGuard) { - let draw_update = self.make_draw_calls().await; + fn redraw(&self, atom: &mut PropertyAtomicGuard) { + let draw_update = self.make_draw_calls(); self.render_api.replace_draw_calls(atom.batch_id, draw_update.draw_calls); } /// Called when scroll changes. Moves content up or down. Nothing more. - async fn redraw_scroll(&self, batch_id: BatchGuardId) { + fn redraw_scroll(&self, batch_id: BatchGuardId) { let rect = self.rect.get(); let mut content_instrs = vec![DrawInstruction::ApplyView(rect.with_zero_pos())]; @@ -1015,16 +1017,16 @@ impl BaseEdit { self.render_api.replace_draw_calls(batch_id, draw_main); } - async fn redraw_cursor(&self, batch_id: BatchGuardId) { - let instrs = self.get_cursor_instrs().await; + fn redraw_cursor(&self, batch_id: BatchGuardId) { + let instrs = self.get_cursor_instrs(); let draw_calls = vec![(self.cursor_dc_key, DrawCall::new(instrs, vec![], 2, "curs_redr"))]; self.render_api.replace_draw_calls(batch_id, draw_calls); } - async fn redraw_select(&self, batch_id: BatchGuardId) { + fn redraw_select(&self, batch_id: BatchGuardId) { //t!("redraw_select"); let sel_instrs = self.regen_select_mesh(); - let phone_sel_instrs = self.regen_phone_select_handle_mesh().await; + let phone_sel_instrs = self.regen_phone_select_handle_mesh(); let draw_calls = vec![ (self.select_dc_key, DrawCall::new(sel_instrs, vec![], 0, "chatedit_sel")), ( @@ -1035,7 +1037,38 @@ impl BaseEdit { self.render_api.replace_draw_calls(batch_id, draw_calls); } - async fn get_cursor_instrs(&self) -> Vec { + fn draw_pasta_overlay(&self, batch_id: BatchGuardId) { + let font_size = self.font_size.get(); + //let window_scale = self.window_scale.get(); + let lineheight = self.lineheight.get(); + + let rect = Rectangle::new(0., 0., 200., 80.); + let mut mesh = MeshBuilder::new(gfxtag!("chatedit_overlay_pasta_box")); + mesh.draw_box(&rect, [0., 0., 0., 0.2], &Rectangle::zero()); + mesh.draw_outline(&rect, [1., 0., 0., 1.], 1.); + let mut instrs = vec![ + DrawInstruction::Move(Point::new(0., -100.)), + DrawInstruction::Draw(mesh.alloc(&self.render_api).draw_untextured()), + ]; + let layout = text::make_layout( + // translator for this + "paste", + [1., 0., 0., 1.], + font_size, + lineheight, + 1., + None, + &vec![], + ); + let mut txt_instrs = + text::render_layout(&layout, &self.render_api, gfxtag!("chatedit_overlay_pasta_txt")); + instrs.append(&mut txt_instrs); + let dcs = + vec![(self.overlay_dc_key, DrawCall::new(instrs, vec![], 1, "chatedit_overlay_pasta"))]; + self.render_api.replace_draw_calls(batch_id, dcs); + } + + fn get_cursor_instrs(&self) -> Vec { if !self.is_focused.get() || !self.cursor_is_visible.load(Ordering::Relaxed) || self.hide_cursor.load(Ordering::Relaxed) @@ -1106,7 +1139,7 @@ impl BaseEdit { instrs } - async fn regen_phone_select_handle_mesh(&self) -> Vec { + fn regen_phone_select_handle_mesh(&self) -> Vec { if !self.is_phone_select.load(Ordering::Acquire) { //t!("regen_phone_select_handle_mesh() [DISABLED]"); return vec![] @@ -1132,13 +1165,13 @@ impl BaseEdit { self.behave.eval_rect(atom); } - async fn make_draw_calls(&self) -> DrawUpdate { + fn make_draw_calls(&self) -> DrawUpdate { let rect = self.rect.get(); - let cursor_instrs = self.get_cursor_instrs().await; + let cursor_instrs = self.get_cursor_instrs(); let txt_instrs = self.regen_txt_mesh(); let sel_instrs = self.regen_select_mesh(); - let phone_sel_instrs = self.regen_phone_select_handle_mesh().await; + let phone_sel_instrs = self.regen_phone_select_handle_mesh(); let mut content_instrs = vec![DrawInstruction::ApplyView(rect.with_zero_pos())]; let mut bg_instrs = self.regen_bg_mesh(); @@ -1224,7 +1257,7 @@ impl BaseEdit { &mut self_.render_api.make_guard(gfxtag!("BaseEdit::process_insert_text_method")); self_.editor.lock().insert(&text, atom); self_.eval_rect(); - self_.redraw(atom).await; + self_.redraw(atom); true } @@ -1266,7 +1299,7 @@ impl BaseEdit { } #[cfg(target_os = "android")] - async fn handle_android_event(&self, state: AndroidTextInputState) { + fn handle_android_event(&self, state: AndroidTextInputState) { if !self.is_active.get() { return } @@ -1313,12 +1346,12 @@ impl BaseEdit { self.pause_blinking(); //assert!(state.text != self.text.get()); self.finish_select(atom); - self.redraw(atom).await; + self.redraw(atom); } else if is_select_changed { // Redrawing the entire text just for select changes is expensive - self.redraw_cursor(atom.batch_id).await; + self.redraw_cursor(atom.batch_id); //t!("handle_android_event calling redraw_select"); - self.redraw_select(atom.batch_id).await; + self.redraw_select(atom.batch_id); } } } @@ -1371,18 +1404,18 @@ impl UIObject for BaseEdit { //self_.select_text.set_null(Role::Internal, 0).unwrap(); self_.scroll.store(0., Ordering::Release); self_.eval_rect(); - self_.redraw(atom).await; + self_.redraw(atom); } async fn redraw(self_: Arc, batch: BatchGuardPtr) { let atom = &mut batch.spawn(); self_.eval_rect(); - self_.redraw(atom).await; + self_.redraw(atom); } async fn set_text(self_: Arc, batch: BatchGuardPtr) { self_.editor.lock().on_text_prop_changed(); let atom = &mut batch.spawn(); self_.eval_rect(); - self_.redraw(atom).await; + self_.redraw(atom); } on_modify.when_change(self.rect.prop(), redraw); @@ -1436,7 +1469,7 @@ impl UIObject for BaseEdit { // Invert the bool self_.cursor_is_visible.fetch_not(Ordering::Relaxed); let atom = &mut self_.render_api.make_guard(gfxtag!("BaseEdit::start")); - self_.redraw_cursor(atom.batch_id).await; + self_.redraw_cursor(atom.batch_id); } }); @@ -1457,14 +1490,14 @@ impl UIObject for BaseEdit { if let Some((mouse_pos, side)) = scroll_stat { let self_ = me2.upgrade().unwrap(); //t!("select task interrupt: {mouse_pos:?} (side={side:?})"); - self_.handle_select(mouse_pos, side).await; + self_.handle_select(mouse_pos, side); }; } _ = msleep(SELECT_TASK_UPDATE_TIME).fuse() => { if let Some((mouse_pos, side)) = scroll_stat { let self_ = me2.upgrade().unwrap(); //t!("select task update: {mouse_pos:?} (side={side:?})"); - self_.handle_select(mouse_pos, side).await; + self_.handle_select(mouse_pos, side); }; } } @@ -1474,7 +1507,7 @@ impl UIObject for BaseEdit { if let Some((mouse_pos, side)) = scroll_stat { let self_ = me2.upgrade().unwrap(); //t!("select task wake up: {mouse_pos:?} (side={side:?})"); - self_.handle_select(mouse_pos, side).await; + self_.handle_select(mouse_pos, side); }; } } @@ -1500,7 +1533,7 @@ impl UIObject for BaseEdit { panic!("self destroyed before autosuggest_task was stopped!"); }; - self_.handle_android_event(ev).await; + self_.handle_android_event(ev); } }); tasks.push(autosuggest_task); @@ -1524,7 +1557,7 @@ impl UIObject for BaseEdit { ) -> Option { *self.parent_rect.lock() = Some(parent_rect); self.eval_rect(); - Some(self.make_draw_calls().await) + Some(self.make_draw_calls()) } async fn handle_char(&self, key: char, mods: KeyMods, repeat: bool) -> bool { @@ -1552,7 +1585,7 @@ impl UIObject for BaseEdit { if repeat { return false } - return self.handle_shortcut(key, &mods, atom).await + return self.handle_shortcut(key, &mods, atom); } // Do nothing @@ -1565,7 +1598,7 @@ impl UIObject for BaseEdit { self.editor.lock().insert(&key_str, atom); self.eval_rect(); self.behave.apply_cursor_scroll(); - self.redraw(atom).await; + self.redraw(atom); true } @@ -1595,7 +1628,7 @@ impl UIObject for BaseEdit { let mut is_handled = false; for _ in 0..actions { - is_handled = self.handle_key(&key, &mods, atom).await; + is_handled = self.handle_key(&key, &mods, atom); } is_handled } @@ -1646,7 +1679,7 @@ impl UIObject for BaseEdit { self.pause_blinking(); self.eval_rect(); - self.redraw(atom).await; + self.redraw(atom); true } @@ -1687,7 +1720,7 @@ impl UIObject for BaseEdit { // Stop any existing select/scroll process sel_sender.send(None).await.unwrap(); // Mouse is inside so just select the text once and be done. - self.handle_select(mouse_pos, None).await; + self.handle_select(mouse_pos, None); } true @@ -1705,7 +1738,7 @@ impl UIObject for BaseEdit { scroll = scroll.clamp(0., self.behave.max_scroll()); t!("handle_mouse_wheel({wheel_pos:?}) [scroll={scroll}]"); self.scroll.store(scroll, Ordering::Release); - self.redraw_scroll(atom.batch_id).await; + self.redraw_scroll(atom.batch_id); true } @@ -1721,7 +1754,7 @@ impl UIObject for BaseEdit { } match phase { - TouchPhase::Started => self.handle_touch_start(touch_pos).await, + TouchPhase::Started => self.handle_touch_start(touch_pos), TouchPhase::Moved => self.handle_touch_move(touch_pos).await, TouchPhase::Ended => self.handle_touch_end(touch_pos).await, TouchPhase::Cancelled => false,