Added multi level undo redo to line edit
This commit is contained in:
parent
619e4eb23d
commit
9dddce75d0
2 changed files with 88 additions and 31 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue