mirror of https://github.com/stella-emu/stella.git
added undo/redo to EditableWidget
This commit is contained in:
parent
7ef46b366d
commit
b2fa192529
|
@ -27,6 +27,15 @@ EventHandlerSDL2::EventHandlerSDL2(OSystem& osystem)
|
||||||
{
|
{
|
||||||
ASSERT_MAIN_THREAD;
|
ASSERT_MAIN_THREAD;
|
||||||
|
|
||||||
|
#ifdef GUI_SUPPORT
|
||||||
|
{
|
||||||
|
ostringstream buf;
|
||||||
|
myQwertz = int('y') == int(SDL_GetKeyFromScancode(SDL_Scancode(KBDK_Z)));
|
||||||
|
buf << "Keyboard: " << (myQwertz ? "QWERTZ" : "QWERTY");
|
||||||
|
Logger::debug(buf.str());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef JOYSTICK_SUPPORT
|
#ifdef JOYSTICK_SUPPORT
|
||||||
if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
|
if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -338,6 +338,11 @@ class EventHandler
|
||||||
virtual void enableTextEvents(bool enable) = 0;
|
virtual void enableTextEvents(bool enable) = 0;
|
||||||
|
|
||||||
#ifdef GUI_SUPPORT
|
#ifdef GUI_SUPPORT
|
||||||
|
/**
|
||||||
|
Check for QWERTZ keyboard layout
|
||||||
|
*/
|
||||||
|
bool isQwertz() { return myQwertz; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Clipboard methods.
|
Clipboard methods.
|
||||||
*/
|
*/
|
||||||
|
@ -359,6 +364,11 @@ class EventHandler
|
||||||
// Global OSystem object
|
// Global OSystem object
|
||||||
OSystem& myOSystem;
|
OSystem& myOSystem;
|
||||||
|
|
||||||
|
#ifdef GUI_SUPPORT
|
||||||
|
// Keyboard layout
|
||||||
|
bool myQwertz{false};
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Methods which are called by derived classes to handle specific types
|
Methods which are called by derived classes to handle specific types
|
||||||
of input.
|
of input.
|
||||||
|
|
|
@ -47,6 +47,9 @@ void EditableWidget::setText(const string& str, bool)
|
||||||
if(_filter(tolower(c)))
|
if(_filter(tolower(c)))
|
||||||
_editString.push_back(c);
|
_editString.push_back(c);
|
||||||
|
|
||||||
|
clearEdits();
|
||||||
|
doEdit();
|
||||||
|
|
||||||
_caretPos = int(_editString.size());
|
_caretPos = int(_editString.size());
|
||||||
_selectSize = 0;
|
_selectSize = 0;
|
||||||
|
|
||||||
|
@ -78,12 +81,64 @@ void EditableWidget::lostFocusWidget()
|
||||||
_selectSize = 0;
|
_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)
|
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);
|
||||||
|
doEdit();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -187,8 +242,12 @@ bool EditableWidget::handleControlKeys(StellaKey key, StellaMod mod)
|
||||||
sendCommand(EditableWidget::kChangedCmd, key, _id);
|
sendCommand(EditableWidget::kChangedCmd, key, _id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case KBDK_Y:
|
||||||
case KBDK_Z:
|
case KBDK_Z:
|
||||||
// TODO: undo
|
if(key == KBDK_Y != instance().eventHandler().isQwertz())
|
||||||
|
dirty = redoEdit();
|
||||||
|
else
|
||||||
|
dirty = undoEdit();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KBDK_LEFT:
|
case KBDK_LEFT:
|
||||||
|
@ -469,7 +528,7 @@ int EditableWidget::scrollOffset()
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool EditableWidget::killChar(int direction)
|
bool EditableWidget::killChar(int direction, bool addEdit)
|
||||||
{
|
{
|
||||||
bool handled = false;
|
bool handled = false;
|
||||||
|
|
||||||
|
@ -480,12 +539,20 @@ bool EditableWidget::killChar(int direction)
|
||||||
_caretPos--;
|
_caretPos--;
|
||||||
_editString.erase(_caretPos, 1);
|
_editString.erase(_caretPos, 1);
|
||||||
handled = true;
|
handled = true;
|
||||||
|
if(_selectSize < 0)
|
||||||
|
_selectSize++;
|
||||||
|
if(addEdit)
|
||||||
|
doEdit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(direction == 1) // Delete next character (delete)
|
else if(direction == 1) // Delete next character (delete)
|
||||||
{
|
{
|
||||||
_editString.erase(_caretPos, 1);
|
_editString.erase(_caretPos, 1);
|
||||||
handled = true;
|
handled = true;
|
||||||
|
if(_selectSize > 0)
|
||||||
|
_selectSize--;
|
||||||
|
if(addEdit)
|
||||||
|
doEdit();
|
||||||
}
|
}
|
||||||
|
|
||||||
return handled;
|
return handled;
|
||||||
|
@ -502,12 +569,13 @@ bool EditableWidget::killLine(int direction)
|
||||||
if(count > 0)
|
if(count > 0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
killChar(-1);
|
killChar(-1, false);
|
||||||
|
|
||||||
handled = true;
|
handled = true;
|
||||||
// remove selection for removed text
|
// remove selection for removed text
|
||||||
if(_selectSize < 0)
|
if(_selectSize < 0)
|
||||||
_selectSize = 0;
|
_selectSize = 0;
|
||||||
|
doEdit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(direction == 1) // erase from current position to end of line
|
else if(direction == 1) // erase from current position to end of line
|
||||||
|
@ -516,12 +584,13 @@ bool EditableWidget::killLine(int direction)
|
||||||
if(count > 0)
|
if(count > 0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
killChar(+1);
|
killChar(+1, false);
|
||||||
|
|
||||||
handled = true;
|
handled = true;
|
||||||
// remove selection for removed text
|
// remove selection for removed text
|
||||||
if(_selectSize > 0)
|
if(_selectSize > 0)
|
||||||
_selectSize = 0;
|
_selectSize = 0;
|
||||||
|
doEdit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -551,12 +620,13 @@ bool EditableWidget::killLastWord()
|
||||||
if(count > 0)
|
if(count > 0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
killChar(-1);
|
killChar(-1, false);
|
||||||
|
|
||||||
handled = true;
|
handled = true;
|
||||||
// remove selection for removed word
|
// remove selection for removed word
|
||||||
if(_selectSize < 0)
|
if(_selectSize < 0)
|
||||||
_selectSize = std::min(_selectSize + count, 0);
|
_selectSize = std::min(_selectSize + count, 0);
|
||||||
|
doEdit();
|
||||||
}
|
}
|
||||||
|
|
||||||
return handled;
|
return handled;
|
||||||
|
@ -649,7 +719,7 @@ int EditableWidget::selectEndPos()
|
||||||
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool EditableWidget::killSelectedText()
|
bool EditableWidget::killSelectedText(bool addEdit)
|
||||||
{
|
{
|
||||||
if(_selectSize)
|
if(_selectSize)
|
||||||
{
|
{
|
||||||
|
@ -660,6 +730,8 @@ bool EditableWidget::killSelectedText()
|
||||||
}
|
}
|
||||||
_editString.erase(_caretPos, _selectSize);
|
_editString.erase(_caretPos, _selectSize);
|
||||||
_selectSize = 0;
|
_selectSize = 0;
|
||||||
|
if(addEdit)
|
||||||
|
doEdit();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -703,7 +775,7 @@ bool EditableWidget::pasteSelectedText()
|
||||||
// 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
|
||||||
killSelectedText();
|
killSelectedText(false);
|
||||||
// insert filtered paste text instead
|
// insert filtered paste text instead
|
||||||
ostringstream buf;
|
ostringstream buf;
|
||||||
bool lastOk = true; // only one filler char per invalid character (block)
|
bool lastOk = true; // only one filler char per invalid character (block)
|
||||||
|
@ -725,5 +797,10 @@ bool EditableWidget::pasteSelectedText()
|
||||||
// position cursor at the end of pasted text
|
// position cursor at the end of pasted text
|
||||||
_caretPos += int(buf.str().length());
|
_caretPos += int(buf.str().length());
|
||||||
|
|
||||||
return selected || !pasted.empty();
|
if(selected || !pasted.empty())
|
||||||
|
{
|
||||||
|
doEdit();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#define EDITABLE_WIDGET_HXX
|
#define EDITABLE_WIDGET_HXX
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
#include "Widget.hxx"
|
#include "Widget.hxx"
|
||||||
#include "Rect.hxx"
|
#include "Rect.hxx"
|
||||||
|
@ -89,18 +90,23 @@ class EditableWidget : public Widget, public CommandSender
|
||||||
bool handleControlKeys(StellaKey key, StellaMod mod);
|
bool handleControlKeys(StellaKey key, StellaMod mod);
|
||||||
bool handleShiftKeys(StellaKey key);
|
bool handleShiftKeys(StellaKey key);
|
||||||
bool handleNormalKeys(StellaKey key);
|
bool handleNormalKeys(StellaKey key);
|
||||||
bool killChar(int direction);
|
bool killChar(int direction, bool addEdit = true);
|
||||||
bool killLine(int direction);
|
bool killLine(int direction);
|
||||||
bool killLastWord();
|
bool killLastWord();
|
||||||
bool moveWord(int direction, bool select);
|
bool moveWord(int direction, bool select);
|
||||||
|
|
||||||
bool killSelectedText();
|
bool killSelectedText(bool addEdit = true);
|
||||||
int selectStartPos();
|
int selectStartPos();
|
||||||
int selectEndPos();
|
int selectEndPos();
|
||||||
// Clipboard
|
// Clipboard
|
||||||
bool cutSelectedText();
|
bool cutSelectedText();
|
||||||
bool copySelectedText();
|
bool copySelectedText();
|
||||||
bool pasteSelectedText();
|
bool pasteSelectedText();
|
||||||
|
// Undo
|
||||||
|
void clearEdits();
|
||||||
|
void doEdit();
|
||||||
|
bool undoEdit();
|
||||||
|
bool redoEdit();
|
||||||
|
|
||||||
// Use the current TextFilter to insert a character into the
|
// Use the current TextFilter to insert a character into the
|
||||||
// internal buffer
|
// internal buffer
|
||||||
|
@ -109,6 +115,9 @@ class EditableWidget : public Widget, public CommandSender
|
||||||
private:
|
private:
|
||||||
bool _editable{true};
|
bool _editable{true};
|
||||||
string _editString;
|
string _editString;
|
||||||
|
|
||||||
|
std::deque<string> _editBuffer;
|
||||||
|
int _redoCount{0};
|
||||||
int _caretPos{0};
|
int _caretPos{0};
|
||||||
// Size of current selected text
|
// Size of current selected text
|
||||||
// 0 = no selection
|
// 0 = no selection
|
||||||
|
|
Loading…
Reference in New Issue