diff options
| -rw-r--r-- | FL/Fl_Input_.H | 5 | ||||
| -rw-r--r-- | FL/Fl_Text_Buffer.H | 2 | ||||
| -rw-r--r-- | src/Fl_Input_.cxx | 138 | ||||
| -rw-r--r-- | src/Fl_Text_Buffer.cxx | 149 |
4 files changed, 172 insertions, 122 deletions
diff --git a/FL/Fl_Input_.H b/FL/Fl_Input_.H index 254730c1b..bd159049a 100644 --- a/FL/Fl_Input_.H +++ b/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 a/FL/Fl_Text_Buffer.H b/FL/Fl_Text_Buffer.H index a1d044f48..727b2a65d 100644 --- a/FL/Fl_Text_Buffer.H +++ b/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 a/src/Fl_Input_.cxx b/src/Fl_Input_.cxx index 55190b258..a8ad63ce0 100644 --- a/src/Fl_Input_.cxx +++ b/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 a/src/Fl_Text_Buffer.cxx b/src/Fl_Text_Buffer.cxx index 410492957..4733fc177 100644 --- a/src/Fl_Text_Buffer.cxx +++ b/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); } } |
