added single char aggregation for undos

fixed potential bug when moving cursor one word left
This commit is contained in:
thrust26 2020-11-06 14:38:33 +01:00
parent d7171b5260
commit 6c315c76be
3 changed files with 99 additions and 27 deletions

View File

@ -90,7 +90,7 @@ bool EditableWidget::tryInsertChar(char c, int pos)
if(_filter(tolower(c))) if(_filter(tolower(c)))
{ {
_editString.insert(pos, 1, c); _editString.insert(pos, 1, c);
myUndoHandler->doo(_editString); myUndoHandler->doChar(); // aggregate single chars
return true; return true;
} }
return false; return false;
@ -140,7 +140,6 @@ bool EditableWidget::handleControlKeys(StellaKey key, StellaMod mod)
{ {
bool shift = StellaModTest::isShift(mod); bool shift = StellaModTest::isShift(mod);
bool handled = true; bool handled = true;
bool dirty = true;
switch(key) switch(key)
{ {
@ -154,13 +153,13 @@ bool EditableWidget::handleControlKeys(StellaKey key, StellaMod mod)
handled = copySelectedText(); handled = copySelectedText();
break; break;
case KBDK_E: //case KBDK_E:
if(shift) // if(shift)
_selectSize += _caretPos - int(_editString.size()); // _selectSize += _caretPos - int(_editString.size());
else // else
_selectSize = 0; // _selectSize = 0;
setCaretPos(int(_editString.size())); // setCaretPos(int(_editString.size()));
break; // break;
case KBDK_D: case KBDK_D:
handled = killChar(+1); handled = killChar(+1);
@ -196,13 +195,29 @@ bool EditableWidget::handleControlKeys(StellaKey key, StellaMod mod)
case KBDK_Y: case KBDK_Y:
case KBDK_Z: case KBDK_Z:
{
string oldString = _editString;
myUndoHandler->endChars(_editString);
// Reverse Y and Z for QWERTZ keyboards
if(key == KBDK_Y != instance().eventHandler().isQwertz()) if(key == KBDK_Y != instance().eventHandler().isQwertz())
dirty = myUndoHandler->redo(_editString); handled = myUndoHandler->redo(_editString);
else else
dirty = myUndoHandler->undo(_editString); if(shift)
_caretPos = int(_editString.size()); // TODO: put at last difference handled = myUndoHandler->redo(_editString);
else
handled = myUndoHandler->undo(_editString);
if(handled)
{
// Put caret at last difference
myUndoHandler->lastDiff(_editString, oldString);
_caretPos = myUndoHandler->lastDiff(_editString, oldString);
_selectSize = 0; _selectSize = 0;
sendCommand(EditableWidget::kChangedCmd, key, _id);
}
break; break;
}
case KBDK_LEFT: case KBDK_LEFT:
handled = moveWord(-1, shift); handled = moveWord(-1, shift);
@ -218,11 +233,13 @@ bool EditableWidget::handleControlKeys(StellaKey key, StellaMod mod)
default: default:
handled = false; handled = false;
dirty = false;
} }
if(dirty) if(handled)
{
myUndoHandler->endChars(_editString);
setDirty(); setDirty();
}
return handled; return handled;
} }
@ -271,7 +288,10 @@ bool EditableWidget::handleShiftKeys(StellaKey key)
} }
if(handled) if(handled)
{
myUndoHandler->endChars(_editString);
setDirty(); setDirty();
}
return handled; return handled;
} }
@ -321,7 +341,7 @@ bool EditableWidget::handleNormalKeys(StellaKey key)
break; break;
case KBDK_LEFT: case KBDK_LEFT:
if (_selectSize) if(_selectSize)
handled = setCaretPos(selectStartPos()); handled = setCaretPos(selectStartPos());
else if(_caretPos > 0) else if(_caretPos > 0)
handled = setCaretPos(_caretPos - 1); handled = setCaretPos(_caretPos - 1);
@ -348,7 +368,10 @@ bool EditableWidget::handleNormalKeys(StellaKey key)
} }
if(handled) if(handled)
{
myUndoHandler->endChars(_editString);
setDirty(); setDirty();
}
if(!selectMode) if(!selectMode)
_selectSize = 0; _selectSize = 0;
@ -490,6 +513,7 @@ bool EditableWidget::killChar(int direction, bool addEdit)
{ {
if(_caretPos > 0) if(_caretPos > 0)
{ {
myUndoHandler->endChars(_editString);
_caretPos--; _caretPos--;
_editString.erase(_caretPos, 1); _editString.erase(_caretPos, 1);
handled = true; handled = true;
@ -501,6 +525,7 @@ bool EditableWidget::killChar(int direction, bool addEdit)
} }
else if(direction == 1) // Delete next character (delete) else if(direction == 1) // Delete next character (delete)
{ {
myUndoHandler->endChars(_editString);
_editString.erase(_caretPos, 1); _editString.erase(_caretPos, 1);
handled = true; handled = true;
if(_selectSize > 0) if(_selectSize > 0)
@ -616,7 +641,7 @@ bool EditableWidget::moveWord(int direction, bool select)
{ {
while (currentPos < int(_editString.size())) while (currentPos < int(_editString.size()))
{ {
if (_editString[currentPos - 1] == ' ') if (currentPos && _editString[currentPos - 1] == ' ')
{ {
if (!space) if (!space)
break; break;
@ -677,6 +702,7 @@ bool EditableWidget::killSelectedText(bool addEdit)
{ {
if(_selectSize) if(_selectSize)
{ {
myUndoHandler->endChars(_editString);
if(_selectSize < 0) if(_selectSize < 0)
{ {
_caretPos += _selectSize; _caretPos += _selectSize;
@ -694,16 +720,7 @@ bool EditableWidget::killSelectedText(bool addEdit)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool EditableWidget::cutSelectedText() bool EditableWidget::cutSelectedText()
{ {
string selected = selectString(); return copySelectedText() && killSelectedText();
// only cut and copy if anything is selected, else keep old cut text
if(!selected.empty())
{
instance().eventHandler().copyText(selected);
killSelectedText();
return true;
}
return false;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -726,6 +743,8 @@ bool EditableWidget::pasteSelectedText()
bool selected = !selectString().empty(); bool selected = !selectString().empty();
string pasted; string pasted;
myUndoHandler->endChars(_editString);
// retrieve the pasted text // retrieve the pasted text
instance().eventHandler().pasteText(pasted); instance().eventHandler().pasteText(pasted);
// remove the currently selected text // remove the currently selected text

View File

@ -21,15 +21,35 @@
UndoHandler::UndoHandler(size_t size) UndoHandler::UndoHandler(size_t size)
: mySize(size) : mySize(size)
{ {
reset();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void UndoHandler::reset() void UndoHandler::reset()
{ {
myBuffer.clear(); myBuffer.clear();
myCharMode = false;
myRedoCount = 0; myRedoCount = 0;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void UndoHandler::doChar()
{
myCharMode = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool UndoHandler::endChars(const string& text)
{
if(myCharMode)
{
doo(text);
return true;
}
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void UndoHandler::doo(const string& text) void UndoHandler::doo(const string& text)
{ {
@ -43,6 +63,7 @@ void UndoHandler::doo(const string& text)
// add text to buffer // add text to buffer
myBuffer.push_front(text); myBuffer.push_front(text);
myCharMode = false;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -68,3 +89,18 @@ bool UndoHandler::redo(string& text)
} }
return false; return false;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 UndoHandler::lastDiff(const string& text, const string& oldText) const
{
uInt32 pos = uInt32(text.size());
for(auto itn = text.crbegin(), ito = oldText.crbegin();
itn != text.crend() && ito != oldText.crend(); ++itn, ++ito)
{
if(*itn != *ito)
break;
pos--;
}
return uInt32(pos);
}

View File

@ -33,14 +33,31 @@ class UndoHandler
UndoHandler(size_t size = 100); UndoHandler(size_t size = 100);
~UndoHandler() = default; ~UndoHandler() = default;
// Reset undo buffer
void reset(); void reset();
// Add input to undo buffer
void doo(const string& text); void doo(const string& text);
// Retrieve last input from undo buffer
bool undo(string& text); bool undo(string& text);
// Retrieve next input from undo buffer
bool redo(string& text); bool redo(string& text);
// Add single char for aggregation
void doChar();
// Add aggregated single chars to undo buffer
bool endChars(const string& text);
// Get index into text of last different character
uInt32 lastDiff(const string& text, const string& oldText) const;
private: private:
std::deque<string> myBuffer; std::deque<string> myBuffer;
// Undo buffer size
size_t mySize{0}; size_t mySize{0};
// Aggregated single chars flag
bool myCharMode{false};
// Number of chars available for redo
uInt32 myRedoCount{0}; uInt32 myRedoCount{0};
private: private: