mirror of
https://github.com/Relintai/godot-resources-as-sheets-plugin.git
synced 2025-04-08 17:41:50 +02:00
Port code from 3.0, but not the features
This commit is contained in:
parent
c56a638340
commit
91e006571d
10
README.md
10
README.md
@ -32,6 +32,8 @@ Possible inputs:
|
||||
- `Home/End` - Move cursor to start/end of cell
|
||||
- `Ctrl + <move/erase> / Cmd + <move/erase>` - Move through / Erase whole word
|
||||
- `Ctrl/Cmd + C/V` - Copy cells / Paste text into cells
|
||||
- `Ctrl/Cmd + R` - Rename resource
|
||||
- `Ctrl/Cmd + D` - Duplicate selected rows
|
||||
- `Ctrl/Cmd + (Shift) + Z` - The Savior
|
||||
|
||||
If clipboard contains as many lines as there are cells selected, each line is pasted into a separate cell.
|
||||
@ -41,8 +43,10 @@ To add support of more datatypes, check out the `typed_cells` and `typed_editors
|
||||
#
|
||||
Made by Don Tnowe in 2022.
|
||||
|
||||
[https://redbladegames.netlify.app]()
|
||||
[My Website](https://redbladegames.netlify.app)
|
||||
|
||||
[https://twitter.com/don_tnowe]()
|
||||
[Itch](https://don-tnowe.itch.io)
|
||||
|
||||
Copying and Modiication is allowed in accordance to the MIT license, full text is included.
|
||||
[Twitter](https://twitter.com/don_tnowe)
|
||||
|
||||
Copying and Modification is allowed in accordance to the MIT license, full text is included.
|
||||
|
@ -2,6 +2,8 @@
|
||||
extends Control
|
||||
|
||||
signal grid_updated()
|
||||
signal cells_selected(cells)
|
||||
signal cells_context(cells)
|
||||
|
||||
@export var table_header_scene : PackedScene
|
||||
@export var cell_editor_classes : Array[Script] = []
|
||||
@ -22,7 +24,6 @@ var recent_paths := []
|
||||
var save_data_path : String = get_script().resource_path.get_base_dir() + "/saved_state.json"
|
||||
var sorting_by := ""
|
||||
var sorting_reverse := false
|
||||
var undo_redo_version := 0
|
||||
|
||||
var all_cell_editors := []
|
||||
|
||||
@ -37,9 +38,10 @@ var remembered_paths := {}
|
||||
var edited_cells := []
|
||||
var edited_cells_text := []
|
||||
var edit_cursor_positions := []
|
||||
|
||||
var inspector_resource : Resource
|
||||
var search_cond : RefCounted
|
||||
var my_undo_redo : UndoRedo
|
||||
var io : RefCounted
|
||||
|
||||
var hidden_columns := {}
|
||||
var first_row := 0
|
||||
@ -48,7 +50,6 @@ var last_row := 0
|
||||
|
||||
func _ready():
|
||||
node_recent_paths.clear()
|
||||
my_undo_redo = editor_plugin.get_undo_redo().get_history_undo_redo(editor_plugin.get_undo_redo().get_object_history_id(self))
|
||||
editor_interface.get_resource_filesystem().filesystem_changed.connect(_on_filesystem_changed)
|
||||
editor_interface.get_inspector().property_edited.connect(_on_inspector_property_edited)
|
||||
node_hide_columns_button.get_popup().id_pressed.connect(_on_visible_cols_id_pressed)
|
||||
@ -69,6 +70,9 @@ func _ready():
|
||||
for x in cell_editor_classes:
|
||||
all_cell_editors.append(x.new())
|
||||
all_cell_editors[all_cell_editors.size() - 1].hint_strings_array = column_hint_strings
|
||||
|
||||
node_recent_paths.selected = 0
|
||||
display_folder(recent_paths[0], "resource_name", false, true)
|
||||
|
||||
|
||||
func _on_filesystem_changed():
|
||||
@ -90,18 +94,23 @@ func _on_filesystem_changed():
|
||||
break
|
||||
|
||||
|
||||
func display_folder(folderpath : String, sort_by : String = "", sort_reverse : bool = false, force_rebuild : bool = false):
|
||||
func display_folder(folderpath : String, sort_by : String = "", sort_reverse : bool = false, force_rebuild : bool = false, is_echo : bool = false):
|
||||
if folderpath == "": return # Root folder resources tend to have MANY properties.
|
||||
$"HeaderContentSplit/MarginContainer/FooterContentSplit/Panel/Label".visible = false
|
||||
if !folderpath.ends_with("/"):
|
||||
folderpath += "/"
|
||||
if folderpath.get_extension() == "":
|
||||
folderpath = folderpath.trim_suffix("/") + "/"
|
||||
|
||||
if folderpath.ends_with(".tres") and !folderpath.ends_with(SpreadsheetImport.SUFFIX):
|
||||
folderpath = folderpath.get_base_dir() + "/"
|
||||
|
||||
if search_cond == null:
|
||||
_on_search_cond_text_submitted("true")
|
||||
|
||||
add_path_to_recent(folderpath)
|
||||
first_row = node_page_manager.first_row
|
||||
last_row = min(node_page_manager.last_row, rows.size())
|
||||
_load_resources_from_folder(folderpath, sort_by, sort_reverse)
|
||||
|
||||
if columns.size() == 0: return
|
||||
|
||||
node_folder_path.text = folderpath
|
||||
@ -114,7 +123,7 @@ func display_folder(folderpath : String, sort_by : String = "", sort_reverse : b
|
||||
_update_hidden_columns()
|
||||
_update_column_sizes()
|
||||
|
||||
await get_tree().process_frame
|
||||
await get_tree().create_timer(0.25).timeout
|
||||
if node_table_root.get_child_count() == 0:
|
||||
display_folder(folderpath, sort_by, sort_reverse, force_rebuild)
|
||||
|
||||
@ -126,65 +135,50 @@ func refresh(force_rebuild : bool = true):
|
||||
display_folder(current_path, sorting_by, sorting_reverse, force_rebuild)
|
||||
|
||||
|
||||
func _load_resources_from_folder(folderpath : String, sort_by : String, sort_reverse : bool):
|
||||
var dir = DirAccess.open(folderpath)
|
||||
dir.list_dir_begin()
|
||||
func _load_resources_from_folder(path : String, sort_by : String, sort_reverse : bool):
|
||||
if path.ends_with("/"):
|
||||
io = SpreadsheetEditFormatTres.new()
|
||||
|
||||
rows.clear()
|
||||
remembered_paths.clear()
|
||||
var cur_dir_script : Script = null
|
||||
|
||||
var filepath = dir.get_next()
|
||||
var res : Resource
|
||||
|
||||
while filepath != "":
|
||||
remembered_paths[folderpath + filepath] = null
|
||||
if filepath.ends_with(".tres"):
|
||||
filepath = folderpath + filepath
|
||||
res = load(filepath)
|
||||
if !is_instance_valid(cur_dir_script):
|
||||
columns.clear()
|
||||
column_types.clear()
|
||||
column_hints.clear()
|
||||
column_hint_strings.clear()
|
||||
column_editors.clear()
|
||||
var column_index = -1
|
||||
for x in res.get_property_list():
|
||||
if x["usage"] & PROPERTY_USAGE_EDITOR != 0 and x["name"] != "script":
|
||||
column_index += 1
|
||||
columns.append(x["name"])
|
||||
column_types.append(x["type"])
|
||||
column_hints.append(x["hint"])
|
||||
column_hint_strings.append(x["hint_string"].split(","))
|
||||
for y in all_cell_editors:
|
||||
if y.can_edit_value(res.get(x["name"]), x["type"], x["hint"], column_index):
|
||||
column_editors.append(y)
|
||||
break
|
||||
|
||||
cur_dir_script = res.get_script()
|
||||
if !(sort_by in res):
|
||||
sort_by = "resource_path"
|
||||
|
||||
if res.get_script() == cur_dir_script:
|
||||
_insert_row_sorted(res, rows, sort_by, sort_reverse)
|
||||
remembered_paths[res.resource_path] = res
|
||||
|
||||
filepath = dir.get_next()
|
||||
else:
|
||||
io = load(path).view_script.new()
|
||||
|
||||
io.editor_view = self
|
||||
rows = io.import_from_path(path, insert_row_sorted, sort_by, sort_reverse)
|
||||
|
||||
|
||||
func _insert_row_sorted(res : Resource, rows : Array, sort_by : String, sort_reverse : bool):
|
||||
func fill_property_data(res):
|
||||
columns.clear()
|
||||
column_types.clear()
|
||||
column_hints.clear()
|
||||
column_hint_strings.clear()
|
||||
column_editors.clear()
|
||||
var column_index = -1
|
||||
for x in res.get_property_list():
|
||||
if x["usage"] & PROPERTY_USAGE_EDITOR != 0 and x["name"] != "script":
|
||||
column_index += 1
|
||||
columns.append(x["name"])
|
||||
column_types.append(x["type"])
|
||||
column_hints.append(x["hint"])
|
||||
column_hint_strings.append(x["hint_string"].split(","))
|
||||
for y in all_cell_editors:
|
||||
if y.can_edit_value(io.get_value(res, x["name"]), x["type"], x["hint"], column_index):
|
||||
column_editors.append(y)
|
||||
break
|
||||
|
||||
|
||||
func insert_row_sorted(res : Resource, rows : Array, sort_by : String, sort_reverse : bool):
|
||||
if !search_cond.can_show(res, rows.size()):
|
||||
return
|
||||
|
||||
for i in rows.size():
|
||||
if sort_reverse == _compare_values(res.get(sort_by), rows[i].get(sort_by)):
|
||||
if sort_reverse == compare_values(io.get_value(res, sort_by), io.get_value(rows[i], sort_by)):
|
||||
rows.insert(i, res)
|
||||
return
|
||||
|
||||
rows.append(res)
|
||||
|
||||
|
||||
func _compare_values(a, b) -> bool:
|
||||
func compare_values(a, b) -> bool:
|
||||
if a == null or b == null: return b == null
|
||||
if a is Color:
|
||||
return a.h > b.h if a.h != b.h else a.v > b.v
|
||||
@ -267,7 +261,6 @@ func _update_column_sizes():
|
||||
var min_width := 0
|
||||
var cell : Control
|
||||
|
||||
node_columns.get_parent().custom_minimum_size.y = column_headers[0].size.y
|
||||
for i in column_headers.size():
|
||||
var header = column_headers[i]
|
||||
cell = node_table_root.get_child(i)
|
||||
@ -289,6 +282,8 @@ func _update_column_sizes():
|
||||
node_columns.show()
|
||||
|
||||
await get_tree().process_frame
|
||||
|
||||
node_columns.get_parent().custom_minimum_size.y = column_headers[0].size.y
|
||||
for i in column_headers.size():
|
||||
column_headers[i].position.x = node_table_root.get_child(i).position.x
|
||||
column_headers[i].size.x = node_table_root.get_child(i).size.x
|
||||
@ -306,17 +301,17 @@ func _update_row(row_index : int, color_rows : bool = true):
|
||||
else:
|
||||
current_node = node_table_root.get_child((row_index - first_row) * columns.size() + i)
|
||||
current_node.tooltip_text = (
|
||||
TextEditingUtils.string_snake_to_naming_case(columns[i])
|
||||
columns[i].capitalize()
|
||||
+ "\n---\n"
|
||||
+ "Of " + rows[row_index].resource_path.get_file().get_basename()
|
||||
)
|
||||
|
||||
column_editors[i].set_value(current_node, rows[row_index].get(columns[i]))
|
||||
column_editors[i].set_value(current_node, io.get_value(rows[row_index], columns[i]))
|
||||
if columns[i] == "resource_path":
|
||||
column_editors[i].set_value(current_node, current_node.text.get_file().get_basename())
|
||||
|
||||
if color_rows and column_types[i] == TYPE_COLOR:
|
||||
next_color = rows[row_index].get(columns[i])
|
||||
next_color = io.get_value(rows[row_index], columns[i])
|
||||
|
||||
column_editors[i].set_color(current_node, next_color)
|
||||
|
||||
@ -383,7 +378,6 @@ func save_data():
|
||||
func _on_path_text_submitted(new_text : String = ""):
|
||||
if new_text != "":
|
||||
current_path = new_text
|
||||
add_path_to_recent(new_text)
|
||||
display_folder(new_text, "", false, true)
|
||||
|
||||
else:
|
||||
@ -393,12 +387,11 @@ func _on_path_text_submitted(new_text : String = ""):
|
||||
func _on_RecentPaths_item_selected(index : int):
|
||||
current_path = recent_paths[index]
|
||||
node_folder_path.text = recent_paths[index]
|
||||
display_folder(current_path)
|
||||
display_folder(current_path, sorting_by, sorting_reverse, true)
|
||||
|
||||
|
||||
func _on_FileDialog_dir_selected(dir : String):
|
||||
node_folder_path.text = dir
|
||||
add_path_to_recent(dir)
|
||||
display_folder(dir)
|
||||
|
||||
|
||||
@ -409,6 +402,7 @@ func deselect_all_cells():
|
||||
edited_cells.clear()
|
||||
edited_cells_text.clear()
|
||||
edit_cursor_positions.clear()
|
||||
cells_selected.emit([])
|
||||
|
||||
|
||||
func deselect_cell(cell : Control):
|
||||
@ -420,6 +414,8 @@ func deselect_cell(cell : Control):
|
||||
if edited_cells_text.size() != 0:
|
||||
edited_cells_text.remove_at(idx)
|
||||
edit_cursor_positions.remove_at(idx)
|
||||
|
||||
cells_selected.emit(edited_cells)
|
||||
|
||||
|
||||
func select_cell(cell : Control):
|
||||
@ -431,6 +427,8 @@ func select_cell(cell : Control):
|
||||
inspector_resource = rows[_get_cell_row(cell)]
|
||||
editor_plugin.get_editor_interface().edit_resource(inspector_resource)
|
||||
|
||||
cells_selected.emit(edited_cells)
|
||||
|
||||
|
||||
func select_cells_to(cell : Control):
|
||||
var column_index := _get_cell_column(cell)
|
||||
@ -456,6 +454,8 @@ func select_cells_to(cell : Control):
|
||||
edited_cells_text.append(str(cur_cell.text))
|
||||
edit_cursor_positions.append(cur_cell.text.length())
|
||||
|
||||
cells_selected.emit(edited_cells)
|
||||
|
||||
|
||||
func select_column(column_index : int):
|
||||
deselect_all_cells()
|
||||
@ -486,7 +486,7 @@ func _try_open_docks(cell : Control):
|
||||
var column_index = _get_cell_column(cell)
|
||||
for x in node_property_editors.get_children():
|
||||
x.visible = x.try_edit_value(
|
||||
rows[_get_cell_row(cell)].get(columns[column_index]),
|
||||
io.get_value(rows[_get_cell_row(cell)], columns[column_index]),
|
||||
column_types[column_index],
|
||||
column_hints[column_index]
|
||||
)
|
||||
@ -524,10 +524,34 @@ func set_edited_cells_values(new_cell_values : Array):
|
||||
)
|
||||
editor_plugin.undo_redo.commit_action()
|
||||
editor_interface.get_resource_filesystem().scan()
|
||||
undo_redo_version = my_undo_redo.get_version()
|
||||
_update_column_sizes()
|
||||
|
||||
|
||||
func rename_row(row, new_name):
|
||||
if !has_row_names(): return
|
||||
|
||||
io.rename_row(row, new_name)
|
||||
refresh()
|
||||
|
||||
|
||||
func duplicate_selected_rows(new_name : String):
|
||||
io.duplicate_rows(_get_edited_cells_resources(), new_name)
|
||||
refresh()
|
||||
|
||||
|
||||
func delete_selected_rows():
|
||||
io.delete_rows(_get_edited_cells_resources())
|
||||
refresh()
|
||||
|
||||
|
||||
func has_row_names():
|
||||
return io.has_row_names()
|
||||
|
||||
|
||||
func get_last_selected_row():
|
||||
return rows[_get_cell_row(edited_cells[-1])]
|
||||
|
||||
|
||||
func _update_selected_cells_text():
|
||||
if edited_cells_text.size() == 0:
|
||||
return
|
||||
@ -542,13 +566,13 @@ func get_edited_cells_values() -> Array:
|
||||
var column_index := _get_cell_column(edited_cells[0])
|
||||
var cell_editor = column_editors[column_index]
|
||||
for i in arr.size():
|
||||
arr[i] = rows[_get_cell_row(arr[i])].get(columns[column_index])
|
||||
arr[i] = io.get_value(rows[_get_cell_row(arr[i])], columns[column_index])
|
||||
|
||||
return arr
|
||||
|
||||
|
||||
func get_cell_value(cell : Control):
|
||||
return rows[_get_cell_row(cell)].get(columns[_get_cell_column(cell)])
|
||||
return io.get_value(rows[_get_cell_row(cell)], columns[_get_cell_column(cell)])
|
||||
|
||||
|
||||
func _can_select_cell(cell : Control) -> bool:
|
||||
@ -579,6 +603,13 @@ func _on_cell_gui_input(event : InputEvent, cell : Control):
|
||||
if event is InputEventMouseButton:
|
||||
grab_focus()
|
||||
if event.button_index != MOUSE_BUTTON_LEFT:
|
||||
if event.button_index == MOUSE_BUTTON_RIGHT && event.is_pressed():
|
||||
if !cell in edited_cells:
|
||||
deselect_all_cells()
|
||||
select_cell(cell)
|
||||
|
||||
cells_context.emit(edited_cells)
|
||||
|
||||
return
|
||||
|
||||
if event.pressed:
|
||||
@ -600,6 +631,9 @@ func _on_cell_gui_input(event : InputEvent, cell : Control):
|
||||
func _gui_input(event : InputEvent):
|
||||
if event is InputEventMouseButton:
|
||||
if event.button_index != MOUSE_BUTTON_LEFT:
|
||||
if event.button_index == MOUSE_BUTTON_RIGHT && event.is_pressed():
|
||||
cells_context.emit(edited_cells)
|
||||
|
||||
return
|
||||
|
||||
grab_focus()
|
||||
@ -619,24 +653,24 @@ func _input(event : InputEvent):
|
||||
return
|
||||
|
||||
# Ctrl + Z (before, and instead of, committing the action!)
|
||||
if Input.is_key_pressed(KEY_CTRL) and event.keycode == KEY_Z:
|
||||
if Input.is_key_pressed(KEY_SHIFT):
|
||||
my_undo_redo.redo()
|
||||
# Ctrl + z
|
||||
else:
|
||||
my_undo_redo.undo()
|
||||
|
||||
return
|
||||
if Input.is_key_pressed(KEY_CTRL):
|
||||
if event.keycode == KEY_Z:
|
||||
if Input.is_key_pressed(KEY_SHIFT):
|
||||
editor_plugin.undo_redo.redo()
|
||||
# Ctrl + z (smol)
|
||||
else:
|
||||
editor_plugin.undo_redo.undo()
|
||||
|
||||
return
|
||||
|
||||
# This shortcut is used by Godot as well.
|
||||
if event.keycode == KEY_Y:
|
||||
editor_plugin.undo_redo.redo()
|
||||
return
|
||||
|
||||
# This shortcut is used by Godot as well.
|
||||
if Input.is_key_pressed(KEY_CTRL) and event.keycode == KEY_Y:
|
||||
my_undo_redo.redo()
|
||||
return
|
||||
|
||||
_key_specific_action(event)
|
||||
grab_focus()
|
||||
editor_interface.get_resource_filesystem().scan()
|
||||
undo_redo_version = my_undo_redo.get_version()
|
||||
|
||||
|
||||
func _key_specific_action(event : InputEvent):
|
||||
@ -685,6 +719,7 @@ 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.keycode == KEY_C:
|
||||
TextEditingUtils.multi_copy(edited_cells_text)
|
||||
get_tree().set_input_as_handled()
|
||||
|
||||
# The following actions do not work on non-editable cells.
|
||||
if !column_editors[column].is_text() or columns[column] == "resource_path":
|
||||
@ -695,6 +730,7 @@ func _key_specific_action(event : InputEvent):
|
||||
set_edited_cells_values(TextEditingUtils.multi_paste(
|
||||
edited_cells_text, edit_cursor_positions
|
||||
))
|
||||
get_tree().set_input_as_handled()
|
||||
|
||||
# ERASING
|
||||
elif event.keycode == KEY_BACKSPACE:
|
||||
@ -734,17 +770,24 @@ func _move_selection_on_grid(move_h : int, move_v : int):
|
||||
|
||||
|
||||
func _update_resources(update_rows : Array, update_cells : Array, update_column : int, values : Array):
|
||||
var saved_indices = []
|
||||
saved_indices.resize(update_rows.size())
|
||||
for i in update_rows.size():
|
||||
var row = _get_cell_row(update_cells[i])
|
||||
saved_indices[i] = row
|
||||
column_editors[update_column].set_value(update_cells[i], values[i])
|
||||
if values[i] is String:
|
||||
values[i] = _try_convert(values[i], column_types[update_column])
|
||||
|
||||
if values[i] == null:
|
||||
continue
|
||||
|
||||
update_rows[i].set(columns[update_column], values[i])
|
||||
ResourceSaver.save(update_rows[i])
|
||||
|
||||
io.set_value(
|
||||
update_rows[i],
|
||||
columns[update_column],
|
||||
values[i],
|
||||
row
|
||||
)
|
||||
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:
|
||||
@ -757,6 +800,7 @@ func _update_resources(update_rows : Array, update_cells : Array, update_column
|
||||
values[i]
|
||||
)
|
||||
|
||||
io.save_entries(rows, saved_indices)
|
||||
_update_column_sizes()
|
||||
|
||||
|
||||
@ -771,7 +815,8 @@ func _try_convert(value, type):
|
||||
|
||||
|
||||
func _get_edited_cells_resources() -> Array:
|
||||
var arr := edited_cells.duplicate()
|
||||
var arr := []
|
||||
arr.resize(edited_cells.size())
|
||||
for i in arr.size():
|
||||
arr[i] = rows[_get_cell_row(edited_cells[i])]
|
||||
|
||||
@ -811,8 +856,6 @@ func _on_inspector_property_edited(property : String):
|
||||
if !visible: return
|
||||
if inspector_resource == null: return
|
||||
|
||||
undo_redo_version = my_undo_redo.get_version()
|
||||
|
||||
var value = inspector_resource.get(property)
|
||||
var values = []
|
||||
values.resize(edited_cells.size())
|
||||
@ -847,7 +890,7 @@ func _on_visible_cols_about_to_popup():
|
||||
popup.hide_on_checkable_item_selection = false
|
||||
|
||||
for i in columns.size():
|
||||
popup.add_check_item(TextEditingUtils.string_snake_to_naming_case(columns[i]), i)
|
||||
popup.add_check_item(columns[i].capitalize(), i)
|
||||
popup.set_item_checked(i, hidden_columns[current_path].has(columns[i]))
|
||||
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
[gd_scene load_steps=23 format=3 uid="uid://dpdgrocww8a51"]
|
||||
[gd_scene load_steps=21 format=3 uid="uid://blf43y5mcinf7"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/editor_view.gd" id="1"]
|
||||
[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_cells/cell_editor_string.gd" id="2"]
|
||||
[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_cells/cell_editor_color.gd" id="3"]
|
||||
[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/editor_icon_button.gd" id="4"]
|
||||
[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_cells/cell_editor_bool.gd" id="5"]
|
||||
[ext_resource type="PackedScene" uid="uid://bya5ugi40ptxl" path="res://addons/resources_spreadsheet_view/table_header.tscn" id="6"]
|
||||
[ext_resource type="PackedScene" uid="uid://d1s6oihqedvo5" path="res://addons/resources_spreadsheet_view/table_header.tscn" id="6"]
|
||||
[ext_resource type="PackedScene" uid="uid://b3a3bo6cfyh5t" path="res://addons/resources_spreadsheet_view/typed_editors/dock_color.tscn" id="7"]
|
||||
[ext_resource type="PackedScene" path="res://addons/resources_spreadsheet_view/typed_editors/dock_number.tscn" id="8"]
|
||||
[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_cells/cell_editor_enum_array.gd" id="8_2kaah"]
|
||||
@ -26,18 +26,6 @@ colors = PackedColorArray(1, 1, 1, 0.490196, 1, 1, 1, 0.0458716, 1, 1, 1, 0)
|
||||
[sub_resource type="GradientTexture2D" id="GradientTexture2D_18il8"]
|
||||
gradient = SubResource("Gradient_8kp6w")
|
||||
|
||||
[sub_resource type="Image" id="Image_wmhif"]
|
||||
data = {
|
||||
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 93, 93, 55, 255, 97, 97, 58, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 97, 97, 42, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 98, 98, 47, 255, 97, 97, 42, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 93, 93, 233, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 94, 94, 46, 255, 93, 93, 236, 255, 93, 93, 233, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
|
||||
"format": "RGBA8",
|
||||
"height": 16,
|
||||
"mipmaps": false,
|
||||
"width": 16
|
||||
}
|
||||
|
||||
[sub_resource type="ImageTexture" id="ImageTexture_we5a3"]
|
||||
image = SubResource("Image_wmhif")
|
||||
|
||||
[node name="Control" type="MarginContainer" node_paths=PackedStringArray("node_folder_path", "node_recent_paths", "node_table_root", "node_property_editors", "node_columns", "node_hide_columns_button", "node_page_manager")]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
@ -143,7 +131,7 @@ offset_right = 48.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 2
|
||||
texture = SubResource("GradientTexture2D_18il8")
|
||||
ignore_texture_size = true
|
||||
expand_mode = 1
|
||||
|
||||
[node name="ColorRect3" type="Control" parent="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer"]
|
||||
custom_minimum_size = Vector2(2, 0)
|
||||
@ -162,14 +150,12 @@ caret_blink = true
|
||||
[node name="SelectDir" type="Button" parent="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
tooltip_text = "Open Folder"
|
||||
icon = SubResource("ImageTexture_we5a3")
|
||||
script = ExtResource("4")
|
||||
icon_name = "Folder"
|
||||
|
||||
[node name="DeletePath" type="Button" parent="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
tooltip_text = "Remove Path from Recent"
|
||||
icon = SubResource("ImageTexture_we5a3")
|
||||
script = ExtResource("4")
|
||||
icon_name = "Remove"
|
||||
|
||||
@ -212,7 +198,7 @@ offset_right = 48.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 2
|
||||
texture = SubResource("GradientTexture2D_18il8")
|
||||
ignore_texture_size = true
|
||||
expand_mode = 1
|
||||
|
||||
[node name="Label" type="Label" parent="HeaderContentSplit/VBoxContainer/Search/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
@ -242,7 +228,7 @@ offset_right = 48.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 2
|
||||
texture = SubResource("GradientTexture2D_18il8")
|
||||
ignore_texture_size = true
|
||||
expand_mode = 1
|
||||
|
||||
[node name="Label" type="Label" parent="HeaderContentSplit/VBoxContainer/Search/Search"]
|
||||
layout_mode = 2
|
||||
@ -306,7 +292,6 @@ text = "Grid"
|
||||
[node name="Refresh" type="Button" parent="HeaderContentSplit/VBoxContainer/HBoxContainer3"]
|
||||
layout_mode = 2
|
||||
tooltip_text = "Refresh"
|
||||
icon = SubResource("ImageTexture_we5a3")
|
||||
script = ExtResource("4")
|
||||
icon_name = "Loop"
|
||||
|
||||
@ -348,6 +333,7 @@ layout_mode = 0
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="Sep2" type="Control" parent="HeaderContentSplit/VBoxContainer"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="HeaderContentSplit"]
|
||||
|
@ -0,0 +1,36 @@
|
||||
class_name SpreadsheetEditFormat
|
||||
extends RefCounted
|
||||
|
||||
var editor_view : Control
|
||||
|
||||
## Override to define reading behaviour.
|
||||
func get_value(entry, key : String):
|
||||
pass
|
||||
|
||||
## Override to define writing behaviour. This is NOT supposed to save - use `save_entries`.
|
||||
func set_value(entry, key : String, value, index : int):
|
||||
pass
|
||||
|
||||
## Override to define how the data gets saved.
|
||||
func save_entries(all_entries : Array, indices : Array):
|
||||
pass
|
||||
|
||||
## Override to allow editing rows from the Inspector.
|
||||
func create_resource(entry) -> Resource:
|
||||
return Resource.new()
|
||||
|
||||
## Override to define duplication behaviour. `name_input` should be a suffix if multiple entries, and full name if one.
|
||||
func duplicate_rows(rows : Array, name_input : String):
|
||||
pass
|
||||
|
||||
## Override to define removal behaviour.
|
||||
func delete_rows(rows : Array):
|
||||
pass
|
||||
|
||||
## Override with `return true` if `resource_path` is defined and the Rename butoon should show.
|
||||
func has_row_names():
|
||||
return false
|
||||
|
||||
## Override to define import behaviour. Must return the `rows` value for the editor view.
|
||||
func import_from_path(folderpath : String, insert_func : Callable, sort_by : String, sort_reverse : bool = false) -> Array:
|
||||
return []
|
@ -0,0 +1,91 @@
|
||||
class_name SpreadsheetEditFormatCsv
|
||||
extends SpreadsheetEditFormatTres
|
||||
|
||||
var import_data
|
||||
var csv_rows = []
|
||||
var resource_original_positions = {}
|
||||
var timer : SceneTreeTimer
|
||||
|
||||
|
||||
func get_value(entry, key : String):
|
||||
return entry.get(key)
|
||||
|
||||
|
||||
func set_value(entry, key : String, value, index : int):
|
||||
entry.set(key, value)
|
||||
csv_rows[resource_original_positions[entry]] = import_data.resource_to_strings(entry)
|
||||
|
||||
|
||||
func save_entries(all_entries : Array, indices : Array, repeat : bool = true):
|
||||
if timer == null || timer.time_left <= 0.0:
|
||||
var space_after_delimeter = import_data.delimeter.ends_with(" ")
|
||||
var file = FileAccess.open(import_data.edited_path, FileAccess.WRITE)
|
||||
for x in csv_rows:
|
||||
if space_after_delimeter:
|
||||
for i in x.size():
|
||||
if i == 0: continue
|
||||
x[i] = " " + x[i]
|
||||
|
||||
file.store_csv_line(x, import_data.delimeter[0])
|
||||
|
||||
file.close()
|
||||
if repeat:
|
||||
timer = editor_view.get_tree().create_timer(3.0)
|
||||
timer.timeout.connect(save_entries.bind(all_entries, indices, false))
|
||||
|
||||
|
||||
func create_resource(entry) -> Resource:
|
||||
return entry
|
||||
|
||||
|
||||
func duplicate_rows(rows : Array, name_input : String):
|
||||
for x in rows:
|
||||
var new_res = x.duplicate()
|
||||
var index = resource_original_positions[x]
|
||||
csv_rows.insert(index, import_data.resource_to_strings(new_res))
|
||||
_bump_row_indices(index + 1, 1)
|
||||
resource_original_positions[new_res] = index + 1
|
||||
|
||||
save_entries([], [])
|
||||
|
||||
|
||||
func delete_rows(rows):
|
||||
for x in rows:
|
||||
var index = resource_original_positions[x]
|
||||
csv_rows.remove(index)
|
||||
_bump_row_indices(index, -1)
|
||||
resource_original_positions.erase(x)
|
||||
|
||||
save_entries([], [])
|
||||
|
||||
|
||||
func has_row_names():
|
||||
return false
|
||||
|
||||
|
||||
func _bump_row_indices(from : int, increment : int = 1):
|
||||
for k in resource_original_positions:
|
||||
if resource_original_positions[k] >= from:
|
||||
resource_original_positions[k] += increment
|
||||
|
||||
|
||||
func import_from_path(path : String, insert_func : Callable, sort_by : String, sort_reverse : bool = false) -> Array:
|
||||
import_data = load(path)
|
||||
var file = FileAccess.open(import_data.edited_path, FileAccess.READ)
|
||||
csv_rows = SpreadsheetImportFormatCsv.import_as_arrays(import_data)
|
||||
|
||||
var rows := []
|
||||
var res : Resource
|
||||
resource_original_positions.clear()
|
||||
for i in csv_rows.size():
|
||||
if import_data.remove_first_row and i == 0:
|
||||
continue
|
||||
|
||||
res = import_data.strings_to_resource(csv_rows[i])
|
||||
res.resource_path = ""
|
||||
insert_func.call(res, rows, sort_by, sort_reverse)
|
||||
resource_original_positions[res] = i
|
||||
|
||||
editor_view.fill_property_data(rows[0])
|
||||
file.close()
|
||||
return rows
|
@ -0,0 +1,79 @@
|
||||
class_name SpreadsheetEditFormatTres
|
||||
extends SpreadsheetEditFormat
|
||||
|
||||
|
||||
func get_value(entry, key : String):
|
||||
return entry.get(key)
|
||||
|
||||
|
||||
func set_value(entry, key : String, value, index : int):
|
||||
entry.set(key, value)
|
||||
|
||||
|
||||
func save_entries(all_entries : Array, indices : Array):
|
||||
for x in indices:
|
||||
ResourceSaver.save(all_entries[x])
|
||||
|
||||
|
||||
func create_resource(entry) -> Resource:
|
||||
return entry
|
||||
|
||||
|
||||
func duplicate_rows(rows : Array, name_input : String):
|
||||
if rows.size() == 1:
|
||||
var new_row = rows[0].duplicate()
|
||||
new_row.resource_path = rows[0].resource_path.get_base_dir() + "/" + name_input + ".tres"
|
||||
ResourceSaver.save(new_row)
|
||||
return
|
||||
|
||||
var new_row
|
||||
for x in rows:
|
||||
new_row = x.duplicate()
|
||||
new_row.resource_path = x.resource_path.get_basename() + name_input + ".tres"
|
||||
ResourceSaver.save(new_row)
|
||||
|
||||
|
||||
func rename_row(row, new_name : String):
|
||||
var new_row = row
|
||||
DirAccess.open("res://").remove(row.resource_path)
|
||||
new_row.resource_path = row.resource_path.get_base_dir() + "/" + new_name + ".tres"
|
||||
ResourceSaver.save(new_row)
|
||||
|
||||
|
||||
func delete_rows(rows):
|
||||
for x in rows:
|
||||
DirAccess.open("res://").remove(x.resource_path)
|
||||
|
||||
|
||||
func has_row_names():
|
||||
return true
|
||||
|
||||
|
||||
func import_from_path(folderpath : String, insert_func : Callable, sort_by : String, sort_reverse : bool = false) -> Array:
|
||||
var rows := []
|
||||
var dir := DirAccess.open(folderpath)
|
||||
dir.list_dir_begin()
|
||||
|
||||
editor_view.remembered_paths.clear()
|
||||
var cur_dir_script : Script = null
|
||||
|
||||
var filepath = dir.get_next()
|
||||
var res : Resource
|
||||
|
||||
while filepath != "":
|
||||
if filepath.ends_with(".tres"):
|
||||
filepath = folderpath + filepath
|
||||
res = load(filepath)
|
||||
if !is_instance_valid(cur_dir_script):
|
||||
editor_view.fill_property_data(res)
|
||||
cur_dir_script = res.get_script()
|
||||
if !(sort_by in res):
|
||||
sort_by = "resource_path"
|
||||
|
||||
if res.get_script() == cur_dir_script:
|
||||
insert_func.call(res, rows, sort_by, sort_reverse)
|
||||
editor_view.remembered_paths[res.resource_path] = res
|
||||
|
||||
filepath = dir.get_next()
|
||||
|
||||
return rows
|
@ -0,0 +1,30 @@
|
||||
class_name SpreadsheetExportFormatCsv
|
||||
extends RefCounted
|
||||
|
||||
|
||||
static func export_to_file(entries_array : Array, column_names : Array, into_path : String, import_data):
|
||||
var file = FileAccess.open(into_path, FileAccess.WRITE)
|
||||
|
||||
var line = PackedStringArray()
|
||||
var space_after_delimeter = import_data.delimeter.ends_with(" ")
|
||||
import_data.prop_names = column_names
|
||||
import_data.prop_types = import_data.get_resource_property_types(entries_array[0], column_names)
|
||||
import_data.resource_path = ""
|
||||
line.resize(column_names.size())
|
||||
if import_data.remove_first_row:
|
||||
for j in column_names.size():
|
||||
line[j] = column_names[j]
|
||||
if space_after_delimeter and j != 0:
|
||||
line[j] = " " + line[j]
|
||||
|
||||
file.store_csv_line(line, import_data.delimeter[0])
|
||||
|
||||
for i in entries_array.size():
|
||||
for j in column_names.size():
|
||||
line[j] = import_data.property_to_string((entries_array[i].get(column_names[j])), j)
|
||||
if space_after_delimeter and j != 0:
|
||||
line[j] = " " + line[j]
|
||||
|
||||
file.store_csv_line(line, import_data.delimeter[0])
|
||||
|
||||
file.close()
|
@ -0,0 +1,49 @@
|
||||
class_name SpreadsheetImportFormatCsv
|
||||
extends RefCounted
|
||||
|
||||
|
||||
static func can_edit_path(path : String):
|
||||
return path.ends_with(".csv")
|
||||
|
||||
|
||||
static func import_as_arrays(import_data) -> Array:
|
||||
var file = FileAccess.open(import_data.edited_path, FileAccess.READ)
|
||||
|
||||
import_data.delimeter = ";"
|
||||
var text_lines := [file.get_line().split(import_data.delimeter)]
|
||||
var space_after_delimeter = false
|
||||
var line = text_lines[0]
|
||||
if line.size() == 1:
|
||||
import_data.delimeter = ","
|
||||
line = line[0].split(import_data.delimeter)
|
||||
text_lines[0] = line
|
||||
|
||||
if line[1].begins_with(" "):
|
||||
for i in line.size():
|
||||
line[i] = line[i].trim_prefix(" ")
|
||||
|
||||
text_lines[0] = line
|
||||
space_after_delimeter = true
|
||||
import_data.delimeter += " "
|
||||
|
||||
while !file.eof_reached():
|
||||
line = file.get_csv_line(import_data.delimeter[0])
|
||||
if space_after_delimeter:
|
||||
for i in line.size():
|
||||
line[i] = line[i].trim_prefix(" ")
|
||||
|
||||
if line.size() == text_lines[0].size():
|
||||
text_lines.append(line)
|
||||
|
||||
elif line.size() != 1:
|
||||
line.resize(text_lines[0].size())
|
||||
text_lines.append(line)
|
||||
|
||||
file.close()
|
||||
var entries = []
|
||||
entries.resize(text_lines.size())
|
||||
|
||||
for i in entries.size():
|
||||
entries[i] = text_lines[i]
|
||||
|
||||
return entries
|
@ -0,0 +1,212 @@
|
||||
@tool
|
||||
extends Window
|
||||
|
||||
@export var prop_list_item_scene : PackedScene
|
||||
@export var formats_export : Array[Script]
|
||||
@export var formats_import : Array[Script]
|
||||
|
||||
@onready var editor_view := $"../.."
|
||||
@onready var node_filename_options := $"TabContainer/Import/MarginContainer/ScrollContainer/VBoxContainer/GridContainer/OptionButton"
|
||||
@onready var node_classname_field := $"TabContainer/Import/MarginContainer/ScrollContainer/VBoxContainer/GridContainer/LineEdit"
|
||||
@onready var node_filename_props := $"TabContainer/Import/MarginContainer/ScrollContainer/VBoxContainer/GridContainer/OptionButton"
|
||||
@onready var prop_list := $"TabContainer/Import/MarginContainer/ScrollContainer/VBoxContainer"
|
||||
|
||||
var entries := []
|
||||
|
||||
var property_used_as_filename := 0
|
||||
var import_data : SpreadsheetImport
|
||||
|
||||
|
||||
func _ready():
|
||||
var create_file_button = Button.new()
|
||||
$"../FileDialogText".get_child(3).get_child(3).add_child(create_file_button)
|
||||
create_file_button.get_parent().move_child(create_file_button, 2)
|
||||
create_file_button.text = "Create File"
|
||||
create_file_button.visible = true
|
||||
create_file_button.icon = get_theme_icon("New", "EditorIcons")
|
||||
create_file_button.pressed.connect(_on_create_file_pressed)
|
||||
|
||||
|
||||
func _on_create_file_pressed():
|
||||
var new_name = (
|
||||
$"../FileDialogText".get_child(3).get_child(3).get_child(1).text
|
||||
)
|
||||
if new_name == "":
|
||||
new_name += editor_view.current_path.get_base_dir().get_file()
|
||||
|
||||
var file = FileAccess.open(
|
||||
$"../FileDialogText".get_child(3).get_child(0).get_child(4).text
|
||||
+ "/"
|
||||
+ new_name.get_basename() + ".csv", FileAccess.WRITE
|
||||
)
|
||||
file.close()
|
||||
$"../FileDialogText".invalidate()
|
||||
|
||||
|
||||
func _on_FileDialogText_file_selected(path : String):
|
||||
import_data = SpreadsheetImport.new()
|
||||
import_data.initialize(path)
|
||||
_reset_controls()
|
||||
_open_dialog(path)
|
||||
popup_centered()
|
||||
|
||||
|
||||
func _open_dialog(path : String):
|
||||
node_classname_field.text = import_data.edited_path.get_file().get_basename()\
|
||||
.capitalize().replace(" ", "")
|
||||
import_data.script_classname = node_classname_field.text
|
||||
|
||||
for x in formats_import:
|
||||
if x.new().can_edit_path(path):
|
||||
entries = x.new().import_as_arrays(import_data)
|
||||
|
||||
_load_property_names()
|
||||
_create_prop_editors()
|
||||
$"TabContainer/Import/MarginContainer/ScrollContainer/VBoxContainer/StyleSettingsI"._send_signal()
|
||||
|
||||
|
||||
func _load_property_names():
|
||||
import_data.prop_names = Array(entries[0])
|
||||
import_data.prop_types.resize(import_data.prop_names.size())
|
||||
import_data.prop_types.fill(4)
|
||||
for i in import_data.prop_names.size():
|
||||
import_data.prop_names[i] = entries[0][i]\
|
||||
.replace("\"", "")\
|
||||
.replace(" ", "_")\
|
||||
.replace("-", "_")\
|
||||
.replace(".", "_")\
|
||||
.replace(",", "_")\
|
||||
.replace("\t", "_")\
|
||||
.replace("/", "_")\
|
||||
.replace("\\", "_")\
|
||||
.to_lower()
|
||||
|
||||
# Don't guess Ints automatically - further rows might have floats
|
||||
if entries[1][i].is_valid_float():
|
||||
import_data.prop_types[i] = SpreadsheetImport.PropType.FLOAT
|
||||
|
||||
elif entries[1][i].begins_with("res://"):
|
||||
import_data.prop_types[i] = SpreadsheetImport.PropType.OBJECT
|
||||
|
||||
else:
|
||||
import_data.prop_types[i] = SpreadsheetImport.PropType.STRING
|
||||
|
||||
node_filename_options.clear()
|
||||
for i in import_data.prop_names.size():
|
||||
node_filename_options.add_item(import_data.prop_names[i], i)
|
||||
|
||||
|
||||
func _create_prop_editors():
|
||||
for x in prop_list.get_children():
|
||||
if !x is GridContainer: x.free()
|
||||
|
||||
for i in import_data.prop_names.size():
|
||||
var new_node = prop_list_item_scene.instance()
|
||||
prop_list.add_child(new_node)
|
||||
new_node.display(import_data.prop_names[i], import_data.prop_types[i])
|
||||
new_node.connect_all_signals(self, i)
|
||||
|
||||
|
||||
func _generate_class(save_script = true):
|
||||
save_script = true # Built-ins didn't work in 3.x, won't change because dont wanna test rn
|
||||
import_data.new_script = import_data.generate_script(entries, save_script)
|
||||
if save_script:
|
||||
import_data.new_script.resource_path = import_data.edited_path.get_basename() + ".gd"
|
||||
ResourceSaver.save(import_data.new_script)
|
||||
# Because when instanced, objects have a copy of the script
|
||||
import_data.new_script = load(import_data.edited_path.get_basename() + ".gd")
|
||||
|
||||
|
||||
func _export_tres_folder():
|
||||
DirAccess.open("res://").make_dir_recursive(import_data.edited_path.get_basename())
|
||||
|
||||
import_data.prop_used_as_filename = import_data.prop_names[property_used_as_filename]
|
||||
var new_res : Resource
|
||||
for i in entries.size():
|
||||
if import_data.remove_first_row && i == 0:
|
||||
continue
|
||||
|
||||
new_res = import_data.strings_to_resource(entries[i])
|
||||
ResourceSaver.save(new_res)
|
||||
|
||||
|
||||
func _on_import_to_tres_pressed():
|
||||
hide()
|
||||
_generate_class()
|
||||
_export_tres_folder()
|
||||
await get_tree().process_frame
|
||||
editor_view.display_folder(import_data.edited_path.get_basename() + "/")
|
||||
await get_tree().process_frame
|
||||
editor_view.refresh()
|
||||
|
||||
|
||||
func _on_import_edit_pressed():
|
||||
hide()
|
||||
_generate_class(false)
|
||||
import_data.prop_used_as_filename = ""
|
||||
import_data.save()
|
||||
await get_tree().process_frame
|
||||
editor_view.display_folder(import_data.resource_path)
|
||||
editor_view.hidden_columns[editor_view.current_path] = {
|
||||
"resource_path" : true,
|
||||
"resource_local_to_scene" : true,
|
||||
}
|
||||
editor_view.save_data()
|
||||
await get_tree().process_frame
|
||||
editor_view.refresh()
|
||||
|
||||
|
||||
func _on_export_csv_pressed():
|
||||
hide()
|
||||
var exported_cols = editor_view.columns.duplicate()
|
||||
exported_cols.erase("resource_local_to_scene")
|
||||
for x in editor_view.hidden_columns[editor_view.current_path].keys():
|
||||
exported_cols.erase(x)
|
||||
|
||||
SpreadsheetExportFormatCsv.export_to_file(editor_view.rows, exported_cols, import_data.edited_path, import_data)
|
||||
await get_tree().process_frame
|
||||
editor_view.refresh()
|
||||
|
||||
|
||||
# Input controls
|
||||
func _on_classname_field_text_changed(new_text : String):
|
||||
import_data.script_classname = new_text.replace(" ", "")
|
||||
|
||||
|
||||
func _on_remove_first_row_toggled(button_pressed : bool):
|
||||
import_data.remove_first_row = button_pressed
|
||||
$"TabContainer/Export/HBoxContainer2/Button".pressed = true
|
||||
$"TabContainer/Export/HBoxContainer3/CheckBox".pressed = true
|
||||
|
||||
|
||||
func _on_filename_options_item_selected(index):
|
||||
property_used_as_filename = index
|
||||
|
||||
|
||||
func _on_list_item_type_selected(type : int, index : int):
|
||||
import_data.prop_types[index] = type
|
||||
|
||||
|
||||
func _on_list_item_name_changed(name : String, index : int):
|
||||
import_data.prop_names[index] = name.replace(" ", "")
|
||||
|
||||
|
||||
func _on_export_delimeter_pressed(del : String):
|
||||
import_data.delimeter = del + import_data.delimeter.substr(1)
|
||||
|
||||
|
||||
func _on_export_space_toggled(button_pressed : bool):
|
||||
import_data.delimeter = (
|
||||
import_data.delimeter[0]
|
||||
if !button_pressed else
|
||||
import_data.delimeter + " "
|
||||
)
|
||||
|
||||
|
||||
func _reset_controls():
|
||||
$"TabContainer/Export/HBoxContainer2/CheckBox".pressed = false
|
||||
_on_remove_first_row_toggled(true)
|
||||
|
||||
|
||||
func _on_enum_format_changed(case, delimiter, bool_yes, bool_no):
|
||||
import_data.enum_format = [case, delimiter, bool_yes, bool_no]
|
@ -0,0 +1,172 @@
|
||||
[gd_scene load_steps=5 format=3 uid="uid://b413igx28kkvb"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/import_export/import_export_dialog.gd" id="1"]
|
||||
[ext_resource type="PackedScene" path="res://addons/resources_spreadsheet_view/import_export/property_list_item.tscn" id="2"]
|
||||
[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/import_export/formats_import/import_csv.gd" id="3"]
|
||||
[ext_resource type="PackedScene" path="res://addons/resources_spreadsheet_view/import_export/import_export_enum_format.tscn" id="4"]
|
||||
|
||||
[node name="Control" type="Window"]
|
||||
size = Vector2i(600, 373)
|
||||
wrap_controls = true
|
||||
min_size = Vector2i(600, 0)
|
||||
script = ExtResource("1")
|
||||
prop_list_item_scene = ExtResource("2")
|
||||
formats_import = [ExtResource("3")]
|
||||
|
||||
[node name="TabContainer" type="TabContainer" parent="."]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_right = -552.0
|
||||
offset_bottom = -275.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
use_hidden_tabs_for_min_size = true
|
||||
|
||||
[node name="Import" type="VBoxContainer" parent="TabContainer"]
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="TabContainer/Import"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="ScrollContainer" type="ScrollContainer" parent="TabContainer/Import/MarginContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="TabContainer/Import/MarginContainer/ScrollContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="GridContainer" type="GridContainer" parent="TabContainer/Import/MarginContainer/ScrollContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
columns = 2
|
||||
|
||||
[node name="Label" type="Label" parent="TabContainer/Import/MarginContainer/ScrollContainer/VBoxContainer/GridContainer"]
|
||||
layout_mode = 2
|
||||
text = "Use as filename:"
|
||||
|
||||
[node name="OptionButton" type="OptionButton" parent="TabContainer/Import/MarginContainer/ScrollContainer/VBoxContainer/GridContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Label2" type="Label" parent="TabContainer/Import/MarginContainer/ScrollContainer/VBoxContainer/GridContainer"]
|
||||
layout_mode = 2
|
||||
text = "Class Name"
|
||||
|
||||
[node name="LineEdit" type="LineEdit" parent="TabContainer/Import/MarginContainer/ScrollContainer/VBoxContainer/GridContainer"]
|
||||
layout_mode = 2
|
||||
caret_blink = true
|
||||
caret_blink_interval = 0.5
|
||||
|
||||
[node name="CheckBox" type="CheckBox" parent="TabContainer/Import/MarginContainer/ScrollContainer/VBoxContainer/GridContainer"]
|
||||
layout_mode = 2
|
||||
text = "First row contains property names"
|
||||
|
||||
[node name="Control" type="Control" parent="TabContainer/Import/MarginContainer/ScrollContainer/VBoxContainer/GridContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Control2" type="Control" parent="TabContainer/Import/MarginContainer/ScrollContainer/VBoxContainer/GridContainer"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
|
||||
[node name="StyleSettingsI" parent="TabContainer/Import/MarginContainer/ScrollContainer/VBoxContainer" instance=ExtResource("4")]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="TabContainer/Import"]
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
alignment = 1
|
||||
|
||||
[node name="Ok2" type="Button" parent="TabContainer/Import/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Confirm and edit"
|
||||
|
||||
[node name="Ok" type="Button" parent="TabContainer/Import/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Convert to Resources and edit"
|
||||
|
||||
[node name="Cancel" type="Button" parent="TabContainer/Import/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Cancel"
|
||||
|
||||
[node name="Control" type="Control" parent="TabContainer/Import"]
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="Export" type="VBoxContainer" parent="TabContainer"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Info" type="Label" parent="TabContainer/Export"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 0
|
||||
text = "The currently edited folder will be exported into the selected file.
|
||||
|
||||
Rows hidden by the filter will NOT be exported, and order follows the current sorting key. Rows on non-selected pages will not be removed.
|
||||
|
||||
Hidden columns will NOT be exported."
|
||||
autowrap_mode = 2
|
||||
|
||||
[node name="HSeparator" type="HSeparator" parent="TabContainer/Export"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="HBoxContainer2" type="HBoxContainer" parent="TabContainer/Export"]
|
||||
layout_mode = 2
|
||||
alignment = 1
|
||||
|
||||
[node name="Label2" type="Label" parent="TabContainer/Export/HBoxContainer2"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Delimeter:"
|
||||
|
||||
[node name="Button" type="Button" parent="TabContainer/Export/HBoxContainer2"]
|
||||
layout_mode = 2
|
||||
toggle_mode = true
|
||||
text = "Comma (,)"
|
||||
|
||||
[node name="Button2" type="Button" parent="TabContainer/Export/HBoxContainer2"]
|
||||
layout_mode = 2
|
||||
toggle_mode = true
|
||||
text = "Semicolon (;)"
|
||||
|
||||
[node name="Button3" type="Button" parent="TabContainer/Export/HBoxContainer2"]
|
||||
layout_mode = 2
|
||||
toggle_mode = true
|
||||
text = "Tab"
|
||||
|
||||
[node name="CheckBox" type="CheckBox" parent="TabContainer/Export/HBoxContainer2"]
|
||||
layout_mode = 2
|
||||
text = "With space after"
|
||||
|
||||
[node name="HBoxContainer3" type="HBoxContainer" parent="TabContainer/Export"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="CheckBox" type="CheckBox" parent="TabContainer/Export/HBoxContainer3"]
|
||||
layout_mode = 2
|
||||
text = "First row contains property names (CSV)"
|
||||
|
||||
[node name="StyleSettingsE" parent="TabContainer/Export" instance=ExtResource("4")]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Control" type="Control" parent="TabContainer/Export"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="TabContainer/Export"]
|
||||
layout_mode = 2
|
||||
alignment = 1
|
||||
|
||||
[node name="Button" type="Button" parent="TabContainer/Export/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Export to CSV"
|
||||
|
||||
[node name="Cancel" type="Button" parent="TabContainer/Export/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Cancel"
|
||||
|
||||
[node name="Control2" type="Control" parent="TabContainer/Export"]
|
||||
layout_mode = 2
|
||||
|
||||
[connection signal="pressed" from="TabContainer/Import/HBoxContainer/Cancel" to="." method="hide"]
|
||||
[connection signal="pressed" from="TabContainer/Export/HBoxContainer/Cancel" to="." method="hide"]
|
@ -0,0 +1,20 @@
|
||||
@tool
|
||||
extends GridContainer
|
||||
|
||||
signal format_changed(case, delimiter, bool_yes, bool_no)
|
||||
|
||||
|
||||
func _send_signal(arg1 = null):
|
||||
format_changed.emit(
|
||||
$"HBoxContainer/Case".selected,
|
||||
[" ", "_", "-"][$"HBoxContainer/Separator".selected],
|
||||
$"HBoxContainer2/True".text,
|
||||
$"HBoxContainer2/False".text
|
||||
)
|
||||
|
||||
|
||||
func _on_format_changed(case, delimiter, bool_yes, bool_no):
|
||||
$"HBoxContainer/Case".selected = case
|
||||
$"HBoxContainer/Separator".selected = [" ", "_", "-"].find(delimiter)
|
||||
$"HBoxContainer2/True".text = bool_yes
|
||||
$"HBoxContainer2/False".text = bool_no
|
@ -0,0 +1,76 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/resources_speadsheet_view/import_export/import_export_enum_format.gd" type="Script" id=1]
|
||||
|
||||
[node name="EnumFormat" type="GridContainer"]
|
||||
margin_right = 400.0
|
||||
margin_bottom = 48.0
|
||||
rect_pivot_offset = Vector2( 40, 71 )
|
||||
columns = 2
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="Label3" type="Label" parent="."]
|
||||
margin_top = 3.0
|
||||
margin_right = 198.0
|
||||
margin_bottom = 17.0
|
||||
size_flags_horizontal = 3
|
||||
text = "Enum word case/separator"
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="."]
|
||||
margin_left = 202.0
|
||||
margin_right = 400.0
|
||||
margin_bottom = 20.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Case" type="OptionButton" parent="HBoxContainer"]
|
||||
margin_right = 129.0
|
||||
margin_bottom = 20.0
|
||||
size_flags_horizontal = 3
|
||||
text = "Caps Every Word"
|
||||
clip_text = true
|
||||
items = [ "all lower", null, false, 0, null, "caps Except First", null, false, 1, null, "Caps Every Word", null, false, 2, null, "ALL CAPS", null, false, 3, null ]
|
||||
selected = 2
|
||||
|
||||
[node name="Separator" type="OptionButton" parent="HBoxContainer"]
|
||||
margin_left = 133.0
|
||||
margin_right = 198.0
|
||||
margin_bottom = 20.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_stretch_ratio = 0.5
|
||||
text = "Space \" \""
|
||||
clip_text = true
|
||||
items = [ "Space \" \"", null, false, 0, null, "Underscore \"_\"", null, false, 1, null, "Kebab \"-\"", null, false, 2, null ]
|
||||
selected = 0
|
||||
|
||||
[node name="Label4" type="Label" parent="."]
|
||||
margin_top = 29.0
|
||||
margin_right = 198.0
|
||||
margin_bottom = 43.0
|
||||
size_flags_horizontal = 3
|
||||
text = "Boolean True/False"
|
||||
|
||||
[node name="HBoxContainer2" type="HBoxContainer" parent="."]
|
||||
margin_left = 202.0
|
||||
margin_top = 24.0
|
||||
margin_right = 400.0
|
||||
margin_bottom = 48.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="True" type="LineEdit" parent="HBoxContainer2"]
|
||||
margin_right = 97.0
|
||||
margin_bottom = 24.0
|
||||
size_flags_horizontal = 3
|
||||
text = "Yes"
|
||||
|
||||
[node name="False" type="LineEdit" parent="HBoxContainer2"]
|
||||
margin_left = 101.0
|
||||
margin_right = 198.0
|
||||
margin_bottom = 24.0
|
||||
size_flags_horizontal = 3
|
||||
text = "No"
|
||||
|
||||
[connection signal="mouse_entered" from="Label3" to="." method="_on_Label3_mouse_entered"]
|
||||
[connection signal="item_selected" from="HBoxContainer/Case" to="." method="_send_signal"]
|
||||
[connection signal="item_selected" from="HBoxContainer/Separator" to="." method="_send_signal"]
|
||||
[connection signal="text_changed" from="HBoxContainer2/True" to="." method="_send_signal"]
|
||||
[connection signal="text_changed" from="HBoxContainer2/False" to="." method="_send_signal"]
|
@ -0,0 +1,12 @@
|
||||
@tool
|
||||
extends HBoxContainer
|
||||
|
||||
|
||||
func display(name : String, type : int):
|
||||
$"LineEdit".text = name
|
||||
$"OptionButton".selected = type
|
||||
|
||||
|
||||
func connect_all_signals(to : Object, index : int, prefix : String = "_on_list_item_"):
|
||||
$"LineEdit".text_changed.connect(Callable(to, prefix + "name_changed").bind(index))
|
||||
$"OptionButton".item_selected.connect(Callable(to, prefix + "type_selected").bind(index))
|
@ -0,0 +1,26 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/resources_speadsheet_view/import_export/property_list_item.gd" type="Script" id=1]
|
||||
|
||||
[node name="Entry" type="HBoxContainer"]
|
||||
margin_right = 468.0
|
||||
margin_bottom = 24.0
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="LineEdit" type="LineEdit" parent="."]
|
||||
margin_right = 309.0
|
||||
margin_bottom = 24.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_stretch_ratio = 0.5
|
||||
text = "1"
|
||||
|
||||
[node name="OptionButton" type="OptionButton" parent="."]
|
||||
margin_left = 313.0
|
||||
margin_right = 468.0
|
||||
margin_bottom = 24.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 5
|
||||
size_flags_stretch_ratio = 0.25
|
||||
text = "Bool"
|
||||
items = [ "Bool", null, false, 1, null, "Integer Number", null, false, 2, null, "Floating Point Number", null, false, 3, null, "String/Other", null, false, 4, null, "Vector2", null, true, 5, null, "Rect2", null, true, 6, null, "Vector3", null, true, 7, null, "Color", null, false, 14, null, "Array", null, true, 19, null, "Resource Path", null, false, 17, null, "Enumeration", null, false, 101, null ]
|
||||
selected = 0
|
@ -0,0 +1,293 @@
|
||||
@tool
|
||||
class_name SpreadsheetImport
|
||||
extends Resource
|
||||
|
||||
enum PropType {
|
||||
BOOL,
|
||||
INT,
|
||||
FLOAT,
|
||||
STRING,
|
||||
VECTOR2,
|
||||
RECT2,
|
||||
VECTOR3,
|
||||
COLOR,
|
||||
ARRAY,
|
||||
OBJECT,
|
||||
ENUM,
|
||||
MAX,
|
||||
}
|
||||
|
||||
enum NameCasing {
|
||||
ALL_LOWER,
|
||||
CAPS_WORD_EXCEPT_FIRST,
|
||||
CAPS_WORD,
|
||||
ALL_CAPS,
|
||||
}
|
||||
|
||||
const SUFFIX := "_spreadsheet_import.tres"
|
||||
const TYPE_MAP := {
|
||||
TYPE_STRING : PropType.STRING,
|
||||
TYPE_FLOAT : PropType.FLOAT,
|
||||
TYPE_BOOL : PropType.BOOL,
|
||||
TYPE_INT : PropType.INT,
|
||||
TYPE_OBJECT : PropType.OBJECT,
|
||||
TYPE_COLOR : PropType.COLOR,
|
||||
}
|
||||
|
||||
@export var prop_types : Array
|
||||
@export var prop_names : Array
|
||||
|
||||
@export var edited_path := "res://"
|
||||
@export var prop_used_as_filename := ""
|
||||
@export var script_classname := ""
|
||||
@export var remove_first_row := true
|
||||
|
||||
@export var new_script : GDScript
|
||||
@export var view_script : Script = SpreadsheetEditFormatCsv
|
||||
@export var delimeter := ";"
|
||||
@export var enum_format : Array = [NameCasing.CAPS_WORD, " ", "Yes", "No"]
|
||||
|
||||
@export var uniques : Dictionary
|
||||
|
||||
|
||||
func initialize(path):
|
||||
edited_path = path
|
||||
prop_types = []
|
||||
prop_names = []
|
||||
|
||||
|
||||
func save():
|
||||
ResourceSaver.call_deferred("save", edited_path.get_basename() + SUFFIX, self)
|
||||
|
||||
|
||||
func string_to_property(string : String, col_index : int):
|
||||
match prop_types[col_index]:
|
||||
PropType.STRING:
|
||||
return string
|
||||
|
||||
PropType.BOOL:
|
||||
string = string.to_lower()
|
||||
if string == enum_format[2].to_lower(): return true
|
||||
if string == enum_format[3].to_lower(): return false
|
||||
return !string in ["no", "disabled", "-", "false", "absent", "wrong", "off", ""]
|
||||
|
||||
PropType.FLOAT:
|
||||
return string.to_float()
|
||||
|
||||
PropType.INT:
|
||||
return string.to_int()
|
||||
|
||||
PropType.COLOR:
|
||||
return Color(string)
|
||||
|
||||
PropType.OBJECT:
|
||||
return load(string)
|
||||
|
||||
PropType.ENUM:
|
||||
if string == "":
|
||||
return int(uniques[col_index]["N_A"])
|
||||
|
||||
else:
|
||||
return int(uniques[col_index][string.capitalize().replace(" ", "_").to_upper()])
|
||||
|
||||
|
||||
func property_to_string(value, col_index : int) -> String:
|
||||
if value == null: return ""
|
||||
if col_index == 0:
|
||||
if prop_names[col_index] == "resource_path":
|
||||
return value.get_file().get_basename()
|
||||
|
||||
if prop_types[col_index] is PackedStringArray:
|
||||
return prop_types[col_index][value].capitalize()
|
||||
|
||||
match prop_types[col_index]:
|
||||
PropType.STRING:
|
||||
return str(value)
|
||||
|
||||
PropType.BOOL:
|
||||
return enum_format[2] if value else enum_format[3]
|
||||
|
||||
PropType.FLOAT, PropType.INT:
|
||||
return str(value)
|
||||
|
||||
PropType.COLOR:
|
||||
return value.to_html()
|
||||
|
||||
PropType.OBJECT:
|
||||
return value.resource_path
|
||||
|
||||
PropType.ENUM:
|
||||
var dict = uniques[col_index]
|
||||
for k in dict:
|
||||
if dict[k] == value:
|
||||
return change_name_to_format(k, enum_format[0], enum_format[1])
|
||||
|
||||
return str(value)
|
||||
|
||||
|
||||
func create_property_line_for_prop(col_index : int) -> String:
|
||||
var result = "@export var " + prop_names[col_index] + " :"
|
||||
match prop_types[col_index]:
|
||||
PropType.STRING:
|
||||
return result + "= \"\"\r\n"
|
||||
|
||||
PropType.BOOL:
|
||||
return result + "= false\r\n"
|
||||
|
||||
PropType.FLOAT:
|
||||
return result + "= 0.0\r\n"
|
||||
|
||||
PropType.INT:
|
||||
return result + "= 0\r\n"
|
||||
|
||||
PropType.COLOR:
|
||||
return result + "= Color.white\r\n"
|
||||
|
||||
PropType.OBJECT:
|
||||
return result + " Resource\r\n"
|
||||
|
||||
PropType.ENUM:
|
||||
return result + ": %s\r\n" % _escape_forbidden_enum_names(prop_names[col_index].capitalize().replace(" ", ""))
|
||||
# return result.replace(
|
||||
# "@export var",
|
||||
# "@export_enum(" + _escape_forbidden_enum_names(
|
||||
# prop_names[col_index].capitalize()\
|
||||
# .replace(" ", "")
|
||||
# ) + ") var"
|
||||
# ) + "= 0\r\n"
|
||||
|
||||
return ""
|
||||
|
||||
|
||||
func _escape_forbidden_enum_names(string : String) -> String:
|
||||
if ClassDB.class_exists(string):
|
||||
return string + "_"
|
||||
|
||||
# Not in ClassDB, but are engine types and can be property names
|
||||
if string in [
|
||||
"Color", "String", "Plane",
|
||||
"Basis", "Transform", "Variant",
|
||||
]:
|
||||
return string + "_"
|
||||
|
||||
return string
|
||||
|
||||
|
||||
func create_enum_for_prop(col_index) -> String:
|
||||
var result := (
|
||||
"enum "
|
||||
+ _escape_forbidden_enum_names(
|
||||
prop_names[col_index].capitalize().replace(" ", "")
|
||||
) + " {\r\n"
|
||||
)
|
||||
for k in uniques[col_index]:
|
||||
result += (
|
||||
"\t"
|
||||
+ k # Enum Entry
|
||||
+ " = "
|
||||
+ str(uniques[col_index][k]) # Value
|
||||
+ ",\r\n"
|
||||
)
|
||||
result += "\tMAX,\r\n}\r\n\r\n"
|
||||
return result
|
||||
|
||||
|
||||
func generate_script(entries, has_classname = true) -> GDScript:
|
||||
var source = ""
|
||||
if has_classname and script_classname != "":
|
||||
source = "class_name " + script_classname + " \r\nextends Resource\r\n\r\n"
|
||||
|
||||
else:
|
||||
source = "extends Resource\r\n\r\n"
|
||||
|
||||
# Enums
|
||||
uniques = get_uniques(entries)
|
||||
for i in prop_types.size():
|
||||
if prop_types[i] == PropType.ENUM:
|
||||
source += create_enum_for_prop(i)
|
||||
|
||||
# Properties
|
||||
for i in prop_names.size():
|
||||
if (prop_names[i] != "resource_path") and (prop_names[i] != "resource_name"):
|
||||
source += create_property_line_for_prop(i)
|
||||
|
||||
var created_script = GDScript.new()
|
||||
created_script.source_code = source
|
||||
created_script.reload()
|
||||
return created_script
|
||||
|
||||
|
||||
func strings_to_resource(strings : Array):
|
||||
var new_res = new_script.new()
|
||||
for j in min(prop_names.size(), strings.size()):
|
||||
new_res.set(prop_names[j], string_to_property(strings[j], j))
|
||||
|
||||
if prop_used_as_filename != "":
|
||||
new_res.resource_path = edited_path.get_basename() + "/" + new_res.get(prop_used_as_filename) + ".tres"
|
||||
|
||||
return new_res
|
||||
|
||||
|
||||
func resource_to_strings(res : Resource):
|
||||
var strings := []
|
||||
strings.resize(prop_names.size())
|
||||
for i in prop_names.size():
|
||||
strings[i] = property_to_string(res.get(prop_names[i]), i)
|
||||
|
||||
return PackedStringArray(strings)
|
||||
|
||||
|
||||
func get_uniques(entries : Array) -> Dictionary:
|
||||
var result = {}
|
||||
for i in prop_types.size():
|
||||
if prop_types[i] == PropType.ENUM:
|
||||
var cur_value := ""
|
||||
result[i] = {}
|
||||
for j in entries.size():
|
||||
if j == 0 and remove_first_row: continue
|
||||
|
||||
cur_value = entries[j][i].capitalize().to_upper().replace(" ", "_")
|
||||
if cur_value == "":
|
||||
cur_value = "N_A"
|
||||
|
||||
if !result[i].has(cur_value):
|
||||
result[i][cur_value] = result[i].size()
|
||||
|
||||
return result
|
||||
|
||||
|
||||
static func change_name_to_format(name : String, case : int, delim : String):
|
||||
var string = name.capitalize().replace(" ", delim)
|
||||
if case == NameCasing.ALL_LOWER:
|
||||
return string.to_lower()
|
||||
|
||||
if case == NameCasing.CAPS_WORD_EXCEPT_FIRST:
|
||||
return string[0].to_lower() + string.substr(1)
|
||||
|
||||
if case == NameCasing.CAPS_WORD:
|
||||
return string
|
||||
|
||||
if case == NameCasing.ALL_CAPS:
|
||||
return string.to_upper()
|
||||
|
||||
|
||||
static func get_resource_property_types(res : Resource, properties : Array) -> Array:
|
||||
var result = []
|
||||
result.resize(properties.size())
|
||||
result.fill(PropType.STRING)
|
||||
var cur_type := 0
|
||||
for x in res.get_property_list():
|
||||
var found = properties.find(x["name"])
|
||||
if found == -1: continue
|
||||
if x["usage"] & PROPERTY_USAGE_EDITOR != 0:
|
||||
if x["hint"] == PROPERTY_HINT_ENUM:
|
||||
var enum_values = x["hint_string"].split(",")
|
||||
for i in enum_values.size():
|
||||
enum_values[i] = enum_values[i].left(enum_values[i].find(":"))
|
||||
|
||||
result[found] = enum_values
|
||||
|
||||
else:
|
||||
result[found] = TYPE_MAP.get(x["type"], PropType.STRING)
|
||||
|
||||
return result
|
@ -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="2.1"
|
||||
version="2.3"
|
||||
script="plugin.gd"
|
||||
|
@ -1 +0,0 @@
|
||||
{ "recent_paths": ["res://example/Random Upgrades/upgrades", "res://example/Random Upgrades/upgrades/"], "hidden_columns": { "res://example/Random Upgrades/upgrades/": { "resource_name": true, "resource_local_to_scene": true, "list_item_delimeter": true, "list_row_delimeter": true } } }
|
177
addons/resources_spreadsheet_view/selection_actions.gd
Normal file
177
addons/resources_spreadsheet_view/selection_actions.gd
Normal file
@ -0,0 +1,177 @@
|
||||
@tool
|
||||
extends MarginContainer
|
||||
|
||||
enum {
|
||||
EDITBOX_DUPLICATE = 1,
|
||||
EDITBOX_RENAME,
|
||||
EDITBOX_DELETE,
|
||||
}
|
||||
|
||||
@export var editor_view := NodePath("../..")
|
||||
|
||||
@onready var editbox_node := $"Control/ColorRect/Popup"
|
||||
@onready var editbox_label := editbox_node.get_node("Panel/VBoxContainer/Label")
|
||||
@onready var editbox_input := editbox_node.get_node("Panel/VBoxContainer/LineEdit")
|
||||
|
||||
var cell : Control
|
||||
var editbox_action : int
|
||||
|
||||
|
||||
func _ready():
|
||||
editbox_input.get_node("../..").add_theme_stylebox_override(
|
||||
"panel",
|
||||
get_theme_stylebox("Content", "EditorStyles")
|
||||
)
|
||||
|
||||
|
||||
func _on_grid_cells_context(cells):
|
||||
open(cells)
|
||||
|
||||
|
||||
func _on_grid_cells_selected(cells):
|
||||
if ProjectSettings.get_setting(SettingsGrid.SETTING_PREFIX + "context_menu_on_leftclick"):
|
||||
open(cells, true)
|
||||
|
||||
else: hide()
|
||||
|
||||
|
||||
func open(cells : Array, pin_to_cell : bool = false):
|
||||
if cells.size() == 0:
|
||||
hide()
|
||||
cell = null
|
||||
return
|
||||
|
||||
if pin_to_cell:
|
||||
cell = cells[-1]
|
||||
global_position = Vector2(
|
||||
cell.global_position.x + cell.size.x,
|
||||
cell.global_position.y
|
||||
)
|
||||
|
||||
else:
|
||||
cell = null
|
||||
global_position = get_global_mouse_position() + Vector2.ONE
|
||||
|
||||
size = Vector2.ZERO
|
||||
top_level = true
|
||||
show()
|
||||
$"Control2/Label".text = str(cells.size()) + (" Cells" if cells.size() % 10 != 1 else " Cell")
|
||||
$"GridContainer/Rename".visible = get_node(editor_view).has_row_names()
|
||||
|
||||
|
||||
func _unhandled_input(event):
|
||||
if !get_node(editor_view).is_visible_in_tree():
|
||||
hide()
|
||||
return
|
||||
|
||||
if event is InputEventKey:
|
||||
if Input.is_key_pressed(KEY_CTRL):
|
||||
# Dupe
|
||||
if event.keycode == KEY_D:
|
||||
_on_Duplicate_pressed()
|
||||
return
|
||||
|
||||
# Rename
|
||||
if event.keycode == KEY_R:
|
||||
_on_Rename_pressed()
|
||||
return
|
||||
|
||||
if event is InputEventMouseButton && event.is_pressed():
|
||||
hide()
|
||||
|
||||
|
||||
func _input(event):
|
||||
if cell == null: return
|
||||
if !get_node(editor_view).is_visible_in_tree():
|
||||
hide()
|
||||
return
|
||||
|
||||
global_position = Vector2(
|
||||
cell.global_position.x + cell.size.x,
|
||||
cell.global_position.y
|
||||
)
|
||||
|
||||
|
||||
func _on_Duplicate_pressed():
|
||||
_show_editbox(EDITBOX_DUPLICATE)
|
||||
|
||||
|
||||
func _on_CbCopy_pressed():
|
||||
TextEditingUtils.multi_copy(get_node(editor_view).edited_cells_text)
|
||||
|
||||
|
||||
func _on_CbPaste_pressed():
|
||||
get_node(editor_view).set_edited_cells_values(
|
||||
TextEditingUtils.multi_paste(
|
||||
get_node(editor_view).edited_cells_text,
|
||||
get_node(editor_view).edit_cursor_positions
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
func _on_Rename_pressed():
|
||||
_show_editbox(EDITBOX_RENAME)
|
||||
|
||||
|
||||
func _on_Delete_pressed():
|
||||
_show_editbox(EDITBOX_DELETE)
|
||||
|
||||
|
||||
func _show_editbox(action):
|
||||
var node_editor_view = get_node(editor_view)
|
||||
editbox_action = action
|
||||
match action:
|
||||
EDITBOX_DUPLICATE:
|
||||
if !node_editor_view.has_row_names():
|
||||
_on_editbox_accepted()
|
||||
return
|
||||
|
||||
if node_editor_view.edited_cells.size() == 1:
|
||||
editbox_label.text = "Input new row's name..."
|
||||
editbox_input.text = node_editor_view.get_last_selected_row()\
|
||||
.resource_path.get_file().get_basename()
|
||||
|
||||
else:
|
||||
editbox_label.text = "Input suffix to append to names..."
|
||||
editbox_input.text = ""
|
||||
|
||||
EDITBOX_RENAME:
|
||||
editbox_label.text = "Input new name for row..."
|
||||
editbox_input.text = node_editor_view.get_last_selected_row()\
|
||||
.resource_path.get_file().get_basename()
|
||||
|
||||
EDITBOX_DELETE:
|
||||
editbox_label.text = "Really delete selected rows? (Irreversible!!!)"
|
||||
editbox_input.text = node_editor_view.get_last_selected_row()\
|
||||
.resource_path.get_file().get_basename()
|
||||
|
||||
editbox_input.grab_focus()
|
||||
editbox_input.caret_position = 999999999
|
||||
editbox_node.show()
|
||||
$"Control/ColorRect".show()
|
||||
$"Control/ColorRect".top_level = true
|
||||
$"Control/ColorRect".size = get_viewport_rect().size * 4.0
|
||||
editbox_node.global_position = (
|
||||
global_position
|
||||
+ size * 0.5
|
||||
- editbox_node.get_child(0).size * 0.5
|
||||
)
|
||||
|
||||
|
||||
func _on_editbox_closed():
|
||||
editbox_node.hide()
|
||||
$"Control/ColorRect".hide()
|
||||
|
||||
|
||||
func _on_editbox_accepted():
|
||||
match(editbox_action):
|
||||
EDITBOX_DUPLICATE:
|
||||
get_node(editor_view).duplicate_selected_rows(editbox_input.text)
|
||||
|
||||
EDITBOX_RENAME:
|
||||
get_node(editor_view).rename_row(get_node(editor_view).get_last_selected_row(), editbox_input.text)
|
||||
|
||||
EDITBOX_DELETE:
|
||||
get_node(editor_view).delete_selected_rows()
|
||||
|
||||
_on_editbox_closed()
|
217
addons/resources_spreadsheet_view/selection_actions.tscn
Normal file
217
addons/resources_spreadsheet_view/selection_actions.tscn
Normal file
@ -0,0 +1,217 @@
|
||||
[gd_scene load_steps=8 format=2]
|
||||
|
||||
[ext_resource path="res://addons/resources_speadsheet_view/editor_icon_button.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/resources_speadsheet_view/selection_actions.gd" type="Script" id=2]
|
||||
|
||||
[sub_resource type="Image" id=6]
|
||||
data = {
|
||||
"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ),
|
||||
"format": "LumAlpha8",
|
||||
"height": 16,
|
||||
"mipmaps": false,
|
||||
"width": 16
|
||||
}
|
||||
|
||||
[sub_resource type="ImageTexture" id=2]
|
||||
flags = 4
|
||||
flags = 4
|
||||
image = SubResource( 6 )
|
||||
size = Vector2( 16, 16 )
|
||||
|
||||
[sub_resource type="Image" id=7]
|
||||
data = {
|
||||
"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ),
|
||||
"format": "LumAlpha8",
|
||||
"height": 16,
|
||||
"mipmaps": false,
|
||||
"width": 16
|
||||
}
|
||||
|
||||
[sub_resource type="ImageTexture" id=4]
|
||||
flags = 4
|
||||
flags = 4
|
||||
image = SubResource( 7 )
|
||||
size = Vector2( 16, 16 )
|
||||
|
||||
[sub_resource type="StyleBoxTexture" id=5]
|
||||
texture = SubResource( 4 )
|
||||
region_rect = Rect2( 0, 0, 16, 16 )
|
||||
margin_left = 2.0
|
||||
margin_right = 2.0
|
||||
margin_top = 2.0
|
||||
margin_bottom = 2.0
|
||||
|
||||
[node name="SelectionActions" type="MarginContainer"]
|
||||
margin_right = 84.0
|
||||
margin_bottom = 44.0
|
||||
mouse_filter = 2
|
||||
size_flags_horizontal = 9
|
||||
script = ExtResource( 2 )
|
||||
__meta__ = {
|
||||
"_edit_group_": true,
|
||||
"_edit_lock_": true
|
||||
}
|
||||
|
||||
[node name="Control2" type="Control" parent="."]
|
||||
margin_right = 84.0
|
||||
margin_bottom = 44.0
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="ColorRect" type="ColorRect" parent="Control2"]
|
||||
show_behind_parent = true
|
||||
margin_left = -2.0
|
||||
margin_top = -18.0
|
||||
margin_bottom = 2.0
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="ColorRect2" type="ColorRect" parent="Control2"]
|
||||
show_behind_parent = true
|
||||
anchor_bottom = 1.0
|
||||
margin_left = -2.0
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="Label" type="Label" parent="Control2"]
|
||||
margin_left = 2.0
|
||||
margin_top = -16.0
|
||||
margin_right = 50.0
|
||||
margin_bottom = -2.0
|
||||
text = "Actions"
|
||||
|
||||
[node name="ColorRect3" type="Panel" parent="Control2/Label"]
|
||||
show_behind_parent = true
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = -2.0
|
||||
margin_top = -2.0
|
||||
margin_bottom = 2.0
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="GridContainer" type="GridContainer" parent="."]
|
||||
margin_right = 84.0
|
||||
margin_bottom = 44.0
|
||||
mouse_filter = 2
|
||||
size_flags_horizontal = 9
|
||||
size_flags_vertical = 9
|
||||
custom_constants/vseparation = 0
|
||||
custom_constants/hseparation = 0
|
||||
columns = 3
|
||||
|
||||
[node name="Duplicate" type="Button" parent="GridContainer"]
|
||||
margin_right = 28.0
|
||||
margin_bottom = 22.0
|
||||
tooltip_text = "Duplicate Selected Rows (Ctrl+D)"
|
||||
mouse_filter = 1
|
||||
icon = SubResource( 2 )
|
||||
script = ExtResource( 1 )
|
||||
icon_name = "Duplicate"
|
||||
|
||||
[node name="CbCopy" type="Button" parent="GridContainer"]
|
||||
margin_left = 28.0
|
||||
margin_right = 56.0
|
||||
margin_bottom = 22.0
|
||||
tooltip_text = "Copy to Clipboard (Ctrl+C)"
|
||||
mouse_filter = 1
|
||||
icon = SubResource( 2 )
|
||||
script = ExtResource( 1 )
|
||||
icon_name = "ActionCopy"
|
||||
|
||||
[node name="CbPaste" type="Button" parent="GridContainer"]
|
||||
margin_left = 56.0
|
||||
margin_right = 84.0
|
||||
margin_bottom = 22.0
|
||||
tooltip_text = "Paste Clipboard (Ctrl+V)"
|
||||
mouse_filter = 1
|
||||
icon = SubResource( 2 )
|
||||
script = ExtResource( 1 )
|
||||
icon_name = "ActionPaste"
|
||||
|
||||
[node name="Rename" type="Button" parent="GridContainer"]
|
||||
margin_top = 22.0
|
||||
margin_right = 28.0
|
||||
margin_bottom = 44.0
|
||||
tooltip_text = "Rename Selected Rows (Ctrl+R)"
|
||||
mouse_filter = 1
|
||||
icon = SubResource( 2 )
|
||||
script = ExtResource( 1 )
|
||||
icon_name = "Edit"
|
||||
|
||||
[node name="Delete" type="Button" parent="GridContainer"]
|
||||
margin_left = 28.0
|
||||
margin_top = 22.0
|
||||
margin_right = 56.0
|
||||
margin_bottom = 44.0
|
||||
tooltip_text = "DELETE Selected Rows"
|
||||
mouse_filter = 1
|
||||
icon = SubResource( 2 )
|
||||
script = ExtResource( 1 )
|
||||
icon_name = "Remove"
|
||||
|
||||
[node name="Control" type="Control" parent="."]
|
||||
margin_right = 84.0
|
||||
margin_bottom = 44.0
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="ColorRect" type="ColorRect" parent="Control"]
|
||||
visible = false
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
color = Color( 0, 0, 0, 0.498039 )
|
||||
|
||||
[node name="Popup" type="Popup" parent="Control/ColorRect"]
|
||||
visible = true
|
||||
margin_left = 42.0
|
||||
margin_top = 22.0
|
||||
margin_right = 42.0
|
||||
margin_bottom = 22.0
|
||||
mouse_filter = 2
|
||||
popup_exclusive = true
|
||||
|
||||
[node name="Panel" type="PanelContainer" parent="Control/ColorRect/Popup"]
|
||||
margin_right = 14.0
|
||||
margin_bottom = 14.0
|
||||
rect_min_size = Vector2( 192, 0 )
|
||||
mouse_filter = 2
|
||||
custom_styles/panel = SubResource( 5 )
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="Control/ColorRect/Popup/Panel"]
|
||||
margin_left = 7.0
|
||||
margin_top = 7.0
|
||||
margin_right = 185.0
|
||||
margin_bottom = 73.0
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="Label" type="Label" parent="Control/ColorRect/Popup/Panel/VBoxContainer"]
|
||||
margin_right = 178.0
|
||||
margin_bottom = 14.0
|
||||
text = "Input new name..."
|
||||
|
||||
[node name="LineEdit" type="LineEdit" parent="Control/ColorRect/Popup/Panel/VBoxContainer"]
|
||||
margin_top = 18.0
|
||||
margin_right = 178.0
|
||||
margin_bottom = 42.0
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Control/ColorRect/Popup/Panel/VBoxContainer"]
|
||||
margin_top = 46.0
|
||||
margin_right = 178.0
|
||||
margin_bottom = 66.0
|
||||
alignment = 1
|
||||
|
||||
[node name="Button" type="Button" parent="Control/ColorRect/Popup/Panel/VBoxContainer/HBoxContainer"]
|
||||
margin_left = 44.0
|
||||
margin_right = 75.0
|
||||
margin_bottom = 20.0
|
||||
text = "OK"
|
||||
|
||||
[node name="Button2" type="Button" parent="Control/ColorRect/Popup/Panel/VBoxContainer/HBoxContainer"]
|
||||
margin_left = 79.0
|
||||
margin_right = 133.0
|
||||
margin_bottom = 20.0
|
||||
text = "Cancel"
|
||||
|
||||
[connection signal="pressed" from="GridContainer/Duplicate" to="." method="_on_Duplicate_pressed"]
|
||||
[connection signal="pressed" from="GridContainer/CbCopy" to="." method="_on_CbCopy_pressed"]
|
||||
[connection signal="pressed" from="GridContainer/CbPaste" to="." method="_on_CbPaste_pressed"]
|
||||
[connection signal="pressed" from="GridContainer/Rename" to="." method="_on_Rename_pressed"]
|
||||
[connection signal="pressed" from="GridContainer/Delete" to="." method="_on_Delete_pressed"]
|
||||
[connection signal="pressed" from="Control/ColorRect/Popup/Panel/VBoxContainer/HBoxContainer/Button" to="." method="_on_editbox_accepted"]
|
||||
[connection signal="pressed" from="Control/ColorRect/Popup/Panel/VBoxContainer/HBoxContainer/Button2" to="." method="_on_editbox_closed"]
|
@ -7,7 +7,7 @@ const SETTING_PREFIX = "addons/resources_spreadsheet_view/"
|
||||
|
||||
func _ready():
|
||||
for x in get_children():
|
||||
var setting = SETTING_PREFIX + TextEditingUtils.pascal_case_to_snake_case(x.name)
|
||||
var setting = SETTING_PREFIX + x.name.to_snake_case()
|
||||
if x is BaseButton:
|
||||
x.toggled.connect(_set_setting.bind(setting))
|
||||
if !ProjectSettings.has_setting(setting):
|
||||
|
@ -5,7 +5,7 @@ var editor_view : Control
|
||||
|
||||
|
||||
func set_label(label : String):
|
||||
$"Button".text = TextEditingUtils.string_snake_to_naming_case(label)
|
||||
$"Button".text = label.capitalize()
|
||||
$"Button".tooltip_text = label + "\nClick to sort."
|
||||
|
||||
|
||||
|
@ -1,33 +1,16 @@
|
||||
[gd_scene load_steps=5 format=3 uid="uid://bya5ugi40ptxl"]
|
||||
[gd_scene load_steps=3 format=3 uid="uid://d1s6oihqedvo5"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/table_header.gd" id="1_xhap0"]
|
||||
[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/editor_icon_button.gd" id="2_t08bs"]
|
||||
|
||||
[sub_resource type="Image" id="Image_1jisk"]
|
||||
data = {
|
||||
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 93, 93, 55, 255, 97, 97, 58, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 97, 97, 42, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 98, 98, 47, 255, 97, 97, 42, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 93, 93, 233, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 94, 94, 46, 255, 93, 93, 236, 255, 93, 93, 233, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
|
||||
"format": "RGBA8",
|
||||
"height": 16,
|
||||
"mipmaps": false,
|
||||
"width": 16
|
||||
}
|
||||
|
||||
[sub_resource type="ImageTexture" id="ImageTexture_wgkau"]
|
||||
image = SubResource("Image_1jisk")
|
||||
|
||||
[node name="Header" type="HBoxContainer"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
offset_right = 179.0
|
||||
offset_bottom = 31.0
|
||||
size_flags_horizontal = 3
|
||||
script = ExtResource("1_xhap0")
|
||||
|
||||
[node name="Button" type="Button" parent="."]
|
||||
layout_mode = 2
|
||||
offset_right = 1124.0
|
||||
offset_bottom = 31.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 0
|
||||
text = "resource_name"
|
||||
@ -35,11 +18,7 @@ clip_text = true
|
||||
|
||||
[node name="Button2" type="MenuButton" parent="."]
|
||||
layout_mode = 2
|
||||
offset_left = 1128.0
|
||||
offset_right = 1152.0
|
||||
offset_bottom = 648.0
|
||||
size_flags_horizontal = 9
|
||||
icon = SubResource("ImageTexture_wgkau")
|
||||
item_count = 2
|
||||
popup/item_0/text = "Select All"
|
||||
popup/item_0/id = 0
|
||||
|
@ -3,18 +3,10 @@ extends HBoxContainer
|
||||
|
||||
@export @onready var node_editor_view_root : Control = $"../../../.."
|
||||
|
||||
# These can not be set externally.
|
||||
var rows_per_page := 50:
|
||||
set(v): pass
|
||||
|
||||
var current_page := 0:
|
||||
set(v): pass
|
||||
|
||||
var first_row := 0:
|
||||
set(v): pass
|
||||
|
||||
var last_row := 50:
|
||||
set(v): pass
|
||||
var rows_per_page := 50
|
||||
var current_page := 0
|
||||
var first_row := 0
|
||||
var last_row := 50
|
||||
|
||||
|
||||
func _on_grid_updated():
|
||||
@ -85,7 +77,7 @@ func _fill_buttons_with_prefixes(btns, strings, page_count):
|
||||
continue
|
||||
|
||||
for j in strings[i].length():
|
||||
if strings[i].ord_at(j) != strings[i - 1].ord_at(j):
|
||||
if strings[i].unicode_at(j) != strings[i - 1].unicode_at(j):
|
||||
btns[i].text = strings[i].left(j + 1)
|
||||
btns[i - 1].text = strings[i - 1].left(max(j + 1, btns[i - 1].text.length()))
|
||||
break
|
||||
|
@ -89,7 +89,7 @@ static func multi_move_right(values : Array, cursor_positions : Array, ctrl_pres
|
||||
|
||||
|
||||
static func multi_paste(values : Array, cursor_positions : Array):
|
||||
var pasted_lines := DisplayServer.clipboard_get().split("\n")
|
||||
var pasted_lines := DisplayServer.clipboard_get().replace("\r", "").split("\n")
|
||||
var paste_each_line := pasted_lines.size() == values.size()
|
||||
|
||||
for i in values.size():
|
||||
@ -140,25 +140,3 @@ static func _step_cursor(text : String, start : int, step : int = 1, ctrl_presse
|
||||
return start
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
static func string_snake_to_naming_case(string : String, add_spaces : bool = true) -> String:
|
||||
if string == "": return ""
|
||||
|
||||
var split = string.split("_")
|
||||
for i in split.size():
|
||||
split[i] = split[i][0].to_upper() + split[i].substr(1).to_lower()
|
||||
|
||||
return (" " if add_spaces else "").join(split)
|
||||
|
||||
|
||||
static func pascal_case_to_snake_case(string : String) -> String:
|
||||
var i = 0
|
||||
while i < string.length():
|
||||
if string.unicode_at(i) < 97:
|
||||
string = string.left(i) + ("_" if i > 0 else "") + string[i].to_lower() + string.substr(i + 1)
|
||||
i += 1
|
||||
|
||||
i += 1
|
||||
|
||||
return string
|
||||
|
@ -31,7 +31,7 @@ func _on_Button_pressed():
|
||||
tile.region = Rect2(tile_size * Vector2(i, j), tile_size)
|
||||
tile.atlas = _stored_value
|
||||
tile_array.append(tile)
|
||||
tile.take_over_path(folder_name + "/" + folder_name.get_file() + "_" + str(j * v_count + i + 1) + ".tres")
|
||||
tile.take_over_path(folder_name + "/" + folder_name.get_file() + "_" + str(j * h_count + i + 1) + ".tres")
|
||||
ResourceSaver.save(tile)
|
||||
|
||||
tile_array.resize(sheet.edited_cells.size())
|
||||
|
@ -8,57 +8,6 @@
|
||||
|
||||
config_version=5
|
||||
|
||||
_global_script_classes=[{
|
||||
"base": "RefCounted",
|
||||
"class": &"CellEditor",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/resources_spreadsheet_view/typed_cells/cell_editor.gd"
|
||||
}, {
|
||||
"base": "CellEditor",
|
||||
"class": &"CellEditorArray",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/resources_spreadsheet_view/typed_cells/cell_editor_array.gd"
|
||||
}, {
|
||||
"base": "GridContainer",
|
||||
"class": &"SettingsGrid",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/resources_spreadsheet_view/settings_grid.gd"
|
||||
}, {
|
||||
"base": "Control",
|
||||
"class": &"SheetsDockEditor",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/resources_spreadsheet_view/typed_editors/dock_base.gd"
|
||||
}, {
|
||||
"base": "RefCounted",
|
||||
"class": &"TextEditingUtils",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/resources_spreadsheet_view/text_editing_utils.gd"
|
||||
}, {
|
||||
"base": "Control",
|
||||
"class": &"ThemeColorSetter",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/resources_spreadsheet_view/editor_color_setter.gd"
|
||||
}, {
|
||||
"base": "Button",
|
||||
"class": &"ThemeIconButton",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/resources_spreadsheet_view/editor_icon_button.gd"
|
||||
}, {
|
||||
"base": "Control",
|
||||
"class": &"ThemeStylebox",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/resources_spreadsheet_view/editor_stylebox_overrider.gd"
|
||||
}]
|
||||
_global_script_class_icons={
|
||||
"CellEditor": "",
|
||||
"CellEditorArray": "",
|
||||
"SettingsGrid": "",
|
||||
"SheetsDockEditor": "",
|
||||
"TextEditingUtils": "",
|
||||
"ThemeColorSetter": "",
|
||||
"ThemeIconButton": "",
|
||||
"ThemeStylebox": ""
|
||||
}
|
||||
color_rows=false
|
||||
color_arrays=true
|
||||
|
||||
@ -76,6 +25,10 @@ resources_spreadsheet_view/resource_preview_size=32.0
|
||||
config/name="Addon: Resources as Sheets"
|
||||
config/features=PackedStringArray("4.0")
|
||||
|
||||
[editor]
|
||||
|
||||
export/convert_text_resources_to_binary=true
|
||||
|
||||
[editor_plugins]
|
||||
|
||||
enabled=PackedStringArray("res://addons/resources_spreadsheet_view/plugin.cfg")
|
||||
|
Loading…
Reference in New Issue
Block a user