FLTK logo

[master] 495b239 - Fix selection extension in Fl_Text_*, issue 196 (#550)

FLTK matrix user chat room
(using Element browser app)   FLTK gitter user chat room   GitHub FLTK Project   FLTK News RSS Feed  
  FLTK Apps      FLTK Library      Forums      Links     Login 
 All Forums  |  Back to fltk.commit  ]
 
Previous Message ]Next Message ]

[master] 495b239 - Fix selection extension in Fl_Text_*, issue 196 (#550) "Matthias Melcher" Nov 22, 2022  
 
commit 495b2395c14607c030a0270ed7341bf04be7fa56
Author:     Matthias Melcher <github@matthiasm.com>
AuthorDate: Tue Nov 22 16:18:56 2022 +0100
Commit:     GitHub <noreply@github.com>
CommitDate: Tue Nov 22 16:18:56 2022 +0100

    Fix selection extension in Fl_Text_*, issue 196 (#550)
    
    
    Selecting a text range programmatically would not sync
    some variables with the actual selection. This also fixes
    a crash bug in macOS when dragging text that was
    selected by buffer()->select() only.

 FL/Fl_Text_Display.H    |  1 +
 src/Fl_Text_Display.cxx | 46 +++++++++++++++++++++++++++++++++++++++++++---
 src/Fl_Text_Editor.cxx  |  6 +++++-
 3 files changed, 49 insertions(+), 4 deletions(-)

diff --git FL/Fl_Text_Display.H FL/Fl_Text_Display.H
index 21f0d63..1d5b511 100644
--- FL/Fl_Text_Display.H
+++ FL/Fl_Text_Display.H
@@ -124,6 +124,7 @@ public:
     WRAP_AT_BOUNDS  /**< wrap text so that it fits into the widget width */
   };
 
+  friend int fl_text_drag_prepare(int pos, int key, Fl_Text_Display* d);
   friend void fl_text_drag_me(int pos, Fl_Text_Display* d);
 
   typedef void (*Unfinished_Style_Cb)(int, void *);
diff --git src/Fl_Text_Display.cxx src/Fl_Text_Display.cxx
index bd81e0e..e6f30c1 100644
--- src/Fl_Text_Display.cxx
+++ src/Fl_Text_Display.cxx
@@ -3961,7 +3961,42 @@ void Fl_Text_Display::draw(void) {
   fl_pop_clip();
 }
 
-
+// GitHub Issue #196: internal selection and visible selection can run out of
+// sync, giving the user unexpected keyboard selection. The code block below
+// captures that and fixes it.
+// - set pos to the drag target postion or -1 if we don't know
+// - if pos is -1, and key is not -1, key can be set to indicate a direction
+//   (e.g. FL_Left)
+// return 0 if nothing changed, return 1 if dragPos or mCursorPos were modified
+int fl_text_drag_prepare(int pos, int key, Fl_Text_Display* d) {
+  if (d->buffer()->selected()) {
+    int start, end;
+    d->buffer()->selection_position(&start, &end);
+    if ( (d->dragPos!=start || d->mCursorPos!=end) && (d->dragPos!=end || d->mCursorPos!=start) ) {
+      if (pos!=-1) {
+        if (pos<start) {
+          d->mCursorPos = start;
+          d->dragPos = end;
+        } else {
+          d->mCursorPos = end;
+          d->dragPos = start;
+        }
+      } else if (key!=-1) {
+        switch (key) {
+          case FL_Home: case FL_Left: case FL_Up: case FL_Page_Up:
+            d->dragPos = end; d->mCursorPos = start; break;
+          default:
+            d->dragPos = start; d->mCursorPos = end; break;
+        }
+      } else {
+        d->dragPos = start;
+        d->mCursorPos = end;
+      }
+      return 1;
+    }
+  }
+  return 0;
+}
 
 // this processes drag events due to mouse for Fl_Text_Display and
 // also drags due to cursor movement with shift held down for
@@ -4079,8 +4114,12 @@ int Fl_Text_Display::handle(int event) {
       }
       if (Fl_Group::handle(event)) return 1;
       if (Fl::event_state()&FL_SHIFT) {
-        if (!buffer()->primary_selection()->selected())
-            dragPos = insert_position();
+        if (buffer()->primary_selection()->selected()) {
+          int pos = xy_to_position(Fl::event_x(), Fl::event_y(), CURSOR_POS);
+          fl_text_drag_prepare(pos, -1, this);
+        } else {
+          dragPos = insert_position();
+        }
         return handle(FL_DRAG);
       }
       dragging = 1;
@@ -4114,6 +4153,7 @@ int Fl_Text_Display::handle(int event) {
       if (dragType==DRAG_START_DND) {
         if (!Fl::event_is_click() && Fl::dnd_text_ops()) {
           const char* copy = buffer()->selection_text();
+          Fl::copy(copy, strlen(copy));
           Fl::screen_driver()->dnd(1);
           free((void*)copy);
         }
diff --git src/Fl_Text_Editor.cxx src/Fl_Text_Editor.cxx
index a786ac4..1393500 100644
--- src/Fl_Text_Editor.cxx
+++ src/Fl_Text_Editor.cxx
@@ -284,6 +284,7 @@ int Fl_Text_Editor::kf_enter(int, Fl_Text_Editor* e) {
   return 1;
 }
 
+extern int fl_text_drag_prepare(int pos, int key, Fl_Text_Display* d);
 extern void fl_text_drag_me(int pos, Fl_Text_Display* d);
 /** Moves the text cursor in the direction indicated by key \p 'c' in editor \p 'e'.
     Supported values for 'c' are currently:
@@ -339,6 +340,7 @@ int Fl_Text_Editor::kf_move(int c, Fl_Text_Editor* e) {
     \see kf_move()
 */
 int Fl_Text_Editor::kf_shift_move(int c, Fl_Text_Editor* e) {
+  fl_text_drag_prepare(-1, c, e);
   kf_move(c, e);
   fl_text_drag_me(e->insert_position(), e);
   char *copy = e->buffer()->selection_text();
@@ -441,6 +443,7 @@ int Fl_Text_Editor::kf_meta_move(int c, Fl_Text_Editor* e) {
     \see kf_meta_move().
 */
 int Fl_Text_Editor::kf_m_s_move(int c, Fl_Text_Editor* e) {
+  fl_text_drag_prepare(-1, c, e);
   kf_meta_move(c, e);
   fl_text_drag_me(e->insert_position(), e);
   return 1;
@@ -450,6 +453,7 @@ int Fl_Text_Editor::kf_m_s_move(int c, Fl_Text_Editor* e) {
     \see kf_ctrl_move().
 */
 int Fl_Text_Editor::kf_c_s_move(int c, Fl_Text_Editor* e) {
+  fl_text_drag_prepare(-1, c, e);
   kf_ctrl_move(c, e);
   fl_text_drag_me(e->insert_position(), e);
   return 1;
@@ -709,7 +713,7 @@ int Fl_Text_Editor::handle(int event) {
         dragType = DRAG_NONE;
         if(buffer()->selected()) {
           buffer()->unselect();
-          }
+        }
         int pos = xy_to_position(Fl::event_x(), Fl::event_y(), CURSOR_POS);
         insert_position(pos);
         Fl::paste(*this, 0);
Direct Link to Message ]
 
     
Previous Message ]Next Message ]
 
 

Comments are owned by the poster. All other content is copyright 1998-2024 by Bill Spitzak and others. This project is hosted by The FLTK Team. Please report site problems to 'erco@seriss.com'.