diff --git a/src/gui/EditableWidget.cxx b/src/gui/EditableWidget.cxx index 76b592516..d7f0e4aea 100644 --- a/src/gui/EditableWidget.cxx +++ b/src/gui/EditableWidget.cxx @@ -21,6 +21,7 @@ #include "Font.hxx" #include "OSystem.hxx" #include "EventHandler.hxx" +#include "UndoHandler.hxx" #include "EditableWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -36,6 +37,8 @@ EditableWidget::EditableWidget(GuiObject* boss, const GUI::Font& font, _bgcolorlo = kDlgColor; _textcolor = kTextColor; _textcolorhi = kTextColor; + + myUndoHandler = make_unique(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -47,8 +50,8 @@ void EditableWidget::setText(const string& str, bool) if(_filter(tolower(c))) _editString.push_back(c); - clearEdits(); - doEdit(); + myUndoHandler->reset(); + myUndoHandler->doo(_editString); _caretPos = int(_editString.size()); _selectSize = 0; @@ -81,64 +84,13 @@ void EditableWidget::lostFocusWidget() _selectSize = 0; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void EditableWidget::clearEdits() -{ - _editBuffer.clear(); - _redoCount = 0; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void EditableWidget::doEdit() -{ - constexpr size_t UNDO_SIZE = 100; - - // clear redos - for(; _redoCount; _redoCount--) - _editBuffer.pop_back(); - - if(_editBuffer.size() == UNDO_SIZE) - _editBuffer.pop_front(); - _editBuffer.push_back(_editString); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool EditableWidget::undoEdit() -{ - if(_editBuffer.size() - _redoCount - 1) - { - _redoCount++; - _editString = _editBuffer[_editBuffer.size() - _redoCount - 1]; - _caretPos = int(_editString.size()); // TODO: put at last difference - _selectSize = 0; - - return true; - } - return false; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool EditableWidget::redoEdit() -{ - if(_redoCount) - { - _redoCount--; - _editString = _editBuffer[_editBuffer.size() - _redoCount - 1]; - _caretPos = int(_editString.size()); // TODO: put at last difference - _selectSize = 0; - - return true; - } - return false; -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EditableWidget::tryInsertChar(char c, int pos) { if(_filter(tolower(c))) { _editString.insert(pos, 1, c); - doEdit(); + myUndoHandler->doo(_editString); return true; } return false; @@ -245,9 +197,11 @@ bool EditableWidget::handleControlKeys(StellaKey key, StellaMod mod) case KBDK_Y: case KBDK_Z: if(key == KBDK_Y != instance().eventHandler().isQwertz()) - dirty = redoEdit(); + dirty = myUndoHandler->redo(_editString); else - dirty = undoEdit(); + dirty = myUndoHandler->undo(_editString); + _caretPos = int(_editString.size()); // TODO: put at last difference + _selectSize = 0; break; case KBDK_LEFT: @@ -542,7 +496,7 @@ bool EditableWidget::killChar(int direction, bool addEdit) if(_selectSize < 0) _selectSize++; if(addEdit) - doEdit(); + myUndoHandler->doo(_editString); } } else if(direction == 1) // Delete next character (delete) @@ -552,7 +506,7 @@ bool EditableWidget::killChar(int direction, bool addEdit) if(_selectSize > 0) _selectSize--; if(addEdit) - doEdit(); + myUndoHandler->doo(_editString); } return handled; @@ -575,7 +529,7 @@ bool EditableWidget::killLine(int direction) // remove selection for removed text if(_selectSize < 0) _selectSize = 0; - doEdit(); + myUndoHandler->doo(_editString); } } else if(direction == 1) // erase from current position to end of line @@ -590,7 +544,7 @@ bool EditableWidget::killLine(int direction) // remove selection for removed text if(_selectSize > 0) _selectSize = 0; - doEdit(); + myUndoHandler->doo(_editString); } } @@ -626,7 +580,7 @@ bool EditableWidget::killLastWord() // remove selection for removed word if(_selectSize < 0) _selectSize = std::min(_selectSize + count, 0); - doEdit(); + myUndoHandler->doo(_editString); } return handled; @@ -731,7 +685,7 @@ bool EditableWidget::killSelectedText(bool addEdit) _editString.erase(_caretPos, _selectSize); _selectSize = 0; if(addEdit) - doEdit(); + myUndoHandler->doo(_editString); return true; } return false; @@ -799,7 +753,7 @@ bool EditableWidget::pasteSelectedText() if(selected || !pasted.empty()) { - doEdit(); + myUndoHandler->doo(_editString); return true; } return false; diff --git a/src/gui/EditableWidget.hxx b/src/gui/EditableWidget.hxx index 4d5ff71dc..66c8dc20e 100644 --- a/src/gui/EditableWidget.hxx +++ b/src/gui/EditableWidget.hxx @@ -19,10 +19,10 @@ #define EDITABLE_WIDGET_HXX #include -#include #include "Widget.hxx" #include "Rect.hxx" +#include "UndoHandler.hxx" /** * Base class for widgets which need to edit text, like ListWidget and @@ -102,11 +102,6 @@ class EditableWidget : public Widget, public CommandSender bool cutSelectedText(); bool copySelectedText(); bool pasteSelectedText(); - // Undo - void clearEdits(); - void doEdit(); - bool undoEdit(); - bool redoEdit(); // Use the current TextFilter to insert a character into the // internal buffer @@ -115,10 +110,10 @@ class EditableWidget : public Widget, public CommandSender private: bool _editable{true}; string _editString; + unique_ptr myUndoHandler; - std::deque _editBuffer; - int _redoCount{0}; int _caretPos{0}; + // Size of current selected text // 0 = no selection // <0 = selected left of caret diff --git a/src/gui/UndoHandler.cxx b/src/gui/UndoHandler.cxx new file mode 100644 index 000000000..756dbb19a --- /dev/null +++ b/src/gui/UndoHandler.cxx @@ -0,0 +1,70 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#include "UndoHandler.hxx" + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +UndoHandler::UndoHandler(size_t size) + : myRedoCount(0), + mySize(size) +{} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void UndoHandler::reset() +{ + myBuffer.clear(); + myRedoCount = 0; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void UndoHandler::doo(const string& text) +{ + // clear redos + for(; myRedoCount; myRedoCount--) + myBuffer.pop_front(); + + // limit buffer size + if(myBuffer.size() == mySize) + myBuffer.pop_back(); + + // add text to buffer + myBuffer.push_front(text); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool UndoHandler::undo(string& text) +{ + if(myBuffer.size() > myRedoCount + 1) + { + text = myBuffer[++myRedoCount]; + + return true; + } + return false; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool UndoHandler::redo(string& text) +{ + if(myRedoCount) + { + text = myBuffer[--myRedoCount]; + + return true; + } + return false; +} diff --git a/src/gui/UndoHandler.hxx b/src/gui/UndoHandler.hxx new file mode 100644 index 000000000..42630671f --- /dev/null +++ b/src/gui/UndoHandler.hxx @@ -0,0 +1,53 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + + +#ifndef UNDO_HANDLER_HXX +#define UNDO_HANDLER_HXX + +#include "bspf.hxx" +#include + +/** + * Class for providing undo/redo functionality + * + * @author Thomas Jentzsch + */ +class UndoHandler +{ + public: + UndoHandler(size_t size = 100); + ~UndoHandler() = default; + + void reset(); + void doo(const string& text); + bool undo(string& text); + bool redo(string& text); + + private: + std::deque myBuffer; + size_t mySize; + uInt32 myRedoCount; + + private: + // Following constructors and assignment operators not supported + UndoHandler(const UndoHandler&) = delete; + UndoHandler(UndoHandler&&) = delete; + UndoHandler& operator=(const UndoHandler&) = delete; + UndoHandler& operator=(UndoHandler&&) = delete; +}; +#endif diff --git a/src/gui/module.mk b/src/gui/module.mk index d7412d2a2..a2f8489fd 100644 --- a/src/gui/module.mk +++ b/src/gui/module.mk @@ -49,6 +49,7 @@ MODULE_OBJS := \ src/gui/TimeLineWidget.o \ src/gui/TimeMachineDialog.o \ src/gui/TimeMachine.o \ + src/gui/UndoHandler.o \ src/gui/UIDialog.o \ src/gui/VideoAudioDialog.o \ src/gui/WhatsNewDialog.o \ diff --git a/src/windows/Stella.vcxproj b/src/windows/Stella.vcxproj index 420c63513..5f0bd9126 100644 --- a/src/windows/Stella.vcxproj +++ b/src/windows/Stella.vcxproj @@ -786,6 +786,7 @@ + @@ -1837,6 +1838,7 @@ + diff --git a/src/windows/Stella.vcxproj.filters b/src/windows/Stella.vcxproj.filters index 44f2539a2..8dca2be2e 100644 --- a/src/windows/Stella.vcxproj.filters +++ b/src/windows/Stella.vcxproj.filters @@ -1029,6 +1029,9 @@ Source Files + + Source Files\gui + @@ -2117,6 +2120,9 @@ Header Files\emucore + + Header Files\gui +