FLTK logo

[master] 87fe293 - Local undo per Fl_Text_Buffer and Fl_Input_ (#557)

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] 87fe293 - Local undo per Fl_Text_Buffer and Fl_Input_ (#557) "Matthias Melcher" Nov 26, 2022  
 
commit 87fe29372cf8623a003b39dea755f3d290916601
Author:     Matthias Melcher <github@matthiasm.com>
AuthorDate: Sat Nov 26 20:28:12 2022 +0100
Commit:     GitHub <noreply@github.com>
CommitDate: Sat Nov 26 20:28:12 2022 +0100

    Local undo per Fl_Text_Buffer and Fl_Input_ (#557)

 FL/Fl_Input_.H         |   5 ++
 FL/Fl_Text_Buffer.H    |   2 +
 src/Fl_Input_.cxx      | 138 +++++++++++++++++++++++++--------------------
 src/Fl_Text_Buffer.cxx | 149 +++++++++++++++++++++++++++++--------------------
 4 files changed, 172 insertions(+), 122 deletions(-)

diff --git FL/Fl_Input_.H FL/Fl_Input_.H
index 254730c..bd15904 100644
--- FL/Fl_Input_.H
+++ FL/Fl_Input_.H
@@ -38,6 +38,8 @@
 #define FL_MULTILINE_INPUT_WRAP (FL_MULTILINE_INPUT | FL_INPUT_WRAP)
 #define FL_MULTILINE_OUTPUT_WRAP (FL_MULTILINE_INPUT | FL_INPUT_READONLY | FL_INPUT_WRAP)
 
+class Fl_Input_Undo_Action;
+
 /**
   This class provides a low-overhead text input field.
 
@@ -144,6 +146,9 @@ class FL_EXPORT Fl_Input_ : public Fl_Widget {
   /** \internal color of the text cursor */
   Fl_Color cursor_color_;
 
+  /** \internal local undo event */
+  Fl_Input_Undo_Action* undo_;
+
   /** \internal Horizontal cursor position in pixels while moving up or down. */
   static double up_down_pos;
 
diff --git FL/Fl_Text_Buffer.H FL/Fl_Text_Buffer.H
index a1d044f..727b2a6 100644
--- FL/Fl_Text_Buffer.H
+++ FL/Fl_Text_Buffer.H
@@ -60,6 +60,7 @@
 
 #include "Fl_Export.H"
 
+class Fl_Text_Undo_Action;
 
 /**
   \class Fl_Text_Selection
@@ -836,6 +837,7 @@ protected:
   int mPreferredGapSize;          /**< the default allocation for the text gap is 1024
                                        bytes and should only be increased if frequent
                                        and large changes in buffer size are expected */
+  Fl_Text_Undo_Action* mUndo;     /**< local undo event */
 };
 
 #endif
diff --git src/Fl_Input_.cxx src/Fl_Input_.cxx
index 55190b2..a8ad63c 100644
--- src/Fl_Input_.cxx
+++ src/Fl_Input_.cxx
@@ -33,6 +33,45 @@ extern void fl_draw(const char*, int, float, float);
 
 ////////////////////////////////////////////////////////////////
 
+class Fl_Input_Undo_Action {
+public:
+  Fl_Input_Undo_Action() :
+  undobuffer(NULL),
+  undobufferlength(0),
+  undoat(0),
+  undocut(0),
+  undoinsert(0),
+  undoyankcut(0)
+  { }
+  ~Fl_Input_Undo_Action() {
+    if (undobuffer)
+      ::free(undobuffer);
+  }
+
+  char *undobuffer;
+  int undobufferlength;
+  int undoat;              // points after insertion
+  int undocut;             // number of characters deleted there
+  int undoinsert;          // number of characters inserted
+  int undoyankcut;         // length of valid contents of buffer, even if undocut=0
+
+  /*
+   Resize the undo buffer to match at least the requested size.
+   */
+  void undobuffersize(int n)
+  {
+    if (n > undobufferlength) {
+      undobufferlength = n + 128;
+      undobuffer = (char *)realloc(undobuffer, undobufferlength);
+    }
+  }
+
+  void clear() {
+    undocut = undoinsert = 0;
+  }
+};
+
+
 /** \internal
   Converts a given text segment into the text that will be rendered on screen.
 
@@ -723,26 +762,6 @@ int Fl_Input_::copy(int clipboard) {
 
 #define MAXFLOATSIZE 40
 
-static char* undobuffer;
-static int undobufferlength;
-static Fl_Input_* undowidget;
-static int undoat;      // points after insertion
-static int undocut;     // number of characters deleted there
-static int undoinsert;  // number of characters inserted
-static int yankcut;     // length of valid contents of buffer, even if undocut=0
-
-static void undobuffersize(int n) {
-  if (n > undobufferlength) {
-    if (undobuffer) {
-      do {undobufferlength *= 2;} while (undobufferlength < n);
-      undobuffer = (char*)realloc(undobuffer, undobufferlength);
-    } else {
-      undobufferlength = n+9;
-      undobuffer = (char*)malloc(undobufferlength);
-    }
-  }
-}
-
 /**
  Append text at the end.
 
@@ -860,45 +879,43 @@ int Fl_Input_::replace(int b, int e, const char* text, int ilen) {
   put_in_buffer(size_+ilen);
 
   if (e>b) {
-    if (undowidget == this && b == undoat) {
-      undobuffersize(undocut+(e-b));
-      memcpy(undobuffer+undocut, value_+b, e-b);
-      undocut += e-b;
-    } else if (undowidget == this && e == undoat && !undoinsert) {
-      undobuffersize(undocut+(e-b));
-      memmove(undobuffer+(e-b), undobuffer, undocut);
-      memcpy(undobuffer, value_+b, e-b);
-      undocut += e-b;
-    } else if (undowidget == this && e == undoat && (e-b)<undoinsert) {
-      undoinsert -= e-b;
+    if (b == undo_->undoat) {
+      undo_->undobuffersize(undo_->undocut+(e-b));
+      memcpy(undo_->undobuffer+undo_->undocut, value_+b, e-b);
+      undo_->undocut += e-b;
+    } else if (e == undo_->undoat && !undo_->undoinsert) {
+      undo_->undobuffersize(undo_->undocut+(e-b));
+      memmove(undo_->undobuffer+(e-b), undo_->undobuffer, undo_->undocut);
+      memcpy(undo_->undobuffer, value_+b, e-b);
+      undo_->undocut += e-b;
+    } else if (e == undo_->undoat && (e-b)<undo_->undoinsert) {
+      undo_->undoinsert -= e-b;
     } else {
-      undobuffersize(e-b);
-      memcpy(undobuffer, value_+b, e-b);
-      undocut = e-b;
-      undoinsert = 0;
+      undo_->undobuffersize(e-b);
+      memcpy(undo_->undobuffer, value_+b, e-b);
+      undo_->undocut = e-b;
+      undo_->undoinsert = 0;
     }
     memmove(buffer+b, buffer+e, size_-e+1);
     size_ -= e-b;
-    undowidget = this;
-    undoat = b;
-    if (input_type() == FL_SECRET_INPUT) yankcut = 0; else yankcut = undocut;
+    undo_->undoat = b;
+    if (input_type() == FL_SECRET_INPUT) undo_->undoyankcut = 0; else undo_->undoyankcut = undo_->undocut;
   }
 
   if (ilen) {
-    if (undowidget == this && b == undoat)
-      undoinsert += ilen;
+    if (b == undo_->undoat)
+      undo_->undoinsert += ilen;
     else {
-      undocut = 0;
-      undoinsert = ilen;
+      undo_->undocut = 0;
+      undo_->undoinsert = ilen;
     }
     memmove(buffer+b+ilen, buffer+b, size_-b+1);
     memcpy(buffer+b, text, ilen);
     size_ += ilen;
   }
-  undowidget = this;
   om = mark_;
   op = position_;
-  mark_ = position_ = undoat = b+ilen;
+  mark_ = position_ = undo_->undoat = b+ilen;
 
   // Insertions into the word at the end of the line will cause it to
   // wrap to the next line, so we must indicate that the changes may start
@@ -922,7 +939,7 @@ int Fl_Input_::replace(int b, int e, const char* text, int ilen) {
 
   minimal_update(b);
 
-  mark_ = position_ = undoat;
+  mark_ = position_ = undo_->undoat;
 
   set_changed();
   if (when()&FL_WHEN_CHANGED) do_callback();
@@ -938,33 +955,33 @@ int Fl_Input_::replace(int b, int e, const char* text, int ilen) {
 */
 int Fl_Input_::undo() {
   was_up_down = 0;
-  if ( undowidget != this || (!undocut && !undoinsert) ) return 0;
+  if (!undo_->undocut && !undo_->undoinsert) return 0;
 
-  int ilen = undocut;
-  int xlen = undoinsert;
-  int b = undoat-xlen;
+  int ilen = undo_->undocut;
+  int xlen = undo_->undoinsert;
+  int b = undo_->undoat-xlen;
   int b1 = b;
 
   put_in_buffer(size_+ilen);
 
   if (ilen) {
     memmove(buffer+b+ilen, buffer+b, size_-b+1);
-    memcpy(buffer+b, undobuffer, ilen);
+    memcpy(buffer+b, undo_->undobuffer, ilen);
     size_ += ilen;
     b += ilen;
   }
 
   if (xlen) {
-    undobuffersize(xlen);
-    memcpy(undobuffer, buffer+b, xlen);
+    undo_->undobuffersize(xlen);
+    memcpy(undo_->undobuffer, buffer+b, xlen);
     memmove(buffer+b, buffer+b+xlen, size_-xlen-b+1);
     size_ -= xlen;
   }
 
-  undocut = xlen;
-  if (xlen) yankcut = xlen;
-  undoinsert = ilen;
-  undoat = b;
+  undo_->undocut = xlen;
+  if (xlen) undo_->undoyankcut = xlen;
+  undo_->undoinsert = ilen;
+  undo_->undoat = b;
   mark_ = b /* -ilen */;
   position_ = b;
 
@@ -988,8 +1005,8 @@ int Fl_Input_::undo() {
 */
 int Fl_Input_::copy_cuts() {
   // put the yank buffer into the X clipboard
-  if (!yankcut || input_type()==FL_SECRET_INPUT) return 0;
-  Fl::copy(undobuffer, yankcut, 1);
+  if (!undo_->undoyankcut || input_type()==FL_SECRET_INPUT) return 0;
+  Fl::copy(undo_->undobuffer, undo_->undoyankcut, 1);
   return 1;
 }
 
@@ -1151,6 +1168,7 @@ Fl_Input_::Fl_Input_(int X, int Y, int W, int H, const char* l)
   xscroll_ = yscroll_ = 0;
   maximum_size_ = 32767;
   shortcut_ = 0;
+  undo_ = new Fl_Input_Undo_Action();
   set_flag(SHORTCUT_LABEL);
   set_flag(MAC_USE_ACCENTS_MENU);
   set_flag(NEEDS_KEYBOARD);
@@ -1217,7 +1235,7 @@ void Fl_Input_::put_in_buffer(int len) {
 */
 int Fl_Input_::static_value(const char* str, int len) {
   clear_changed();
-  if (undowidget == this) undowidget = 0;
+  undo_->clear();
   if (str == value_ && len == size_) return 0;
   if (len) { // non-empty new value:
     if (xscroll_ || yscroll_) {
@@ -1318,7 +1336,7 @@ void Fl_Input_::resize(int X, int Y, int W, int H) {
   from the parent Fl_Group.
 */
 Fl_Input_::~Fl_Input_() {
-  if (undowidget == this) undowidget = 0;
+  delete undo_;
   if (bufsize) free((void*)buffer);
 }
 
diff --git src/Fl_Text_Buffer.cxx src/Fl_Text_Buffer.cxx
index 4104929..4733fc1 100644
--- src/Fl_Text_Buffer.cxx
+++ src/Fl_Text_Buffer.cxx
@@ -66,32 +66,44 @@ static int min(int i1, int i2)
 
 #endif
 
+class Fl_Text_Undo_Action {
+public:
+  Fl_Text_Undo_Action() :
+    undobuffer(NULL),
+    undobufferlength(0),
+    undoat(0),
+    undocut(0),
+    undoinsert(0),
+    undoyankcut(0)
+  { }
+  ~Fl_Text_Undo_Action() {
+    if (undobuffer)
+      ::free(undobuffer);
+  }
 
-static char *undobuffer;
-static int undobufferlength;
-static Fl_Text_Buffer *undowidget;
-static int undoat;              // points after insertion
-static int undocut;             // number of characters deleted there
-static int undoinsert;          // number of characters inserted
-static int undoyankcut;         // length of valid contents of buffer, even if undocut=0
-
-/*
- Resize the undo buffer to match at least the requested size.
- */
-static void undobuffersize(int n)
-{
-  if (n > undobufferlength) {
-    if (undobuffer) {
-      do {
-        undobufferlength *= 2;
-      } while (undobufferlength < n);
-      undobuffer = (char *) realloc(undobuffer, undobufferlength);
-    } else {
-      undobufferlength = n + 9;
-      undobuffer = (char *) malloc(undobufferlength);
+  char *undobuffer;
+  int undobufferlength;
+  int undoat;              // points after insertion
+  int undocut;             // number of characters deleted there
+  int undoinsert;          // number of characters inserted
+  int undoyankcut;         // length of valid contents of buffer, even if undocut=0
+
+  /*
+   Resize the undo buffer to match at least the requested size.
+   */
+  void undobuffersize(int n)
+  {
+    if (n > undobufferlength) {
+      undobufferlength = n + 128;
+      undobuffer = (char *)realloc(undobuffer, undobufferlength);
     }
   }
-}
+
+  void clear() {
+    undocut = undoinsert = 0;
+  }
+};
+
 
 static void def_transcoding_warning_action(Fl_Text_Buffer *text)
 {
@@ -123,6 +135,7 @@ Fl_Text_Buffer::Fl_Text_Buffer(int requestedSize, int preferredGapSize)
   mPredeleteCbArgs = NULL;
   mCursorPosHint = 0;
   mCanUndo = 1;
+  mUndo = new Fl_Text_Undo_Action();
   input_file_was_transcoded = 0;
   transcoding_warning_action = def_transcoding_warning_action;
 }
@@ -142,6 +155,7 @@ Fl_Text_Buffer::~Fl_Text_Buffer()
     delete[] mPredeleteProcs;
     delete[] mPredeleteCbArgs;
   }
+  delete mUndo;
 }
 
 
@@ -190,6 +204,9 @@ void Fl_Text_Buffer::text(const char *t)
   /* Call the saved display routine(s) to update the screen */
   call_modify_callbacks(0, deletedLength, insertedLength, 0, deletedText);
   free((void *) deletedText);
+
+  if (mCanUndo)
+    mUndo->clear();
 }
 
 
@@ -449,36 +466,39 @@ void Fl_Text_Buffer::copy(Fl_Text_Buffer * fromBuf, int fromStart,
  */
 int Fl_Text_Buffer::undo(int *cursorPos)
 {
-  if (undowidget != this || (!undocut && !undoinsert && !mCanUndo))
+  if (!mCanUndo)
     return 0;
 
-  int ilen = undocut;
-  int xlen = undoinsert;
-  int b = undoat - xlen;
+  if (!mUndo->undocut && !mUndo->undoinsert)
+    return 0;
 
-  if (xlen && undoyankcut && !ilen) {
-    ilen = undoyankcut;
+  int ilen = mUndo->undocut;
+  int xlen = mUndo->undoinsert;
+  int b = mUndo->undoat - xlen;
+
+  if (xlen && mUndo->undoyankcut && !ilen) {
+    ilen = mUndo->undoyankcut;
   }
 
   if (xlen && ilen) {
-    undobuffersize(ilen + 1);
-    undobuffer[ilen] = 0;
-    char *tmp = fl_strdup(undobuffer);
-    replace(b, undoat, tmp);
+    mUndo->undobuffersize(ilen + 1);
+    mUndo->undobuffer[ilen] = 0;
+    char *tmp = fl_strdup(mUndo->undobuffer);
+    replace(b, mUndo->undoat, tmp);
     if (cursorPos)
       *cursorPos = mCursorPosHint;
     free(tmp);
   } else if (xlen) {
-    remove(b, undoat);
+    remove(b, mUndo->undoat);
     if (cursorPos)
       *cursorPos = mCursorPosHint;
   } else if (ilen) {
-    undobuffersize(ilen + 1);
-    undobuffer[ilen] = 0;
-    insert(undoat, undobuffer);
+    mUndo->undobuffersize(ilen + 1);
+    mUndo->undobuffer[ilen] = 0;
+    insert(mUndo->undoat, mUndo->undobuffer);
     if (cursorPos)
       *cursorPos = mCursorPosHint;
-    undoyankcut = 0;
+    mUndo->undoyankcut = 0;
   }
 
   return 1;
@@ -490,10 +510,17 @@ int Fl_Text_Buffer::undo(int *cursorPos)
  */
 void Fl_Text_Buffer::canUndo(char flag)
 {
+  if (flag) {
+    if (!mCanUndo) {
+      mUndo = new Fl_Text_Undo_Action();
+    }
+  } else {
+    if (mCanUndo) {
+      delete mUndo;
+      mUndo = NULL;
+    }
+  }
   mCanUndo = flag;
-  // disabling undo also clears the last undo operation!
-  if (!mCanUndo && undowidget==this)
-    undowidget = 0;
 }
 
 
@@ -1190,15 +1217,14 @@ int Fl_Text_Buffer::insert_(int pos, const char *text)
   update_selections(pos, 0, insertedLength);
 
   if (mCanUndo) {
-    if (undowidget == this && undoat == pos && undoinsert) {
-      undoinsert += insertedLength;
+    if (mUndo->undoat == pos && mUndo->undoinsert) {
+      mUndo->undoinsert += insertedLength;
     } else {
-      undoinsert = insertedLength;
-      undoyankcut = (undoat == pos) ? undocut : 0;
+      mUndo->undoinsert = insertedLength;
+      mUndo->undoyankcut = (mUndo->undoat == pos) ? mUndo->undocut : 0;
     }
-    undoat = pos + insertedLength;
-    undocut = 0;
-    undowidget = this;
+    mUndo->undoat = pos + insertedLength;
+    mUndo->undocut = 0;
   }
 
   return insertedLength;
@@ -1214,34 +1240,33 @@ void Fl_Text_Buffer::remove_(int start, int end)
   /* if the gap is not contiguous to the area to remove, move it there */
 
   if (mCanUndo) {
-    if (undowidget == this && undoat == end && undocut) {
-      undobuffersize(undocut + end - start + 1);
-      memmove(undobuffer + end - start, undobuffer, undocut);
-      undocut += end - start;
+    if (mUndo->undoat == end && mUndo->undocut) {
+      mUndo->undobuffersize(mUndo->undocut + end - start + 1);
+      memmove(mUndo->undobuffer + end - start, mUndo->undobuffer, mUndo->undocut);
+      mUndo->undocut += end - start;
     } else {
-      undocut = end - start;
-      undobuffersize(undocut);
+      mUndo->undocut = end - start;
+      mUndo->undobuffersize(mUndo->undocut);
     }
-    undoat = start;
-    undoinsert = 0;
-    undoyankcut = 0;
-    undowidget = this;
+    mUndo->undoat = start;
+    mUndo->undoinsert = 0;
+    mUndo->undoyankcut = 0;
   }
 
   if (start > mGapStart) {
     if (mCanUndo)
-      memcpy(undobuffer, mBuf + (mGapEnd - mGapStart) + start,
+      memcpy(mUndo->undobuffer, mBuf + (mGapEnd - mGapStart) + start,
              end - start);
     move_gap(start);
   } else if (end < mGapStart) {
     if (mCanUndo)
-      memcpy(undobuffer, mBuf + start, end - start);
+      memcpy(mUndo->undobuffer, mBuf + start, end - start);
     move_gap(end);
   } else {
     int prelen = mGapStart - start;
     if (mCanUndo) {
-      memcpy(undobuffer, mBuf + start, prelen);
-      memcpy(undobuffer + prelen, mBuf + mGapEnd, end - start - prelen);
+      memcpy(mUndo->undobuffer, mBuf + start, prelen);
+      memcpy(mUndo->undobuffer + prelen, mBuf + mGapEnd, end - start - prelen);
     }
   }
 
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'.