Added multi level undo redo to line edit

This commit is contained in:
Paulb23 2017-10-29 23:14:33 +00:00
parent 619e4eb23d
commit 9dddce75d0
2 changed files with 88 additions and 31 deletions

View file

@ -161,13 +161,14 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
} break;
case (KEY_Z): { // Simple One level undo
case (KEY_Z): { // undo / redo
if (editable) {
undo();
if (k->get_shift()) {
redo();
} else {
undo();
}
}
} break;
case (KEY_U): { // Delete from start to cursor
@ -175,7 +176,6 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
if (editable) {
selection_clear();
undo_text = text;
text = text.substr(cursor_pos, text.length() - cursor_pos);
Ref<Font> font = get_font("font");
@ -205,7 +205,6 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
if (editable) {
selection_clear();
undo_text = text;
text = text.substr(0, cursor_pos);
_text_changed();
}
@ -245,7 +244,6 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
break;
if (selection.enabled) {
undo_text = text;
selection_delete();
break;
}
@ -276,7 +274,6 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
set_cursor_position(cc);
} else {
undo_text = text;
delete_char();
}
@ -382,7 +379,6 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
}
if (selection.enabled) {
undo_text = text;
selection_delete();
break;
}
@ -417,7 +413,6 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
delete_text(cursor_pos, cc);
} else {
undo_text = text;
set_cursor_position(cursor_pos + 1);
delete_char();
}
@ -778,7 +773,6 @@ void LineEdit::copy_text() {
void LineEdit::cut_text() {
if (selection.enabled) {
undo_text = text;
OS::get_singleton()->set_clipboard(text.substr(selection.begin, selection.end - selection.begin));
selection_delete();
}
@ -798,23 +792,33 @@ void LineEdit::paste_text() {
}
void LineEdit::undo() {
int old_cursor_pos = cursor_pos;
text = undo_text;
Ref<Font> font = get_font("font");
cached_width = 0;
for (int i = 0; i < text.length(); i++)
cached_width += font->get_char_size(text[i]).width;
if (old_cursor_pos > text.length()) {
set_cursor_position(text.length());
} else {
set_cursor_position(old_cursor_pos);
if (undo_stack_pos == NULL) {
if (undo_stack.size() <= 1) {
return;
}
undo_stack_pos = undo_stack.back();
} else if (undo_stack_pos == undo_stack.front()) {
return;
}
undo_stack_pos = undo_stack_pos->prev();
TextOperation op = undo_stack_pos->get();
text = op.text;
set_cursor_position(op.cursor_pos);
_emit_text_change();
}
_text_changed();
void LineEdit::redo() {
if (undo_stack_pos == NULL) {
return;
}
if (undo_stack_pos == undo_stack.back()) {
return;
}
undo_stack_pos = undo_stack_pos->next();
TextOperation op = undo_stack_pos->get();
text = op.text;
set_cursor_position(op.cursor_pos);
_emit_text_change();
}
void LineEdit::shift_selection_check_pre(bool p_shift) {
@ -947,8 +951,6 @@ void LineEdit::delete_char() {
void LineEdit::delete_text(int p_from_column, int p_to_column) {
undo_text = text;
if (text.size() > 0) {
Ref<Font> font = get_font("font");
if (font != NULL) {
@ -1086,8 +1088,6 @@ void LineEdit::append_at_cursor(String p_text) {
if ((max_length <= 0) || (text.length() + p_text.length() <= max_length)) {
undo_text = text;
Ref<Font> font = get_font("font");
if (font != NULL) {
for (int i = 0; i < p_text.length(); i++)
@ -1105,6 +1105,7 @@ void LineEdit::append_at_cursor(String p_text) {
void LineEdit::clear_internal() {
_clear_undo_stack();
cached_width = 0;
cursor_pos = 0;
window_pos = 0;
@ -1275,6 +1276,11 @@ void LineEdit::menu_option(int p_option) {
undo();
}
} break;
case MENU_REDO: {
if (editable) {
redo();
}
}
}
}
@ -1312,10 +1318,43 @@ void LineEdit::_text_changed() {
if (expand_to_text_length)
minimum_size_changed();
_emit_text_change();
_clear_redo();
}
void LineEdit::_emit_text_change() {
emit_signal("text_changed", text);
_change_notify("text");
}
void LineEdit::_clear_redo() {
_create_undo_state();
if (undo_stack_pos == NULL) {
return;
}
undo_stack_pos = undo_stack_pos->next();
while (undo_stack_pos) {
List<TextOperation>::Element *elem = undo_stack_pos;
undo_stack_pos = undo_stack_pos->next();
undo_stack.erase(elem);
}
_create_undo_state();
}
void LineEdit::_clear_undo_stack() {
undo_stack.clear();
undo_stack_pos = NULL;
_create_undo_state();
}
void LineEdit::_create_undo_state() {
TextOperation op;
op.text = text;
op.cursor_pos = cursor_pos;
undo_stack.push_back(op);
}
void LineEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("_toggle_draw_caret"), &LineEdit::_toggle_draw_caret);
@ -1369,6 +1408,7 @@ void LineEdit::_bind_methods() {
BIND_ENUM_CONSTANT(MENU_CLEAR);
BIND_ENUM_CONSTANT(MENU_SELECT_ALL);
BIND_ENUM_CONSTANT(MENU_UNDO);
BIND_ENUM_CONSTANT(MENU_REDO);
BIND_ENUM_CONSTANT(MENU_MAX);
ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "text"), "set_text", "get_text");
@ -1388,6 +1428,8 @@ void LineEdit::_bind_methods() {
LineEdit::LineEdit() {
undo_stack_pos = NULL;
_create_undo_state();
align = ALIGN_LEFT;
cached_width = 0;
cursor_pos = 0;
@ -1421,6 +1463,7 @@ LineEdit::LineEdit() {
menu->add_item(TTR("Clear"), MENU_CLEAR);
menu->add_separator();
menu->add_item(TTR("Undo"), MENU_UNDO, KEY_MASK_CMD | KEY_Z);
menu->add_item(TTR("Redo"), MENU_REDO, KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z);
menu->connect("id_pressed", this, "menu_option");
expand_to_text_length = false;
}

View file

@ -56,6 +56,7 @@ public:
MENU_CLEAR,
MENU_SELECT_ALL,
MENU_UNDO,
MENU_REDO,
MENU_MAX
};
@ -92,10 +93,22 @@ private:
bool drag_attempt;
} selection;
struct TextOperation {
int cursor_pos;
String text;
};
List<TextOperation> undo_stack;
List<TextOperation>::Element *undo_stack_pos;
void _clear_undo_stack();
void _clear_redo();
void _create_undo_state();
Timer *caret_blink_timer;
static void _ime_text_callback(void *p_self, String p_text, Point2 p_selection);
void _text_changed();
void _emit_text_change();
bool expand_to_text_length;
bool caret_blink_enabled;
@ -166,6 +179,7 @@ public:
void cut_text();
void paste_text();
void undo();
void redo();
void set_editable(bool p_editable);
bool is_editable() const;