Rewrite text editing

This commit is contained in:
don-tnowe 2022-09-23 20:33:04 +03:00
parent da2af14c30
commit b97d63bb48
9 changed files with 151 additions and 149 deletions

View File

@ -32,6 +32,7 @@ var rows := []
var remembered_paths := {}
var edited_cells := []
var edited_cells_text := []
var edit_cursor_positions := []
var inspector_resource : Resource
@ -172,6 +173,7 @@ func _create_table(columns_changed : bool):
var headers_node = get_node(path_columns)
deselect_all_cells()
edited_cells = []
edited_cells_text = []
edit_cursor_positions = []
var new_node : Control
if columns_changed:
@ -311,6 +313,7 @@ func deselect_all_cells():
column_editors[_get_cell_column(x)].set_selected(x, false)
edited_cells.clear()
edited_cells_text.clear()
edit_cursor_positions.clear()
@ -320,6 +323,7 @@ func deselect_cell(cell : Control):
column_editors[_get_cell_column(cell)].set_selected(cell, false)
edited_cells.remove(idx)
edited_cells_text.remove(idx)
edit_cursor_positions.remove(idx)
@ -351,13 +355,17 @@ func select_cell(cell : Control):
column_editors[column_index].set_selected(cur_cell, true)
if !cur_cell in edited_cells:
edited_cells.append(cur_cell)
edit_cursor_positions.append(column_editors[column_index].get_text_length(cur_cell))
if column_editors[column_index].is_text():
edited_cells_text.append(str(cur_cell.text))
edit_cursor_positions.append(cur_cell.text.length())
func _add_cell_to_selection(cell : Control):
column_editors[_get_cell_column(cell)].set_selected(cell, true)
edited_cells.append(cell)
edit_cursor_positions.append(column_editors[_get_cell_column(cell)].get_text_length(cell))
if column_editors[_get_cell_column(cell)].is_text():
edited_cells_text.append(str(cell.text))
edit_cursor_positions.append(cell.text.length())
func _try_open_docks(cell : Control):
@ -375,7 +383,11 @@ func set_edited_cells_values(new_cell_values : Array, update_whole_row : bool =
var column = _get_cell_column(edited_cells[0])
var edited_cells_resources = _get_edited_cells_resources()
editor_plugin.undo_redo.create_action("Set Cell Value Externally")
# Duplicated here since if using text editing, edited_cells_text needs to modified
# but here, it would be converted from a String breaking editing
new_cell_values = new_cell_values.duplicate()
editor_plugin.undo_redo.create_action("Set Cell Values")
editor_plugin.undo_redo.add_undo_method(
self,
"_update_resources",
@ -384,6 +396,10 @@ func set_edited_cells_values(new_cell_values : Array, update_whole_row : bool =
column,
get_edited_cells_values()
)
editor_plugin.undo_redo.add_undo_method(
self,
"_update_selected_cells_text"
)
for i in new_cell_values.size():
column_editors[column].set_value(edited_cells[i], new_cell_values[i])
if update_whole_row:
@ -395,7 +411,7 @@ func set_edited_cells_values(new_cell_values : Array, update_whole_row : bool =
edited_cells_resources.duplicate(),
edited_cells.duplicate(),
column,
get_edited_cells_values()
new_cell_values.duplicate()
)
editor_plugin.undo_redo.commit_action()
editor_interface.get_resource_filesystem().scan()
@ -403,6 +419,15 @@ func set_edited_cells_values(new_cell_values : Array, update_whole_row : bool =
_update_column_sizes()
func _update_selected_cells_text():
if edited_cells_text.size() == 0:
return
for i in edited_cells.size():
edited_cells_text[i] = str(edited_cells[i].text)
edit_cursor_positions[i] = edited_cells_text[i].length()
func get_edited_cells_values() -> Array:
var arr := edited_cells.duplicate()
var column_index := _get_cell_column(edited_cells[0])
@ -413,6 +438,10 @@ func get_edited_cells_values() -> Array:
return arr
func get_cell_value(cell : Control):
return rows[_get_cell_row(cell)].get(columns[_get_cell_column(cell)])
func _can_select_cell(cell : Control) -> bool:
if edited_cells.size() == 0:
return true
@ -480,21 +509,20 @@ func _gui_input(event : InputEvent):
func _input(event : InputEvent):
if !has_focus() or edited_cells.size() == 0:
return
if !event is InputEventKey or !event.pressed:
return
if column_types[_get_cell_column(edited_cells[0])] == TYPE_OBJECT:
if !has_focus() or edited_cells.size() == 0:
return
var column = _get_cell_column(edited_cells[0])
if column_types[column] == TYPE_OBJECT || columns[column] == "resource_path":
return
if event.scancode == KEY_CONTROL or event.scancode == KEY_SHIFT:
# Modifier keys do not get processed.
return
var edited_cells_resources = _get_edited_cells_resources()
# Ctrl + Z (before, and instead of, committing the action!)
if Input.is_key_pressed(KEY_CONTROL) and event.scancode == KEY_Z:
if Input.is_key_pressed(KEY_SHIFT):
@ -510,28 +538,12 @@ func _input(event : InputEvent):
editor_plugin.undo_redo.redo()
return
editor_plugin.undo_redo.create_action("Set Cell Value")
editor_plugin.undo_redo.add_undo_method(
self,
"_update_resources",
edited_cells_resources.duplicate(),
edited_cells.duplicate(),
_get_cell_column(edited_cells[0]),
get_edited_cells_values()
)
if !column_editors[column].is_text():
return
_key_specific_action(event)
grab_focus()
editor_plugin.undo_redo.add_do_method(
self,
"_update_resources",
edited_cells_resources.duplicate(),
edited_cells.duplicate(),
_get_cell_column(edited_cells[0]),
get_edited_cells_values()
)
editor_plugin.undo_redo.commit_action()
editor_interface.get_resource_filesystem().scan()
undo_redo_version = editor_plugin.undo_redo.get_version()
@ -542,20 +554,16 @@ func _key_specific_action(event : InputEvent):
if ctrl_pressed:
editor_plugin.hide_bottom_panel()
# ERASING
if event.scancode == KEY_BACKSPACE:
TextEditingUtils.multi_erase_left(edited_cells, edit_cursor_positions, column_editors[column], self)
if event.scancode == KEY_DELETE:
TextEditingUtils.multi_erase_right(edited_cells, edit_cursor_positions, column_editors[column], self)
get_tree().set_input_as_handled() # Because this is one dangerous action.
# CURSOR MOVEMENT
elif event.scancode == KEY_LEFT:
TextEditingUtils.multi_move_left(edited_cells, edit_cursor_positions, column_editors[column])
if event.scancode == KEY_LEFT:
TextEditingUtils.multi_move_left(
edited_cells_text, edit_cursor_positions, Input.is_key_pressed(KEY_CONTROL)
)
elif event.scancode == KEY_RIGHT:
TextEditingUtils.multi_move_right(edited_cells, edit_cursor_positions, column_editors[column])
TextEditingUtils.multi_move_right(
edited_cells_text, edit_cursor_positions, Input.is_key_pressed(KEY_CONTROL)
)
elif event.scancode == KEY_HOME:
for i in edit_cursor_positions.size():
@ -563,7 +571,7 @@ func _key_specific_action(event : InputEvent):
elif event.scancode == KEY_END:
for i in edit_cursor_positions.size():
edit_cursor_positions[i] = column_editors[column].get_text_length(edited_cells[i])
edit_cursor_positions[i] = edited_cells_text[i].length()
# BETWEEN-CELL NAVIGATION
elif event.scancode == KEY_UP:
@ -582,19 +590,31 @@ func _key_specific_action(event : InputEvent):
# Ctrl + C (so you can edit in a proper text editor instead of this wacky nonsense)
elif ctrl_pressed and event.scancode == KEY_C:
TextEditingUtils.multi_copy(edited_cells)
TextEditingUtils.multi_copy(edited_cells_text)
# Ctrl + V
elif ctrl_pressed and event.scancode == KEY_V:
TextEditingUtils.multi_paste(edited_cells, edit_cursor_positions, column_editors[column], self)
set_edited_cells_values(TextEditingUtils.multi_paste(
edited_cells_text, edit_cursor_positions
))
# Line Skip
elif event.scancode == KEY_ENTER:
TextEditingUtils.multi_linefeed(edited_cells, edit_cursor_positions, column_editors[column], self)
# ERASING
elif event.scancode == KEY_BACKSPACE:
set_edited_cells_values(TextEditingUtils.multi_erase_left(
edited_cells_text, edit_cursor_positions, Input.is_key_pressed(KEY_CONTROL)
))
elif event.scancode == KEY_DELETE:
set_edited_cells_values(TextEditingUtils.multi_erase_right(
edited_cells_text, edit_cursor_positions, Input.is_key_pressed(KEY_CONTROL)
))
get_tree().set_input_as_handled() # Because this is one dangerous action.
# And finally, text typing.
elif event.unicode != 0 and event.unicode != 127:
TextEditingUtils.multi_input(char(event.unicode), edited_cells, edit_cursor_positions, column_editors[column], self)
set_edited_cells_values(TextEditingUtils.multi_input(
char(event.unicode), edited_cells_text, edit_cursor_positions
))
func _move_selection_on_grid(move_h : int, move_v : int):
@ -618,12 +638,16 @@ func set_cell(cell, value):
func _update_resources(update_rows : Array, update_cells : Array, update_column : int, values : Array):
var cells := get_node(path_table_root).get_children()
for i in update_rows.size():
update_rows[i].set(columns[update_column], values[i])
ResourceSaver.save(update_rows[i].resource_path, update_rows[i])
if undo_redo_version > editor_plugin.undo_redo.get_version():
# Set cell values, but only when undoing/redoing (set_cell() normally fills these in)
column_editors[update_column].set_value(update_cells[i], values[i])
values[i] = _try_convert(values[i], column_types[update_column])
if values[i] == null:
continue
update_rows[i].set(columns[update_column], convert(values[i], column_types[update_column]))
ResourceSaver.save(update_rows[i].resource_path, update_rows[i])
if column_types[update_column] == TYPE_COLOR:
for j in columns.size() - update_column:
if j != 0 and column_types[j + update_column] == TYPE_COLOR:
@ -639,6 +663,11 @@ func _update_resources(update_rows : Array, update_cells : Array, update_column
_update_column_sizes()
func _try_convert(value, type):
# If it can't convert, returns null.
return convert(value, type)
func _get_edited_cells_resources() -> Array:
var arr := edited_cells.duplicate()
for i in arr.size():

View File

@ -5,5 +5,5 @@ description="Edit Many Resources from one Folder as a table.
Heavily inspired by Multi-Cursor-Editing in text editors, so after selecting multiple cells (in the same column!) using Ctrl+Click or Shift+Click, most Basic-to-Intermediate movements should be available."
author="Don Tnowe"
version="1.1"
version="1.2"
script="plugin.gd"

View File

@ -47,111 +47,90 @@ static func revert_non_typing(text : String) -> String:
return text
static func multi_erase_right(edited_cells : Array, edit_cursor_positions : Array, cell_editor : Reference, callback_object : Object):
for i in edited_cells.size():
var cell = edited_cells[i]
var start_pos = edit_cursor_positions[i]
while true:
edit_cursor_positions[i] += 1
if !Input.is_key_pressed(KEY_CONTROL) or is_character_whitespace(_get_cell_text(cell, cell_editor), edit_cursor_positions[i]):
break
static func multi_erase_right(values : Array, cursor_positions : Array, ctrl_pressed : bool):
for i in values.size():
var start_pos = cursor_positions[i]
cursor_positions[i] = _step_cursor(values[i], cursor_positions[i], 1, ctrl_pressed)
edit_cursor_positions[i] = min(
edit_cursor_positions[i],
edited_cells[i].text.length()
cursor_positions[i] = min(
cursor_positions[i],
values[i].length()
)
callback_object.set_cell(cell, (
_get_cell_text(cell, cell_editor).left(start_pos)
+ _get_cell_text(cell, cell_editor).substr(edit_cursor_positions[i])
))
edit_cursor_positions[i] = start_pos
static func multi_erase_left(edited_cells : Array, edit_cursor_positions : Array, cell_editor : Reference, callback_object : Object):
for i in edited_cells.size():
var cell = edited_cells[i]
var start_pos = edit_cursor_positions[i]
edit_cursor_positions[i] = _step_cursor(_get_cell_text(cell, cell_editor), edit_cursor_positions[i], -1)
var result_text = (
_get_cell_text(cell, cell_editor).substr(0, edit_cursor_positions[i])
+ _get_cell_text(cell, cell_editor).substr(start_pos)
values[i] = (
values[i].left(start_pos)
+ values[i].substr(cursor_positions[i])
)
callback_object.set_cell(cell, (
_get_cell_text(cell, cell_editor).substr(0, edit_cursor_positions[i])
+ _get_cell_text(cell, cell_editor).substr(start_pos)
))
cursor_positions[i] = start_pos
return values
static func multi_move_left(edited_cells : Array, edit_cursor_positions : Array, cell_editor : Reference):
for i in edit_cursor_positions.size():
edit_cursor_positions[i] = _step_cursor(edited_cells[i].text, edit_cursor_positions[i], -1)
static func multi_erase_left(values : Array, cursor_positions : Array, ctrl_pressed):
for i in values.size():
var start_pos = cursor_positions[i]
cursor_positions[i] = _step_cursor(values[i], cursor_positions[i], -1, ctrl_pressed)
values[i] = (
values[i].substr(0, cursor_positions[i])
+ values[i].substr(start_pos)
)
return values
static func multi_move_right(edited_cells : Array, edit_cursor_positions : Array, cell_editor : Reference):
for i in edit_cursor_positions.size():
edit_cursor_positions[i] = _step_cursor(edited_cells[i].text, edit_cursor_positions[i], 1)
static func multi_move_left(values : Array, cursor_positions : Array, ctrl_pressed):
for i in cursor_positions.size():
cursor_positions[i] = _step_cursor(values[i], cursor_positions[i], -1, ctrl_pressed)
static func multi_paste(edited_cells : Array, edit_cursor_positions : Array, cell_editor : Reference, callback_object : Object):
static func multi_move_right(values : Array, cursor_positions : Array, ctrl_pressed):
for i in cursor_positions.size():
cursor_positions[i] = _step_cursor(values[i], cursor_positions[i], 1, ctrl_pressed)
static func multi_paste(values : Array, cursor_positions : Array):
var pasted_lines := OS.clipboard.split("\n")
var paste_each_line := pasted_lines.size() == edited_cells.size()
var paste_each_line := pasted_lines.size() == values.size()
for i in edited_cells.size():
for i in values.size():
if paste_each_line:
edit_cursor_positions[i] += pasted_lines[i].length()
cursor_positions[i] += pasted_lines[i].length()
else:
edit_cursor_positions[i] += OS.clipboard.length()
cursor_positions[i] += OS.clipboard.length()
var cell = edited_cells[i]
callback_object.set_cell(cell, (
_get_cell_text(cell, cell_editor).left(edit_cursor_positions[i])
values[i] = (
values[i].left(cursor_positions[i])
+ (pasted_lines[i] if paste_each_line else OS.clipboard)
+ _get_cell_text(cell, cell_editor).substr(edit_cursor_positions[i])
))
+ values[i].substr(cursor_positions[i])
)
return values
static func multi_copy(edited_cells : Array):
var copied_text := ""
static func multi_copy(values : Array):
for i in values.size():
values[i] = values[i]
for i in edited_cells.size():
copied_text += "\n" + edited_cells[i].text
# Cut the first \n out.
OS.clipboard = copied_text.substr(1)
OS.clipboard = "\n".join(values)
static func multi_linefeed(edited_cells : Array, edit_cursor_positions : Array, cell_editor : Reference, callback_object : Object):
for i in edited_cells.size():
var cell = edited_cells[i]
callback_object.set_cell(cell, (
_get_cell_text(cell, cell_editor).left(edit_cursor_positions[i])
+ "\n"
+ _get_cell_text(cell, cell_editor).substr(edit_cursor_positions[i])
))
edit_cursor_positions[i] = min(edit_cursor_positions[i] + 1, _get_cell_text(cell, cell_editor).length())
static func multi_input(input_char : String, edited_cells : Array, edit_cursor_positions : Array, cell_editor : Reference, callback_object : Object):
for i in edited_cells.size():
var cell = edited_cells[i]
callback_object.set_cell(cell, (
_get_cell_text(cell, cell_editor).left(edit_cursor_positions[i])
static func multi_input(input_char : String, values : Array, cursor_positions : Array):
for i in values.size():
values[i] = (
values[i].left(cursor_positions[i])
+ input_char
+ _get_cell_text(cell, cell_editor).substr(edit_cursor_positions[i])
))
edit_cursor_positions[i] = min(edit_cursor_positions[i] + 1, _get_cell_text(cell, cell_editor).length())
+ values[i].substr(cursor_positions[i])
)
cursor_positions[i] = min(cursor_positions[i] + 1, values[i].length())
return values
static func _get_cell_text(cell : Control, cell_editor : Reference):
return cell_editor.get_text_value(cell)
static func _step_cursor(text : String, start : int, step : int = 1) -> int:
static func _step_cursor(text : String, start : int, step : int = 1, ctrl_pressed : bool = false) -> int:
while true:
start += step
if !Input.is_key_pressed(KEY_CONTROL) or is_character_whitespace(text, start):
if !ctrl_pressed or is_character_whitespace(text, start):
if start > text.length():
return text.length()

View File

@ -17,17 +17,13 @@ func create_cell(caller : Control) -> Control:
func set_selected(node : Control, selected : bool):
node.get_node("Selected").visible = selected
# Override to change behaviour when the cell is edited via keyboard.
# Override to change how the value is displayed.
func set_value(node : Control, value):
node.text = TextEditingUtils.show_non_typing(str(value))
func get_text_value(node : Control):
return node.text
# Override for text-based types to allow multi-editing.
func get_text_length(node : Control):
return node.text.length()
# Override to prevent the cell from being edited as text.
func is_text():
return true
func set_color(node : Control, color : Color):

View File

@ -25,9 +25,5 @@ func set_value(node : Control, value):
children[i].self_modulate = Color(str(value[i]).hash()) + Color(0.25, 0.25, 0.25, 1.0)
func get_text_value(node : Control):
return ""
func get_text_length(node : Control):
return -1
func is_text():
return false

View File

@ -38,8 +38,8 @@ func set_color(node : Control, color : Color):
node.get_node("Back").modulate = color * 0.6 if node.editor_description == "" else color
func get_text_length(node : Control):
return -1
func is_text():
return false
func _on_preview_loaded(path : String, preview : Texture, thumbnail_preview : Texture, node):

View File

@ -199,9 +199,11 @@ text = "Recent:"
[node name="OptionButton" type="OptionButton" parent="HBoxContainer/Control2/HBoxContainer/HFlowContainer"]
margin_left = 52.0
margin_right = 141.0
margin_right = 106.0
margin_bottom = 20.0
text = "Set Mode"
text = "Add"
items = [ "Add", null, false, 0, null, "Erase", null, false, 1, null, "Delete From Recent", null, false, 2, null ]
selected = 0
[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/String" to="." method="_on_String_pressed"]
[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/Int" to="." method="_on_Int_pressed"]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB