summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Melcher <github@matthiasm.com>2023-02-10 17:13:20 +0100
committerGitHub <noreply@github.com>2023-02-10 17:13:20 +0100
commit7f87c847ba8ec976c6ad345942f9867658a89ab2 (patch)
tree00717f3197ea9d2d76c45207dd4f468b2ee201cb
parent72f860438170638d6aa492b477a59ff88b565d9d (diff)
Unlimited undo/redo for Fl_Input_ and Fl_Text_Buffer (#558) (#676)
-rw-r--r--FL/Fl_Input.H2
-rw-r--r--FL/Fl_Input_.H9
-rw-r--r--FL/Fl_Text_Buffer.H15
-rw-r--r--FL/Fl_Text_Editor.H3
-rw-r--r--src/Fl_Input.cxx6
-rw-r--r--src/Fl_Input_.cxx117
-rw-r--r--src/Fl_Text_Buffer.cxx205
-rw-r--r--src/Fl_Text_Editor.cxx30
-rw-r--r--src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx3
-rw-r--r--src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H4
-rw-r--r--src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx11
11 files changed, 356 insertions, 49 deletions
diff --git a/FL/Fl_Input.H b/FL/Fl_Input.H
index 93d1c2642..f53debd50 100644
--- a/FL/Fl_Input.H
+++ b/FL/Fl_Input.H
@@ -1,7 +1,7 @@
//
// Input header file for the Fast Light Tool Kit (FLTK).
//
-// Copyright 1998-2021 by Bill Spitzak and others.
+// Copyright 1998-2023 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
diff --git a/FL/Fl_Input_.H b/FL/Fl_Input_.H
index d89a341bc..a7062f5a0 100644
--- a/FL/Fl_Input_.H
+++ b/FL/Fl_Input_.H
@@ -39,6 +39,7 @@
#define FL_MULTILINE_OUTPUT_WRAP (FL_MULTILINE_INPUT | FL_INPUT_READONLY | FL_INPUT_WRAP)
class Fl_Input_Undo_Action;
+class Fl_Input_Undo_Action_List;
/**
This class provides a low-overhead text input field.
@@ -148,6 +149,8 @@ class FL_EXPORT Fl_Input_ : public Fl_Widget {
/** \internal local undo event */
Fl_Input_Undo_Action* undo_;
+ Fl_Input_Undo_Action_List* undo_list_;
+ Fl_Input_Undo_Action_List* redo_list_;
/** \internal Horizontal cursor position in pixels while moving up or down. */
static double up_down_pos;
@@ -212,6 +215,9 @@ protected:
/* Return the number of lines displayed on a single page. */
int linesPerPage();
+ /* Apply the current undo/redo operation, called from undo() or redo() */
+ int apply_undo();
+
public:
/* Change the size of the widget. */
@@ -378,6 +384,9 @@ public:
/* Undo previous changes to the text buffer. */
int undo();
+ /* Redo previous undo operations. */
+ int redo();
+
/* Copy the yank buffer to the clipboard. */
int copy_cuts();
diff --git a/FL/Fl_Text_Buffer.H b/FL/Fl_Text_Buffer.H
index e3e131ef1..dabe5677a 100644
--- a/FL/Fl_Text_Buffer.H
+++ b/FL/Fl_Text_Buffer.H
@@ -1,7 +1,7 @@
//
// Header file for Fl_Text_Buffer class.
//
-// Copyright 2001-2021 by Bill Spitzak and others.
+// Copyright 2001-2023 by Bill Spitzak and others.
// Original code Copyright Mark Edel. Permission to distribute under
// the LGPL for the FLTK library granted by Mark Edel.
//
@@ -61,6 +61,7 @@
#include "Fl_Export.H"
+class Fl_Text_Undo_Action_List;
class Fl_Text_Undo_Action;
/**
@@ -327,6 +328,11 @@ public:
int undo(int *cp=0);
/**
+ Redo previous undo action.
+ */
+ int redo(int *cp=0);
+
+ /**
Lets the undo system know if we can undo changes
*/
void canUndo(char flag=1);
@@ -813,6 +819,11 @@ protected:
*/
void update_selections(int pos, int nDeleted, int nInserted);
+ /**
+ Apply the current undo/redo operation, called from undo() or redo().
+ */
+ int apply_undo(Fl_Text_Undo_Action* action, int* cursorPos);
+
Fl_Text_Selection mPrimary; /**< highlighted areas */
Fl_Text_Selection mSecondary; /**< highlighted areas */
Fl_Text_Selection mHighlight; /**< highlighted areas */
@@ -841,6 +852,8 @@ protected:
bytes and should only be increased if frequent
and large changes in buffer size are expected */
Fl_Text_Undo_Action* mUndo; /**< local undo event */
+ Fl_Text_Undo_Action_List* mUndoList; /**< List of undo event */
+ Fl_Text_Undo_Action_List* mRedoList; /**< List of redo event */
};
#endif
diff --git a/FL/Fl_Text_Editor.H b/FL/Fl_Text_Editor.H
index 5bf49781e..16af25451 100644
--- a/FL/Fl_Text_Editor.H
+++ b/FL/Fl_Text_Editor.H
@@ -1,7 +1,7 @@
//
// Header file for Fl_Text_Editor class.
//
-// Copyright 2001-2010 by Bill Spitzak and others.
+// Copyright 2001-2023 by Bill Spitzak and others.
// Original code Copyright Mark Edel. Permission to distribute under
// the LGPL for the FLTK library granted by Mark Edel.
//
@@ -110,6 +110,7 @@ class FL_EXPORT Fl_Text_Editor : public Fl_Text_Display {
static int kf_paste(int c, Fl_Text_Editor* e);
static int kf_select_all(int c, Fl_Text_Editor* e);
static int kf_undo(int c, Fl_Text_Editor* e);
+ static int kf_redo(int c, Fl_Text_Editor* e);
protected:
int handle_key();
diff --git a/src/Fl_Input.cxx b/src/Fl_Input.cxx
index c191bfc6e..6dd026b00 100644
--- a/src/Fl_Input.cxx
+++ b/src/Fl_Input.cxx
@@ -1,7 +1,7 @@
//
// Input widget for the Fast Light Tool Kit (FLTK).
//
-// Copyright 1998-2021 by Bill Spitzak and others.
+// Copyright 1998-2023 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
@@ -275,10 +275,10 @@ int Fl_Input::kf_undo() {
return undo();
}
-// Redo. (currently unimplemented.. toggles undo() instead)
+// Redo.
int Fl_Input::kf_redo() {
if (readonly()) { fl_beep(); return 1; }
- return kf_undo(); // currently we don't support multilevel undo
+ return redo();
}
// Do a copy operation
diff --git a/src/Fl_Input_.cxx b/src/Fl_Input_.cxx
index a8f168b0e..cabbbd112 100644
--- a/src/Fl_Input_.cxx
+++ b/src/Fl_Input_.cxx
@@ -33,6 +33,7 @@ extern void fl_draw(const char*, int, float, float);
////////////////////////////////////////////////////////////////
+// see: Fl_Text_Undo_Action
class Fl_Input_Undo_Action {
public:
Fl_Input_Undo_Action() :
@@ -71,6 +72,50 @@ public:
}
};
+// see: Fl_Text_Undo_Action_List
+class Fl_Input_Undo_Action_List {
+ Fl_Input_Undo_Action** list_;
+ int list_size_;
+ int list_capacity_;
+public:
+ Fl_Input_Undo_Action_List() :
+ list_(NULL),
+ list_size_(0),
+ list_capacity_(0)
+ { }
+
+ ~Fl_Input_Undo_Action_List() {
+ clear();
+ }
+
+ void push(Fl_Input_Undo_Action* action) {
+ if (list_size_ == list_capacity_) {
+ list_capacity_ += 25;
+ list_ = (Fl_Input_Undo_Action**)realloc(list_, list_capacity_ * sizeof(Fl_Input_Undo_Action*));
+ }
+ list_[list_size_++] = action;
+ }
+
+ Fl_Input_Undo_Action* pop() {
+ if (list_size_ > 0)
+ return list_[--list_size_];
+ else
+ return NULL;
+ }
+
+ void clear() {
+ if (list_) {
+ for (int i=0; i<list_size_; i++) {
+ delete list_[i];
+ }
+ delete list_;
+ }
+ list_ = NULL;
+ list_size_ = 0;
+ list_capacity_ = 0;
+ }
+};
+
/** \internal
Converts a given text segment into the text that will be rendered on screen.
@@ -186,7 +231,7 @@ double Fl_Input_::expandpos(
/** \internal
Marks a range of characters for update.
- This call marks all characters from \p to the end of the
+ This call marks all characters from \p p to the end of the
text buffer for update. At least these characters
will be redrawn in the next update cycle.
@@ -891,6 +936,9 @@ int Fl_Input_::replace(int b, int e, const char* text, int ilen) {
} else if (e == undo_->undoat && (e-b)<undo_->undoinsert) {
undo_->undoinsert -= e-b;
} else {
+ redo_list_->clear();
+ undo_list_->push(undo_);
+ undo_ = new Fl_Input_Undo_Action();
undo_->undobuffersize(e-b);
memcpy(undo_->undobuffer, value_+b, e-b);
undo_->undocut = e-b;
@@ -903,9 +951,12 @@ int Fl_Input_::replace(int b, int e, const char* text, int ilen) {
}
if (ilen) {
- if (b == undo_->undoat)
+ if (b == undo_->undoat) {
undo_->undoinsert += ilen;
- else {
+ } else {
+ redo_list_->clear();
+ undo_list_->push(undo_);
+ undo_ = new Fl_Input_Undo_Action();
undo_->undocut = 0;
undo_->undoinsert = ilen;
}
@@ -947,13 +998,13 @@ int Fl_Input_::replace(int b, int e, const char* text, int ilen) {
}
/**
- Undoes previous changes to the text buffer.
+ Apply the current undo/redo operation
- This call undoes a number of previous calls to replace().
+ It's up to undo() and redo() to push and pop actions to and from the lists.
- \return non-zero if any change was made.
-*/
-int Fl_Input_::undo() {
+ \return 1 if the current action changed any text.
+ \see undo(), redo() */
+int Fl_Input_::apply_undo() {
was_up_down = 0;
if (!undo_->undocut && !undo_->undoinsert) return 0;
@@ -962,6 +1013,8 @@ int Fl_Input_::undo() {
int b = undo_->undoat-xlen;
int b1 = b;
+ minimal_update(position_);
+
put_in_buffer(size_+ilen);
if (ilen) {
@@ -989,11 +1042,53 @@ int Fl_Input_::undo() {
while (b1 > 0 && index(b1)!='\n') b1--;
minimal_update(b1);
set_changed();
+
+ return 1;
+}
+
+/**
+ Undoes previous changes to the text buffer.
+
+ This call undoes a number of previous calls to replace().
+
+ \return non-zero if any change was made.
+ */
+int Fl_Input_::undo() {
+ if (apply_undo() == 0)
+ return 0;
+
+ redo_list_->push(undo_);
+ undo_ = undo_list_->pop();
+ if (!undo_) undo_ = new Fl_Input_Undo_Action();
+
if (when()&FL_WHEN_CHANGED) do_callback(FL_REASON_CHANGED);
+
return 1;
}
/**
+ Redo previous undo operation.
+
+ This call reapplies previously executed undo operations.
+
+ \return non-zero if any change was made.
+ */
+int Fl_Input_::redo() {
+ Fl_Input_Undo_Action *redo_action = redo_list_->pop();
+ if (!redo_action)
+ return 0;
+
+ if (undo_->undocut || undo_->undoinsert)
+ undo_list_->push(undo_);
+ undo_ = redo_action;
+
+ int ret = apply_undo();
+ if (ret && (when()&FL_WHEN_CHANGED)) do_callback(FL_REASON_CHANGED);
+
+ return ret;
+}
+
+/**
Copies the \e yank buffer to the clipboard.
This method copies all the previous contiguous cuts from the undo
@@ -1168,6 +1263,8 @@ Fl_Input_::Fl_Input_(int X, int Y, int W, int H, const char* l)
xscroll_ = yscroll_ = 0;
maximum_size_ = 32767;
shortcut_ = 0;
+ undo_list_ = new Fl_Input_Undo_Action_List();
+ redo_list_ = new Fl_Input_Undo_Action_List();
undo_ = new Fl_Input_Undo_Action();
set_flag(SHORTCUT_LABEL);
set_flag(MAC_USE_ACCENTS_MENU);
@@ -1236,6 +1333,8 @@ void Fl_Input_::put_in_buffer(int len) {
int Fl_Input_::static_value(const char* str, int len) {
clear_changed();
undo_->clear();
+ undo_list_->clear();
+ redo_list_->clear();
if (str == value_ && len == size_) return 0;
if (len) { // non-empty new value:
if (xscroll_ || yscroll_) {
@@ -1336,6 +1435,8 @@ void Fl_Input_::resize(int X, int Y, int W, int H) {
from the parent Fl_Group.
*/
Fl_Input_::~Fl_Input_() {
+ delete undo_list_;
+ delete redo_list_;
delete undo_;
if (bufsize) free((void*)buffer);
}
diff --git a/src/Fl_Text_Buffer.cxx b/src/Fl_Text_Buffer.cxx
index 638a3d023..620b3d145 100644
--- a/src/Fl_Text_Buffer.cxx
+++ b/src/Fl_Text_Buffer.cxx
@@ -1,5 +1,5 @@
//
-// Copyright 2001-2017 by Bill Spitzak and others.
+// Copyright 2001-2023 by Bill Spitzak and others.
// Original code Copyright Mark Edel. Permission to distribute under
// the LGPL for the FLTK library granted by Mark Edel.
//
@@ -66,6 +66,23 @@ static int min(int i1, int i2)
#endif
+/*
+ Undo/Redo is handled with Fl_Text_Undo_Action. The names of the class members
+ relate to the original action.
+
+ Deleting text will store the number of bytes deleted in `undocut`, and store
+ the deleted text in `undobuffer`. `undoat` is the insertion position.
+
+ Inserting text will store the number of bytes inserted in `undoinsert` and
+ `undoat` will point after the inserted text.
+
+ If text is deleted first and then text is inserted at the same position, it's
+ called a yankcut, and the number of bytes that were deleted is stored in
+ `undoyankcut`, again storing the deleted text in `undobuffer`.
+
+ If an undo action is run, text is deleted and inserted via the normal
+ Fl_Text_Editor methods, generating the inverse undo action (redo) in mUndo.
+ */
class Fl_Text_Undo_Action {
public:
Fl_Text_Undo_Action() :
@@ -102,6 +119,76 @@ public:
void clear() {
undocut = undoinsert = 0;
}
+
+ bool empty() {
+ return (!undocut && !undoinsert);
+ }
+};
+
+/*
+ Undo events are stored in a Last In - First Out stack.
+
+ Any insertion or deletion of text will either add to the current undo event
+ in mUndo, or generate a new undo event if cursor positions are not consecutive.
+ The previously current undo event will then be pushed to the undo list and
+ the redo event list is purged.
+
+ If the user calls undo(), the current undo event in mUndo will be run,
+ generating a matching redo event in mUndo. The redo event is then pushed into
+ the redo list, and the next undo event is popped from the undo list and made
+ current.
+
+ A list can be locked to be protected from purging while running an undo event.
+ */
+class Fl_Text_Undo_Action_List {
+ Fl_Text_Undo_Action** list_;
+ int list_size_;
+ int list_capacity_;
+ bool locked_;
+public:
+ Fl_Text_Undo_Action_List() :
+ list_(NULL),
+ list_size_(0),
+ list_capacity_(0),
+ locked_(false)
+ { }
+
+ ~Fl_Text_Undo_Action_List() {
+ unlock();
+ clear();
+ }
+
+ void push(Fl_Text_Undo_Action* action) {
+ if (list_size_ == list_capacity_) {
+ list_capacity_ += 25;
+ list_ = (Fl_Text_Undo_Action**)realloc(list_, list_capacity_ * sizeof(Fl_Text_Undo_Action*));
+ }
+ list_[list_size_++] = action;
+ }
+
+ Fl_Text_Undo_Action* pop() {
+ if (list_size_ > 0) {
+ Fl_Text_Undo_Action *action = list_[list_size_-1];
+ return list_[--list_size_];
+ } else
+ return NULL;
+ }
+
+ void clear() {
+ if (locked_) return;
+ if (list_) {
+ for (int i=0; i<list_size_; i++) {
+ delete list_[i];
+ }
+ delete list_;
+ }
+ list_ = NULL;
+ list_size_ = 0;
+ list_capacity_ = 0;
+ }
+
+ void lock() { locked_ = true; }
+ void unlock() { locked_ = false; }
};
@@ -136,6 +223,8 @@ Fl_Text_Buffer::Fl_Text_Buffer(int requestedSize, int preferredGapSize)
mCursorPosHint = 0;
mCanUndo = 1;
mUndo = new Fl_Text_Undo_Action();
+ mUndoList = new Fl_Text_Undo_Action_List();
+ mRedoList = new Fl_Text_Undo_Action_List();
input_file_was_transcoded = 0;
transcoding_warning_action = def_transcoding_warning_action;
}
@@ -156,6 +245,8 @@ Fl_Text_Buffer::~Fl_Text_Buffer()
delete[] mPredeleteCbArgs;
}
delete mUndo;
+ delete mUndoList;
+ delete mRedoList;
}
@@ -205,8 +296,11 @@ void Fl_Text_Buffer::text(const char *t)
call_modify_callbacks(0, deletedLength, insertedLength, 0, deletedText);
free((void *) deletedText);
- if (mCanUndo)
+ if (mCanUndo) {
mUndo->clear();
+ mUndoList->clear();
+ mRedoList->clear();
+ }
}
@@ -459,51 +553,97 @@ void Fl_Text_Buffer::copy(Fl_Text_Buffer * fromBuf, int fromStart,
}
-/*
- Take the previous changes and undo them. Return the previous
- cursor position in cursorPos. Returns 1 if the undo was applied.
- CursorPos will be at a character boundary.
+/**
+ Apply the current undo/redo operation, called from undo() or redo().
*/
-int Fl_Text_Buffer::undo(int *cursorPos)
+int Fl_Text_Buffer::apply_undo(Fl_Text_Undo_Action* action, int* cursorPos)
{
- if (!mCanUndo)
+ if (action->empty())
return 0;
- if (!mUndo->undocut && !mUndo->undoinsert)
- return 0;
+ mRedoList->lock();
- int ilen = mUndo->undocut;
- int xlen = mUndo->undoinsert;
- int b = mUndo->undoat - xlen;
+ int ilen = action->undocut;
+ int xlen = action->undoinsert;
+ int b = action->undoat - xlen;
- if (xlen && mUndo->undoyankcut && !ilen) {
- ilen = mUndo->undoyankcut;
+ if (xlen && action->undoyankcut && !ilen) {
+ ilen = action->undoyankcut;
}
if (xlen && ilen) {
- mUndo->undobuffersize(ilen + 1);
- mUndo->undobuffer[ilen] = 0;
- char *tmp = fl_strdup(mUndo->undobuffer);
- replace(b, mUndo->undoat, tmp);
+ action->undobuffersize(ilen + 1);
+ action->undobuffer[ilen] = 0;
+ char *tmp = fl_strdup(action->undobuffer);
+ replace(b, action->undoat, tmp);
if (cursorPos)
*cursorPos = mCursorPosHint;
free(tmp);
} else if (xlen) {
- remove(b, mUndo->undoat);
+ remove(b, action->undoat);
if (cursorPos)
*cursorPos = mCursorPosHint;
} else if (ilen) {
- mUndo->undobuffersize(ilen + 1);
- mUndo->undobuffer[ilen] = 0;
- insert(mUndo->undoat, mUndo->undobuffer);
+ action->undobuffersize(ilen + 1);
+ action->undobuffer[ilen] = 0;
+ insert(action->undoat, action->undobuffer);
if (cursorPos)
*cursorPos = mCursorPosHint;
- mUndo->undoyankcut = 0;
+ action->undoyankcut = 0;
}
+ mRedoList->unlock();
return 1;
}
+/**
+ Take the previous changes and undo them. Return the previous
+ cursor position in cursorPos. Returns 1 if the undo was applied.
+ CursorPos will be at a character boundary.
+ */
+int Fl_Text_Buffer::undo(int *cursorPos) {
+ if (!mCanUndo || mUndo->empty())
+ return 0;
+
+ // save the current undo action and add an empty action to avoid generating yankcuts
+ Fl_Text_Undo_Action* action = mUndo;
+ mUndo = new Fl_Text_Undo_Action();
+
+ int ret = apply_undo(action, cursorPos);
+ delete action;
+
+ if (ret) {
+ // push the generated undo action to the redo list
+ mRedoList->push(mUndo);
+ // drop the empty action we previously created
+ mUndo = mUndoList->pop();
+ if (mUndo) {
+ delete mUndo;
+ // pop the undo action before that and make it the current undo action
+ mUndo = mUndoList->pop();
+ if (!mUndo) mUndo = new Fl_Text_Undo_Action();
+ }
+ }
+
+ return ret;
+}
+
+/**
+ Redo previous undo action.
+ */
+int Fl_Text_Buffer::redo(int *cursorPos) {
+ if (!mCanUndo)
+ return 0;
+
+ Fl_Text_Undo_Action *redo_action = mRedoList->pop();
+ if (!redo_action)
+ return 0;
+
+ // running the redo action will also generate a new undo action
+ // Note: there is a slight chance that the current undo action and the
+ // generated action merge into one.
+ return apply_undo(redo_action, cursorPos);
+}
/*
Set a flag if undo function will work.
@@ -1218,10 +1358,20 @@ int Fl_Text_Buffer::insert_(int pos, const char *text)
if (mCanUndo) {
if (mUndo->undoat == pos && mUndo->undoinsert) {
+ // continue inserting text at the given cursor position
mUndo->undoinsert += insertedLength;
} else {
+ int yankcut = (mUndo->undoat == pos) ? mUndo->undocut : 0;
+ if (!yankcut) {
+ // insert text at a new position, so generate a new undo action
+ mRedoList->clear();
+ mUndoList->push(mUndo);
+ mUndo = new Fl_Text_Undo_Action();
+ } else {
+ // we deleted and inserted at the same position, making this a yankcut
+ }
mUndo->undoinsert = insertedLength;
- mUndo->undoyankcut = (mUndo->undoat == pos) ? mUndo->undocut : 0;
+ mUndo->undoyankcut = yankcut;
}
mUndo->undoat = pos + insertedLength;
mUndo->undocut = 0;
@@ -1241,10 +1391,15 @@ void Fl_Text_Buffer::remove_(int start, int end)
if (mCanUndo) {
if (mUndo->undoat == end && mUndo->undocut) {
+ // continue to remove text at the same cursor position
mUndo->undobuffersize(mUndo->undocut + end - start + 1);
memmove(mUndo->undobuffer + end - start, mUndo->undobuffer, mUndo->undocut);
mUndo->undocut += end - start;
} else {
+ // remove text at a new position, so generate a new undo action
+ mRedoList->clear();
+ mUndoList->push(mUndo);
+ mUndo = new Fl_Text_Undo_Action();
mUndo->undocut = end - start;
mUndo->undobuffersize(mUndo->undocut);
}
diff --git a/src/Fl_Text_Editor.cxx b/src/Fl_Text_Editor.cxx
index 81dc2f441..c548ef6be 100644
--- a/src/Fl_Text_Editor.cxx
+++ b/src/Fl_Text_Editor.cxx
@@ -1,5 +1,5 @@
//
-// Copyright 2001-2018 by Bill Spitzak and others.
+// Copyright 2001-2023 by Bill Spitzak and others.
//
// Original code Copyright Mark Edel. Permission to distribute under
// the LGPL for the FLTK library granted by Mark Edel.
@@ -132,7 +132,9 @@ static struct {
{ FL_Page_Down, FL_CTRL|FL_SHIFT, Fl_Text_Editor::kf_c_s_move },
//{ FL_Clear, 0, Fl_Text_Editor::delete_to_eol },
{ 'z', FL_CTRL, Fl_Text_Editor::kf_undo },
- { '/', FL_CTRL, Fl_Text_Editor::kf_undo },
+ { 'z', FL_CTRL|FL_SHIFT, Fl_Text_Editor::kf_redo }, // MSWindows screen driver also defines Ctrl-Y
+ { '/', FL_CTRL, Fl_Text_Editor::kf_undo }, // Emacs
+ { '?', FL_CTRL, Fl_Text_Editor::kf_redo }, // Emacs
{ 'x', FL_CTRL, Fl_Text_Editor::kf_cut },
{ FL_Delete, FL_SHIFT, Fl_Text_Editor::kf_cut },
{ 'c', FL_CTRL, Fl_Text_Editor::kf_copy },
@@ -596,13 +598,13 @@ int Fl_Text_Editor::kf_select_all(int, Fl_Text_Editor* e) {
}
/** Undo last edit in the current buffer of editor \p 'e'.
- Also deselects previous selection.
- The key value \p 'c' is currently unused.
-*/
+ Also deselects previous selection.
+ The key value \p 'c' is currently unused.
+ */
int Fl_Text_Editor::kf_undo(int , Fl_Text_Editor* e) {
e->buffer()->unselect();
Fl::copy("", 0, 0);
- int crsr;
+ int crsr = e->insert_position();
int ret = e->buffer()->undo(&crsr);
e->insert_position(crsr);
e->show_insert_position();
@@ -611,6 +613,22 @@ int Fl_Text_Editor::kf_undo(int , Fl_Text_Editor* e) {
return ret;
}
+/** Redo last undo action.
+ Also deselects previous selection.
+ The key value \p 'c' is currently unused.
+ */
+int Fl_Text_Editor::kf_redo(int , Fl_Text_Editor* e) {
+ e->buffer()->unselect();
+ Fl::copy("", 0, 0);
+ int crsr = e->insert_position();
+ int ret = e->buffer()->redo(&crsr);
+ e->insert_position(crsr);
+ e->show_insert_position();
+ e->set_changed();
+ if (e->when()&FL_WHEN_CHANGED) e->do_callback();
+ return ret;
+}
+
/** Handles a key press in the editor */
int Fl_Text_Editor::handle_key() {
// Call FLTK's rules to try to turn this into a printing character.
diff --git a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx
index 76eee9e12..012261b2c 100644
--- a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx
+++ b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx
@@ -1,7 +1,7 @@
//
// Definition of Apple Cocoa Screen interface.
//
-// Copyright 1998-2022 by Bill Spitzak and others.
+// Copyright 1998-2023 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
@@ -79,6 +79,7 @@ Fl_Screen_Driver::Keyname darwin_key_table[] = {
static Fl_Text_Editor::Key_Binding extra_bindings[] = {
// Define CMD+key accelerators...
{ 'z', FL_COMMAND, Fl_Text_Editor::kf_undo ,0},
+ { 'z', FL_COMMAND|FL_SHIFT, Fl_Text_Editor::kf_redo ,0},
{ 'x', FL_COMMAND, Fl_Text_Editor::kf_cut ,0},
{ 'c', FL_COMMAND, Fl_Text_Editor::kf_copy ,0},
{ 'v', FL_COMMAND, Fl_Text_Editor::kf_paste ,0},
diff --git a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H
index 3bb5e11a6..3bbd51d59 100644
--- a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H
+++ b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H
@@ -41,9 +41,7 @@ protected:
public:
float dpi[MAX_SCREENS][2];
- Fl_WinAPI_Screen_Driver() : Fl_Screen_Driver() {
- for (int i = 0; i < MAX_SCREENS; i++) scale_of_screen[i] = 1;
- }
+ Fl_WinAPI_Screen_Driver();
// --- display management
int visual(int flags) FL_OVERRIDE;
// --- screen configuration
diff --git a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx
index 1f9ed3249..452815afb 100644
--- a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx
+++ b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx
@@ -38,6 +38,17 @@ extern const char *fl_bg2;
# include <multimon.h>
#endif // !HMONITOR_DECLARED && _WIN32_WINNT < 0x0500
+static Fl_Text_Editor::Key_Binding extra_bindings[] = {
+ // Define MS Windows specific accelerators...
+ { 'y', FL_CTRL, Fl_Text_Editor::kf_redo ,0},
+ { 0, 0, 0 ,0}
+};
+
+
+Fl_WinAPI_Screen_Driver::Fl_WinAPI_Screen_Driver() : Fl_Screen_Driver() {
+ text_editor_extra_key_bindings = extra_bindings;
+ for (int i = 0; i < MAX_SCREENS; i++) scale_of_screen[i] = 1;
+}
int Fl_WinAPI_Screen_Driver::visual(int flags)
{