diff --git a/src/gui/EditableWidget.cxx b/src/gui/EditableWidget.cxx index d7f0e4aea..48bc79013 100644 --- a/src/gui/EditableWidget.cxx +++ b/src/gui/EditableWidget.cxx @@ -90,7 +90,7 @@ bool EditableWidget::tryInsertChar(char c, int pos) if(_filter(tolower(c))) { _editString.insert(pos, 1, c); - myUndoHandler->doo(_editString); + myUndoHandler->doChar(); // aggregate single chars return true; } return false; @@ -140,7 +140,6 @@ bool EditableWidget::handleControlKeys(StellaKey key, StellaMod mod) { bool shift = StellaModTest::isShift(mod); bool handled = true; - bool dirty = true; switch(key) { @@ -154,13 +153,13 @@ bool EditableWidget::handleControlKeys(StellaKey key, StellaMod mod) handled = copySelectedText(); break; - case KBDK_E: - if(shift) - _selectSize += _caretPos - int(_editString.size()); - else - _selectSize = 0; - setCaretPos(int(_editString.size())); - break; + //case KBDK_E: + // if(shift) + // _selectSize += _caretPos - int(_editString.size()); + // else + // _selectSize = 0; + // setCaretPos(int(_editString.size())); + // break; case KBDK_D: handled = killChar(+1); @@ -196,13 +195,29 @@ bool EditableWidget::handleControlKeys(StellaKey key, StellaMod mod) case KBDK_Y: case KBDK_Z: + { + string oldString = _editString; + + myUndoHandler->endChars(_editString); + // Reverse Y and Z for QWERTZ keyboards if(key == KBDK_Y != instance().eventHandler().isQwertz()) - dirty = myUndoHandler->redo(_editString); + handled = myUndoHandler->redo(_editString); else - dirty = myUndoHandler->undo(_editString); - _caretPos = int(_editString.size()); // TODO: put at last difference - _selectSize = 0; + if(shift) + 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; + sendCommand(EditableWidget::kChangedCmd, key, _id); + } break; + } case KBDK_LEFT: handled = moveWord(-1, shift); @@ -218,11 +233,13 @@ bool EditableWidget::handleControlKeys(StellaKey key, StellaMod mod) default: handled = false; - dirty = false; } - if(dirty) + if(handled) + { + myUndoHandler->endChars(_editString); setDirty(); + } return handled; } @@ -271,7 +288,10 @@ bool EditableWidget::handleShiftKeys(StellaKey key) } if(handled) + { + myUndoHandler->endChars(_editString); setDirty(); + } return handled; } @@ -321,7 +341,7 @@ bool EditableWidget::handleNormalKeys(StellaKey key) break; case KBDK_LEFT: - if (_selectSize) + if(_selectSize) handled = setCaretPos(selectStartPos()); else if(_caretPos > 0) handled = setCaretPos(_caretPos - 1); @@ -348,7 +368,10 @@ bool EditableWidget::handleNormalKeys(StellaKey key) } if(handled) + { + myUndoHandler->endChars(_editString); setDirty(); + } if(!selectMode) _selectSize = 0; @@ -490,6 +513,7 @@ bool EditableWidget::killChar(int direction, bool addEdit) { if(_caretPos > 0) { + myUndoHandler->endChars(_editString); _caretPos--; _editString.erase(_caretPos, 1); handled = true; @@ -501,6 +525,7 @@ bool EditableWidget::killChar(int direction, bool addEdit) } else if(direction == 1) // Delete next character (delete) { + myUndoHandler->endChars(_editString); _editString.erase(_caretPos, 1); handled = true; if(_selectSize > 0) @@ -616,7 +641,7 @@ bool EditableWidget::moveWord(int direction, bool select) { while (currentPos < int(_editString.size())) { - if (_editString[currentPos - 1] == ' ') + if (currentPos && _editString[currentPos - 1] == ' ') { if (!space) break; @@ -677,6 +702,7 @@ bool EditableWidget::killSelectedText(bool addEdit) { if(_selectSize) { + myUndoHandler->endChars(_editString); if(_selectSize < 0) { _caretPos += _selectSize; @@ -694,16 +720,7 @@ bool EditableWidget::killSelectedText(bool addEdit) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EditableWidget::cutSelectedText() { - string selected = selectString(); - - // 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; + return copySelectedText() && killSelectedText(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -726,6 +743,8 @@ bool EditableWidget::pasteSelectedText() bool selected = !selectString().empty(); string pasted; + myUndoHandler->endChars(_editString); + // retrieve the pasted text instance().eventHandler().pasteText(pasted); // remove the currently selected text diff --git a/src/gui/UndoHandler.cxx b/src/gui/UndoHandler.cxx index daaa95bd3..92dd4d2d8 100644 --- a/src/gui/UndoHandler.cxx +++ b/src/gui/UndoHandler.cxx @@ -21,15 +21,35 @@ UndoHandler::UndoHandler(size_t size) : mySize(size) { + reset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void UndoHandler::reset() { myBuffer.clear(); + myCharMode = false; 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) { @@ -43,6 +63,7 @@ void UndoHandler::doo(const string& text) // add text to buffer myBuffer.push_front(text); + myCharMode = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -68,3 +89,18 @@ bool UndoHandler::redo(string& text) } 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); +} \ No newline at end of file diff --git a/src/gui/UndoHandler.hxx b/src/gui/UndoHandler.hxx index b9e832880..499423caf 100644 --- a/src/gui/UndoHandler.hxx +++ b/src/gui/UndoHandler.hxx @@ -33,14 +33,31 @@ class UndoHandler UndoHandler(size_t size = 100); ~UndoHandler() = default; + // Reset undo buffer void reset(); + + // Add input to undo buffer void doo(const string& text); + // Retrieve last input from undo buffer bool undo(string& text); + // Retrieve next input from undo buffer 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: std::deque myBuffer; + // Undo buffer size size_t mySize{0}; + // Aggregated single chars flag + bool myCharMode{false}; + // Number of chars available for redo uInt32 myRedoCount{0}; private: