Răsfoiți Sursa

app: bugfix edit select on android to have correct logic

darkfi 9 luni în urmă
părinte
comite
84d3a1c1fb

+ 13 - 9
bin/app/src/text2/editor/android.rs

@@ -259,20 +259,24 @@ impl Editor {
         let (start, end) = (min(anchor, index), max(anchor, index));
         Some(edit.buffer[start..end].to_string())
     }
-    pub fn selection(&self) -> parley::Selection {
+    pub fn selection(&self, side: isize) -> parley::Selection {
+        assert!(side.abs() == 1);
         let edit = android::get_editable(self.composer_id).unwrap();
 
-        let select_start = char16_to_byte_index(&edit.buffer, edit.select_start).unwrap();
-        let select_end = char16_to_byte_index(&edit.buffer, edit.select_end).unwrap();
+        let mut select_start = char16_to_byte_index(&edit.buffer, edit.select_start).unwrap();
+        let mut select_end = char16_to_byte_index(&edit.buffer, edit.select_end).unwrap();
         //t!("selection() -> ({select_start}, {select_end})");
 
-        let anchor = parley::Cursor::from_byte_index(
-            &self.layout,
-            select_start,
-            parley::Affinity::Downstream,
-        );
+        let (anchor, focus) = match side {
+            -1 => (select_end, select_start),
+            1 => (select_start, select_end),
+            _ => panic!(),
+        };
+
+        let anchor =
+            parley::Cursor::from_byte_index(&self.layout, anchor, parley::Affinity::Downstream);
         let focus =
-            parley::Cursor::from_byte_index(&self.layout, select_end, parley::Affinity::Downstream);
+            parley::Cursor::from_byte_index(&self.layout, focus, parley::Affinity::Downstream);
 
         parley::Selection::new(anchor, focus)
     }

+ 2 - 1
bin/app/src/text2/editor/parley.rs

@@ -134,7 +134,8 @@ impl Editor {
     pub fn selected_text(&self) -> Option<String> {
         self.editor.selected_text().map(str::to_string)
     }
-    pub fn selection(&self) -> parley::Selection {
+    pub fn selection(&self, side: isize) -> parley::Selection {
+        assert!(side == 1);
         *self.editor.raw_selection()
     }
     /// Android uses byte indexes whereas parley has its own things. So this API is a compromise

+ 27 - 13
bin/app/src/ui/edit/mod.rs

@@ -27,6 +27,7 @@ use parking_lot::Mutex as SyncMutex;
 use rand::{rngs::OsRng, Rng};
 use std::{
     io::Cursor,
+    mem::swap,
     ops::{Deref, DerefMut},
     sync::{
         atomic::{AtomicBool, Ordering},
@@ -724,7 +725,7 @@ impl BaseEdit {
     async fn get_select_handles(&self, editor: &Editor) -> Option<(Point, Point)> {
         let layout = editor.layout();
 
-        let sel = editor.selection();
+        let sel = editor.selection(1);
         if sel.is_collapsed() {
             assert!(!self.is_phone_select.load(Ordering::Relaxed));
             return None
@@ -802,7 +803,7 @@ impl BaseEdit {
             touch_info.update(&touch_pos);
             touch_info.state.clone()
         };
-        t!("handle_touch_move({touch_pos:?})  touch_state={touch_state:?}");
+        //t!("handle_touch_move({touch_pos:?})  touch_state={touch_state:?}");
         match &touch_state {
             TouchStateAction::Inactive => return false,
             TouchStateAction::StartSelect => {
@@ -927,6 +928,11 @@ impl BaseEdit {
         // Move mouse pos within this widget
         self.abs_to_local(&mut clip_mouse_pos);
 
+        let mut sel_side = 1;
+        if let Some(side) = side {
+            sel_side = side;
+        }
+
         let (seltext, sel_start, sel_end) = {
             let mut editor = self.lock_editor().await;
 
@@ -935,8 +941,10 @@ impl BaseEdit {
             //let mut drv = editor.driver(&mut txt_ctx).unwrap();
             //drv.extend_selection_to_point(clip_mouse_pos.x, clip_mouse_pos.y);
             let layout = editor.layout();
-            let prev_sel = editor.selection();
+            let mut prev_sel = editor.selection(sel_side);
             let sel = prev_sel.extend_to_point(layout, clip_mouse_pos.x, clip_mouse_pos.y);
+            let (mut prev_start, mut prev_end) =
+                (prev_sel.anchor().index(), prev_sel.focus().index());
             let (mut start, mut end) = (sel.anchor().index(), sel.focus().index());
             //t!("handle_select() setting ({start}, {end})");
 
@@ -948,21 +956,27 @@ impl BaseEdit {
 
                 // Prevent selection crossing itself
                 if side == -1 {
-                    let max_start = sel.focus().previous_visual(layout).index();
-                    start = std::cmp::min(start, max_start);
-                    //t!("handle_select(): LHS set start={start} before {max_start}");
+                    let max_end = sel.anchor().previous_visual(layout).index();
+                    end = std::cmp::min(end, max_end);
+                    //t!("handle_select(): LHS set focus {end} before {max_end}");
+                    // When selecting from the LHS these will be swapped so swap them back
+                    swap(&mut start, &mut end);
+                    swap(&mut prev_start, &mut prev_end);
                 } else {
                     let min_end = sel.anchor().next_visual(layout).index();
                     end = std::cmp::max(end, min_end);
-                    //t!("handle_select(): RHS set end={end} after {min_end}");
+                    //t!("handle_select(): RHS set focus {end} after {min_end}");
                 }
             }
 
-            if start == prev_sel.anchor().index() && end == prev_sel.focus().index() {
+            if start == prev_start && end == prev_end {
                 // No change so just return
+                //t!("handle_select(): no change early exit");
                 return
             }
+            assert!(start <= end);
 
+            //t!("handle_select(): set_selection({start}, {end})");
             editor.set_selection(start, end);
             editor.refresh().await;
 
@@ -1108,7 +1122,7 @@ impl BaseEdit {
         let editor = self.lock_editor().await;
         let layout = editor.layout();
 
-        let sel = editor.selection();
+        let sel = editor.selection(1);
         let sel_color = self.hi_bg_color.get();
         if !sel.is_collapsed() {
             let mut mesh = MeshBuilder::new(gfxtag!("chatedit_select_mesh"));
@@ -1130,7 +1144,7 @@ impl BaseEdit {
         let editor = self.lock_editor().await;
         let (first, last) = self.get_select_handles(&editor).await.unwrap();
 
-        let sel = editor.selection();
+        let sel = editor.selection(1);
         assert!(!sel.is_collapsed());
 
         // We could cache this and use Move instead but why bother?
@@ -1473,14 +1487,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:?})");
+                                //t!("select task interrupt: {mouse_pos:?} (side={side:?})");
                                 self_.handle_select(mouse_pos, side).await;
                             };
                         }
                         _ = 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:?})");
+                                //t!("select task update: {mouse_pos:?} (side={side:?})");
                                 self_.handle_select(mouse_pos, side).await;
                             };
                         }
@@ -1490,7 +1504,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:?})");
+                        //t!("select task wake up: {mouse_pos:?} (side={side:?})");
                         self_.handle_select(mouse_pos, side).await;
                     };
                 }