refactored undo functionality into UndoHandler class

This commit is contained in:
thrust26 2020-11-06 09:54:54 +01:00
parent c1cc678c19
commit f4ab26f350
7 changed files with 152 additions and 71 deletions

View File

@ -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<UndoHandler>();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -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;

View File

@ -19,10 +19,10 @@
#define EDITABLE_WIDGET_HXX
#include <functional>
#include <deque>
#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<UndoHandler> myUndoHandler;
std::deque<string> _editBuffer;
int _redoCount{0};
int _caretPos{0};
// Size of current selected text
// 0 = no selection
// <0 = selected left of caret

70
src/gui/UndoHandler.cxx Normal file
View File

@ -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;
}

53
src/gui/UndoHandler.hxx Normal file
View File

@ -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 <deque>
/**
* 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<string> 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

View File

@ -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 \

View File

@ -786,6 +786,7 @@
<ClCompile Include="..\gui\TimeLineWidget.cxx" />
<ClCompile Include="..\gui\TimeMachine.cxx" />
<ClCompile Include="..\gui\TimeMachineDialog.cxx" />
<ClCompile Include="..\gui\UndoHandler.cxx" />
<ClCompile Include="..\gui\WhatsNewDialog.cxx" />
<ClCompile Include="FSNodeWINDOWS.cxx" />
<ClCompile Include="OSystemWINDOWS.cxx" />
@ -1837,6 +1838,7 @@
<ClInclude Include="..\gui\TimeLineWidget.hxx" />
<ClInclude Include="..\gui\TimeMachine.hxx" />
<ClInclude Include="..\gui\TimeMachineDialog.hxx" />
<ClInclude Include="..\gui\UndoHandler.hxx" />
<ClInclude Include="..\gui\WhatsNewDialog.hxx" />
<ClInclude Include="..\libpng\pngdebug.h" />
<ClInclude Include="..\libpng\pnginfo.h" />

View File

@ -1029,6 +1029,9 @@
<ClCompile Include="..\common\VideoModeHandler.cxx">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\gui\UndoHandler.cxx">
<Filter>Source Files\gui</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\common\bspf.hxx">
@ -2117,6 +2120,9 @@
<ClInclude Include="..\emucore\FBBackend.hxx">
<Filter>Header Files\emucore</Filter>
</ClInclude>
<ClInclude Include="..\gui\UndoHandler.hxx">
<Filter>Header Files\gui</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="stella.ico">