mirror of
https://github.com/Relintai/godot-resources-as-sheets-plugin.git
synced 2024-11-18 20:27:20 +01:00
Initial Commit (i will never start initializing as soon as i begin the project)
This commit is contained in:
commit
53fdb3e72c
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
* text=auto eol=lf
|
18
.gitignore
vendored
Normal file
18
.gitignore
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Godot 4+ specific ignores
|
||||||
|
.godot/
|
||||||
|
|
||||||
|
# Godot-specific ignores
|
||||||
|
.import/
|
||||||
|
export.cfg
|
||||||
|
export_presets.cfg
|
||||||
|
|
||||||
|
# Imported translations (automatically generated from CSV files)
|
||||||
|
*.translation
|
||||||
|
|
||||||
|
# Mono-specific ignores
|
||||||
|
.mono/
|
||||||
|
data_*/
|
||||||
|
mono_crash.*.json
|
||||||
|
|
||||||
|
# Editor Plugin persistent data
|
||||||
|
addons/resources_speadsheet_view/saved_state.json
|
33
README.md
Normal file
33
README.md
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# Edit Resources as Spreadsheet
|
||||||
|
|
||||||
|
"Welp, it is what it sounds like!"
|
||||||
|
|
||||||
|
A plugin for Godot 3 that adds a tab for editing folders of Resources as data tables. It was made from neccessity when trying to develop another plugin.
|
||||||
|
|
||||||
|
- Multi-cell text editing (visible cursor not included, unfortunately)
|
||||||
|
- Copy-paste Text into Cells (one line, one cell)
|
||||||
|
- Sort entries by column
|
||||||
|
- Search by evaluating GDScript expression
|
||||||
|
- Saves recently opened folders between sessions.
|
||||||
|
|
||||||
|
Possible inputs:
|
||||||
|
- `Ctrl + Click / Cmd + Click` - Select multiple cells in one column
|
||||||
|
- `Shift + Click` - Select all cells between A and B in one column
|
||||||
|
- `Left/Right` - Move cursor along cell text
|
||||||
|
- `Backspace/Delete` - Erase text Left / Right from cursor
|
||||||
|
- `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 + (Shift) + Z` - The Savior
|
||||||
|
|
||||||
|
If clipboard contains as many lines as there are cells selected, each line is pasted into a separate cell.
|
||||||
|
|
||||||
|
Support of more data types coming eventually.
|
||||||
|
|
||||||
|
#
|
||||||
|
|
||||||
|
Made by Don Tnowe in 2022.
|
||||||
|
|
||||||
|
[https://redbladegames.netlify.app]()
|
||||||
|
|
||||||
|
[https://twitter.com/don_tnowe]()
|
14
addons/resources_speadsheet_view/editor_icon_button.gd
Normal file
14
addons/resources_speadsheet_view/editor_icon_button.gd
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
tool
|
||||||
|
class_name ThemeIconButton
|
||||||
|
extends Button
|
||||||
|
|
||||||
|
export var icon_name := "Node" setget _set_icon_name
|
||||||
|
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
_set_icon_name(icon_name)
|
||||||
|
|
||||||
|
|
||||||
|
func _set_icon_name(v):
|
||||||
|
icon_name = v
|
||||||
|
icon = get_icon(v, "EditorIcons")
|
@ -0,0 +1,21 @@
|
|||||||
|
tool
|
||||||
|
class_name ThemeStylebox
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
export var box_class := "EditorStyles" setget _set_box_class
|
||||||
|
export var box_name := "Background" setget _set_box_name
|
||||||
|
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
_set_box_name(box_class)
|
||||||
|
_set_box_class(box_name)
|
||||||
|
|
||||||
|
|
||||||
|
func _set_box_name(v):
|
||||||
|
box_name = v
|
||||||
|
add_stylebox_override(box_name, get_stylebox(box_name, box_class))
|
||||||
|
|
||||||
|
|
||||||
|
func _set_box_class(v):
|
||||||
|
box_class = v
|
||||||
|
add_stylebox_override(box_name, get_stylebox(box_name, box_class))
|
481
addons/resources_speadsheet_view/editor_view.gd
Normal file
481
addons/resources_speadsheet_view/editor_view.gd
Normal file
@ -0,0 +1,481 @@
|
|||||||
|
tool
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
export var grid_cell_scene : PackedScene
|
||||||
|
export var table_header_scene : PackedScene
|
||||||
|
|
||||||
|
export var path_folder_path := NodePath("")
|
||||||
|
export var path_recent_paths := NodePath("")
|
||||||
|
export var path_table_root := NodePath("")
|
||||||
|
export var editor_stylebox : StyleBox
|
||||||
|
|
||||||
|
var editor_interface : EditorInterface
|
||||||
|
var editor_plugin : EditorPlugin
|
||||||
|
|
||||||
|
var current_path := ""
|
||||||
|
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 columns := []
|
||||||
|
var column_types := []
|
||||||
|
var column_hints := []
|
||||||
|
var rows := []
|
||||||
|
var remembered_paths := {}
|
||||||
|
|
||||||
|
var edited_cells := []
|
||||||
|
var edit_cursor_positions := []
|
||||||
|
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
get_node(path_recent_paths).clear()
|
||||||
|
editor_interface.get_resource_filesystem()\
|
||||||
|
.connect("filesystem_changed", self, "_on_filesystem_changed")
|
||||||
|
|
||||||
|
var file := File.new()
|
||||||
|
if file.file_exists(save_data_path):
|
||||||
|
file.open(save_data_path, File.READ)
|
||||||
|
|
||||||
|
var as_text = file.get_as_text()
|
||||||
|
var as_var = str2var(as_text)
|
||||||
|
for x in as_var["recent_paths"]:
|
||||||
|
add_path_to_recent(x, true)
|
||||||
|
|
||||||
|
display_folder(recent_paths[0])
|
||||||
|
|
||||||
|
|
||||||
|
func _on_filesystem_changed():
|
||||||
|
var path = editor_interface.get_resource_filesystem().get_filesystem_path(current_path)
|
||||||
|
if !path: return
|
||||||
|
if path.get_file_count() != rows.size():
|
||||||
|
display_folder(current_path, sorting_by, sorting_reverse)
|
||||||
|
|
||||||
|
else:
|
||||||
|
for k in remembered_paths:
|
||||||
|
if remembered_paths[k].resource_path != k:
|
||||||
|
display_folder(current_path, sorting_by, sorting_reverse)
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
func display_folder(folderpath : String, sort_by : String = "", sort_reverse : bool = false):
|
||||||
|
if folderpath == "": return # Root folder resources tend to have MANY properties.
|
||||||
|
if !folderpath.ends_with("/"):
|
||||||
|
folderpath += "/"
|
||||||
|
|
||||||
|
var dir := Directory.new()
|
||||||
|
dir.open(folderpath)
|
||||||
|
dir.list_dir_begin()
|
||||||
|
|
||||||
|
rows.clear()
|
||||||
|
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):
|
||||||
|
columns.clear()
|
||||||
|
column_types.clear()
|
||||||
|
column_hints.clear()
|
||||||
|
for x in res.get_property_list():
|
||||||
|
if x["usage"] & PROPERTY_USAGE_EDITOR != 0 and x["name"] != "script":
|
||||||
|
columns.append(x["name"])
|
||||||
|
column_types.append(x["type"])
|
||||||
|
column_hints.append(x["hint"])
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
if columns.size() == 0: return
|
||||||
|
|
||||||
|
get_node(path_folder_path).text = folderpath
|
||||||
|
_create_table(get_node(path_table_root), current_path != folderpath)
|
||||||
|
current_path = folderpath
|
||||||
|
|
||||||
|
|
||||||
|
func _insert_row_sorted(res : Resource, rows : Array, sort_by : String, sort_reverse : bool):
|
||||||
|
for i in rows.size():
|
||||||
|
if sort_reverse != (res.get(sort_by) < rows[i].get(sort_by)):
|
||||||
|
rows.insert(i, res)
|
||||||
|
return
|
||||||
|
|
||||||
|
rows.append(res)
|
||||||
|
|
||||||
|
|
||||||
|
func _set_sorting(sort_by):
|
||||||
|
var sort_reverse : bool = !(sorting_by != sort_by or sorting_reverse)
|
||||||
|
sorting_reverse = sort_reverse
|
||||||
|
display_folder(current_path, sort_by, sort_reverse)
|
||||||
|
sorting_by = sort_by
|
||||||
|
|
||||||
|
|
||||||
|
func _create_table(root_node : Control, columns_changed : bool):
|
||||||
|
edited_cells = []
|
||||||
|
edit_cursor_positions = []
|
||||||
|
var new_node : Control
|
||||||
|
if columns_changed:
|
||||||
|
root_node.columns = columns.size()
|
||||||
|
for x in root_node.get_children():
|
||||||
|
x.queue_free()
|
||||||
|
|
||||||
|
for x in columns:
|
||||||
|
new_node = table_header_scene.instance()
|
||||||
|
root_node.add_child(new_node)
|
||||||
|
new_node.get_node("Button").text = x
|
||||||
|
new_node.get_node("Button").connect("pressed", self, "_set_sorting", [x])
|
||||||
|
|
||||||
|
var to_free = root_node.get_child_count() - (rows.size() + 1) * columns.size()
|
||||||
|
while to_free > 0:
|
||||||
|
root_node.get_child(columns.size()).free()
|
||||||
|
to_free -= 1
|
||||||
|
|
||||||
|
for i in rows.size():
|
||||||
|
for j in columns.size():
|
||||||
|
if root_node.get_child_count() <= (i + 1) * columns.size() + j:
|
||||||
|
new_node = grid_cell_scene.instance()
|
||||||
|
new_node.connect("gui_input", self, "_on_cell_gui_input", [new_node])
|
||||||
|
root_node.add_child(new_node)
|
||||||
|
|
||||||
|
else:
|
||||||
|
new_node = root_node.get_child((i + 1) * columns.size() + j)
|
||||||
|
new_node.hint_tooltip = columns[j] + "\nOf " + rows[i].resource_path.get_file()
|
||||||
|
|
||||||
|
new_node.text = TextEditingUtils.show_non_typing(str(rows[i].get(columns[j])))
|
||||||
|
if columns[j] == "resource_path":
|
||||||
|
new_node.text = new_node.text.get_file()
|
||||||
|
|
||||||
|
|
||||||
|
func add_path_to_recent(path : String, is_loading : bool = false):
|
||||||
|
if path in recent_paths: return
|
||||||
|
|
||||||
|
var node_recent := get_node(path_recent_paths)
|
||||||
|
var idx_in_array := recent_paths.find(path)
|
||||||
|
if idx_in_array != -1:
|
||||||
|
node_recent.remove_item(idx_in_array)
|
||||||
|
recent_paths.remove(idx_in_array)
|
||||||
|
|
||||||
|
recent_paths.insert(0, path)
|
||||||
|
node_recent.add_item(path, 0)
|
||||||
|
node_recent.select(node_recent.get_item_count() - 1)
|
||||||
|
|
||||||
|
if !is_loading:
|
||||||
|
save_data()
|
||||||
|
|
||||||
|
|
||||||
|
func remove_selected_path_from_recent():
|
||||||
|
if get_node(path_recent_paths).get_item_count() == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
var idx_in_array = get_node(path_recent_paths).selected
|
||||||
|
recent_paths.remove(idx_in_array)
|
||||||
|
get_node(path_recent_paths).remove_item(idx_in_array)
|
||||||
|
|
||||||
|
if get_node(path_recent_paths).get_item_count() != 0:
|
||||||
|
get_node(path_recent_paths).select(0)
|
||||||
|
display_folder(recent_paths[0])
|
||||||
|
save_data()
|
||||||
|
|
||||||
|
|
||||||
|
func save_data():
|
||||||
|
var file = File.new()
|
||||||
|
file.open(save_data_path, File.WRITE)
|
||||||
|
file.store_string(var2str(
|
||||||
|
{
|
||||||
|
"recent_paths" : recent_paths,
|
||||||
|
}
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
func _on_Path_text_entered(new_text : String):
|
||||||
|
current_path = new_text
|
||||||
|
|
||||||
|
add_path_to_recent(new_text)
|
||||||
|
display_folder(new_text)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_RecentPaths_item_selected(index : int):
|
||||||
|
current_path = recent_paths[index]
|
||||||
|
get_node(path_folder_path).text = recent_paths[index]
|
||||||
|
display_folder(current_path)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_FileDialog_dir_selected(dir : String):
|
||||||
|
get_node(path_folder_path).text = dir
|
||||||
|
add_path_to_recent(dir)
|
||||||
|
display_folder(dir)
|
||||||
|
|
||||||
|
|
||||||
|
func deselect_all_cells():
|
||||||
|
for x in edited_cells:
|
||||||
|
x.get_node("Selected").visible = false
|
||||||
|
|
||||||
|
edited_cells = []
|
||||||
|
edit_cursor_positions = []
|
||||||
|
|
||||||
|
|
||||||
|
func deselect_cell(cell : Control):
|
||||||
|
var idx := edited_cells.find(cell)
|
||||||
|
if idx == -1: return
|
||||||
|
|
||||||
|
cell.get_node("Selected").visible = false
|
||||||
|
edited_cells.remove(idx)
|
||||||
|
edit_cursor_positions.remove(idx)
|
||||||
|
|
||||||
|
|
||||||
|
func select_cell(cell : Control):
|
||||||
|
if _can_select_cell(cell):
|
||||||
|
cell.get_node("Selected").visible = true
|
||||||
|
edited_cells.append(cell)
|
||||||
|
edit_cursor_positions.append(cell.text.length())
|
||||||
|
return
|
||||||
|
|
||||||
|
var column_index := _get_cell_column(cell)
|
||||||
|
if column_index != _get_cell_column(edited_cells[edited_cells.size() - 1]):
|
||||||
|
return
|
||||||
|
|
||||||
|
var row_start = _get_cell_row(edited_cells[edited_cells.size() - 1])
|
||||||
|
var row_end := _get_cell_row(cell)
|
||||||
|
var table_root := get_node(path_table_root)
|
||||||
|
|
||||||
|
for i in range(row_end, row_start, 1 if row_start > row_end else -1):
|
||||||
|
var cur_cell := table_root.get_child(i * columns.size() + column_index)
|
||||||
|
cur_cell.get_node("Selected").visible = true
|
||||||
|
edited_cells.append(cur_cell)
|
||||||
|
edit_cursor_positions.append(cur_cell.text.length())
|
||||||
|
|
||||||
|
|
||||||
|
func _can_select_cell(cell : Control) -> bool:
|
||||||
|
if edited_cells.size() == 0:
|
||||||
|
return true
|
||||||
|
|
||||||
|
if !Input.is_key_pressed(KEY_CONTROL):
|
||||||
|
return false
|
||||||
|
|
||||||
|
if (
|
||||||
|
_get_cell_column(cell)
|
||||||
|
!= _get_cell_column(edited_cells[0])
|
||||||
|
):
|
||||||
|
return false
|
||||||
|
|
||||||
|
return !cell in edited_cells
|
||||||
|
|
||||||
|
|
||||||
|
func _get_cell_column(cell) -> int:
|
||||||
|
return cell.get_position_in_parent() % columns.size()
|
||||||
|
|
||||||
|
|
||||||
|
func _get_cell_row(cell) -> int:
|
||||||
|
return cell.get_position_in_parent() / columns.size()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_cell_gui_input(event : InputEvent, cell : Control):
|
||||||
|
if event is InputEventMouseButton:
|
||||||
|
grab_focus()
|
||||||
|
if event.pressed:
|
||||||
|
if cell in edited_cells:
|
||||||
|
if !Input.is_key_pressed(KEY_CONTROL):
|
||||||
|
deselect_cell(cell)
|
||||||
|
|
||||||
|
else:
|
||||||
|
deselect_all_cells()
|
||||||
|
select_cell(cell)
|
||||||
|
|
||||||
|
else:
|
||||||
|
if !(Input.is_key_pressed(KEY_SHIFT) or Input.is_key_pressed(KEY_CONTROL)):
|
||||||
|
deselect_all_cells()
|
||||||
|
|
||||||
|
select_cell(cell)
|
||||||
|
|
||||||
|
if event is InputEventMouseMotion:
|
||||||
|
if Input.is_mouse_button_pressed(BUTTON_LEFT):
|
||||||
|
select_cell(cell)
|
||||||
|
|
||||||
|
|
||||||
|
func _gui_input(event : InputEvent):
|
||||||
|
if event is InputEventMouseButton:
|
||||||
|
grab_focus()
|
||||||
|
if !event.pressed:
|
||||||
|
deselect_all_cells()
|
||||||
|
|
||||||
|
|
||||||
|
func _input(event : InputEvent):
|
||||||
|
if !event is InputEventKey or !event.pressed:
|
||||||
|
return
|
||||||
|
|
||||||
|
if !visible or edited_cells.size() == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
if column_types[_get_cell_column(edited_cells[0])] == TYPE_OBJECT:
|
||||||
|
return
|
||||||
|
|
||||||
|
if event.scancode == KEY_CONTROL || event.scancode == KEY_SHIFT:
|
||||||
|
# Modifier keys do not get processed.
|
||||||
|
return
|
||||||
|
|
||||||
|
var edited_cells_resources = _get_edited_cells_resources()
|
||||||
|
|
||||||
|
# Ctrl + Z (before, and instead of, committing the action!)
|
||||||
|
if Input.is_key_pressed(KEY_CONTROL) and event.scancode == KEY_Z:
|
||||||
|
if Input.is_key_pressed(KEY_SHIFT):
|
||||||
|
editor_plugin.undo_redo.redo()
|
||||||
|
# Ctrl + z
|
||||||
|
else:
|
||||||
|
editor_plugin.undo_redo.undo()
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
editor_plugin.undo_redo.create_action("Set Cell Value")
|
||||||
|
editor_plugin.undo_redo.add_undo_method(
|
||||||
|
self,
|
||||||
|
"_update_resources",
|
||||||
|
edited_cells_resources.duplicate(),
|
||||||
|
edited_cells.duplicate(),
|
||||||
|
columns[_get_cell_column(edited_cells[0])],
|
||||||
|
_get_edited_cells_values()
|
||||||
|
)
|
||||||
|
|
||||||
|
_key_specific_action(event)
|
||||||
|
grab_focus()
|
||||||
|
|
||||||
|
editor_plugin.undo_redo.add_do_method(
|
||||||
|
self,
|
||||||
|
"_update_resources",
|
||||||
|
edited_cells_resources.duplicate(),
|
||||||
|
edited_cells.duplicate(),
|
||||||
|
columns[_get_cell_column(edited_cells[0])],
|
||||||
|
_get_edited_cells_values()
|
||||||
|
)
|
||||||
|
editor_plugin.undo_redo.commit_action()
|
||||||
|
editor_interface.get_resource_filesystem().scan()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func _key_specific_action(event : InputEvent):
|
||||||
|
var ctrl_pressed := Input.is_key_pressed(KEY_CONTROL)
|
||||||
|
if ctrl_pressed:
|
||||||
|
editor_plugin.hide_bottom_panel()
|
||||||
|
|
||||||
|
# ERASING
|
||||||
|
if event.scancode == KEY_BACKSPACE:
|
||||||
|
TextEditingUtils.multi_erase_left(edited_cells, edit_cursor_positions, self)
|
||||||
|
|
||||||
|
if event.scancode == KEY_DELETE:
|
||||||
|
TextEditingUtils.multi_erase_right(edited_cells, edit_cursor_positions, self)
|
||||||
|
get_tree().set_input_as_handled() # Because this is one dangerous action.
|
||||||
|
|
||||||
|
# CURSOR MOVEMENT
|
||||||
|
elif event.scancode == KEY_LEFT:
|
||||||
|
TextEditingUtils.multi_move_left(edited_cells, edit_cursor_positions)
|
||||||
|
|
||||||
|
elif event.scancode == KEY_RIGHT:
|
||||||
|
TextEditingUtils.multi_move_right(edited_cells, edit_cursor_positions)
|
||||||
|
|
||||||
|
elif event.scancode == KEY_HOME:
|
||||||
|
for i in edit_cursor_positions.size():
|
||||||
|
edit_cursor_positions[i] = 0
|
||||||
|
|
||||||
|
elif event.scancode == KEY_END:
|
||||||
|
for i in edit_cursor_positions.size():
|
||||||
|
edit_cursor_positions[i] = edited_cells[i].text.length()
|
||||||
|
|
||||||
|
# BETWEEN-CELL NAVIGATION
|
||||||
|
elif event.scancode == KEY_UP:
|
||||||
|
_move_selection_on_grid(0, (-1 if !ctrl_pressed else -10))
|
||||||
|
|
||||||
|
elif event.scancode == KEY_DOWN:
|
||||||
|
_move_selection_on_grid(0, (1 if !ctrl_pressed else 10))
|
||||||
|
|
||||||
|
elif Input.is_key_pressed(KEY_SHIFT) and event.scancode == KEY_TAB:
|
||||||
|
_move_selection_on_grid((-1 if !ctrl_pressed else -10), 0)
|
||||||
|
get_tree().set_input_as_handled()
|
||||||
|
|
||||||
|
elif event.scancode == KEY_TAB:
|
||||||
|
_move_selection_on_grid((1 if !ctrl_pressed else 10), 0)
|
||||||
|
get_tree().set_input_as_handled()
|
||||||
|
|
||||||
|
# Ctrl + C (so you can edit in a proper text editor instead of this wacky nonsense)
|
||||||
|
elif ctrl_pressed and event.scancode == KEY_C:
|
||||||
|
TextEditingUtils.multi_copy(edited_cells)
|
||||||
|
|
||||||
|
# Ctrl + V
|
||||||
|
elif ctrl_pressed and event.scancode == KEY_V:
|
||||||
|
TextEditingUtils.multi_paste(edited_cells, edit_cursor_positions, self)
|
||||||
|
|
||||||
|
# Line Skip
|
||||||
|
elif event.scancode == KEY_ENTER:
|
||||||
|
TextEditingUtils.multi_linefeed(edited_cells, edit_cursor_positions, self)
|
||||||
|
|
||||||
|
# And finally, text typing.
|
||||||
|
elif event.unicode != 0 and event.unicode != 127:
|
||||||
|
TextEditingUtils.multi_input(char(event.unicode), edited_cells, edit_cursor_positions, self)
|
||||||
|
|
||||||
|
|
||||||
|
func _move_selection_on_grid(move_h : int, move_v : int):
|
||||||
|
select_cell(
|
||||||
|
get_node(path_table_root).get_child(
|
||||||
|
edited_cells[0].get_position_in_parent()
|
||||||
|
+ move_h + move_v * columns.size()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
deselect_cell(edited_cells[0])
|
||||||
|
|
||||||
|
|
||||||
|
func set_cell(cell, value):
|
||||||
|
if columns[_get_cell_column(cell)] == "resource_path":
|
||||||
|
return
|
||||||
|
|
||||||
|
cell.text = value
|
||||||
|
|
||||||
|
|
||||||
|
func _update_resources(update_rows : Array, update_cells : Array, update_column : String, values : Array):
|
||||||
|
var cells := get_node(path_table_root).get_children()
|
||||||
|
for i in update_rows.size():
|
||||||
|
update_rows[i].set(update_column, values[i])
|
||||||
|
update_cells[i].text = TextEditingUtils.show_non_typing(str(values[i]))
|
||||||
|
ResourceSaver.save(update_rows[i].resource_path, update_rows[i])
|
||||||
|
|
||||||
|
|
||||||
|
func _get_edited_cells_resources() -> Array:
|
||||||
|
var arr := edited_cells.duplicate()
|
||||||
|
for i in arr.size():
|
||||||
|
arr[i] = rows[_get_cell_row(edited_cells[i]) - 1]
|
||||||
|
|
||||||
|
return arr
|
||||||
|
|
||||||
|
|
||||||
|
func _get_edited_cells_values() -> Array:
|
||||||
|
var arr := edited_cells.duplicate()
|
||||||
|
for i in arr.size():
|
||||||
|
arr[i] = str2var(TextEditingUtils.revert_non_typing(edited_cells[i].text))
|
||||||
|
|
||||||
|
return arr
|
||||||
|
|
||||||
|
|
||||||
|
func _on_SearchCond_text_entered(new_text : String):
|
||||||
|
var new_script := GDScript.new()
|
||||||
|
new_script.source_code = "static func can_show(res, index):\n\treturn " + new_text
|
||||||
|
new_script.reload()
|
||||||
|
|
||||||
|
var new_script_instance = new_script.new()
|
||||||
|
var table_elements = get_node(path_table_root).get_children()
|
||||||
|
|
||||||
|
for i in rows.size():
|
||||||
|
var row_visible = new_script_instance.can_show(rows[i], i)
|
||||||
|
for j in columns.size():
|
||||||
|
table_elements[(i + 1) * columns.size() + j].visible = row_visible
|
||||||
|
|
||||||
|
|
||||||
|
func _on_focus_exited():
|
||||||
|
deselect_all_cells()
|
383
addons/resources_speadsheet_view/editor_view.tscn
Normal file
383
addons/resources_speadsheet_view/editor_view.tscn
Normal file
@ -0,0 +1,383 @@
|
|||||||
|
[gd_scene load_steps=11 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://addons/resources_speadsheet_view/editor_view.gd" type="Script" id=1]
|
||||||
|
[ext_resource path="res://addons/resources_speadsheet_view/typed_cells/basic.tscn" type="PackedScene" id=3]
|
||||||
|
[ext_resource path="res://addons/resources_speadsheet_view/editor_icon_button.gd" type="Script" id=4]
|
||||||
|
[ext_resource path="res://addons/resources_speadsheet_view/table_header.tscn" type="PackedScene" id=6]
|
||||||
|
|
||||||
|
[sub_resource type="Image" id=15]
|
||||||
|
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( 15 )
|
||||||
|
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
|
||||||
|
|
||||||
|
[sub_resource type="Image" id=16]
|
||||||
|
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=14]
|
||||||
|
flags = 4
|
||||||
|
flags = 4
|
||||||
|
image = SubResource( 16 )
|
||||||
|
size = Vector2( 16, 16 )
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id=11]
|
||||||
|
content_margin_left = 3.0
|
||||||
|
content_margin_right = 3.0
|
||||||
|
content_margin_top = 3.0
|
||||||
|
content_margin_bottom = 3.0
|
||||||
|
bg_color = Color( 0.147059, 0.154412, 0.159314, 1 )
|
||||||
|
|
||||||
|
[node name="Control" type="MarginContainer"]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
focus_neighbour_left = NodePath(".")
|
||||||
|
focus_neighbour_top = NodePath(".")
|
||||||
|
focus_neighbour_right = NodePath(".")
|
||||||
|
focus_neighbour_bottom = NodePath(".")
|
||||||
|
focus_next = NodePath(".")
|
||||||
|
focus_previous = NodePath(".")
|
||||||
|
focus_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
||||||
|
custom_constants/margin_right = 2
|
||||||
|
custom_constants/margin_top = 2
|
||||||
|
custom_constants/margin_left = 2
|
||||||
|
custom_constants/margin_bottom = 2
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_lock_": true
|
||||||
|
}
|
||||||
|
grid_cell_scene = ExtResource( 3 )
|
||||||
|
table_header_scene = ExtResource( 6 )
|
||||||
|
path_folder_path = NodePath("HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer/Path")
|
||||||
|
path_recent_paths = NodePath("HeaderContentSplit/VBoxContainer/HBoxContainer/RecentPaths")
|
||||||
|
path_table_root = NodePath("HeaderContentSplit/MarginContainer/FooterContentSplit/Panel/Scroll/MarginContainer/TableGrid")
|
||||||
|
editor_stylebox = SubResource( 5 )
|
||||||
|
|
||||||
|
[node name="HeaderContentSplit" type="VBoxContainer" parent="."]
|
||||||
|
margin_left = 2.0
|
||||||
|
margin_top = 2.0
|
||||||
|
margin_right = 1022.0
|
||||||
|
margin_bottom = 598.0
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_lock_": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="HeaderContentSplit"]
|
||||||
|
margin_right = 1020.0
|
||||||
|
margin_bottom = 42.0
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_lock_": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="HeaderContentSplit/VBoxContainer"]
|
||||||
|
margin_right = 1020.0
|
||||||
|
margin_bottom = 14.0
|
||||||
|
text = "Select Resource Folder:"
|
||||||
|
|
||||||
|
[node name="HBoxContainer" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer"]
|
||||||
|
margin_top = 18.0
|
||||||
|
margin_right = 1020.0
|
||||||
|
margin_bottom = 42.0
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_lock_": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="HeaderContentSplit/VBoxContainer/HBoxContainer"]
|
||||||
|
margin_top = 5.0
|
||||||
|
margin_right = 107.0
|
||||||
|
margin_bottom = 19.0
|
||||||
|
text = "Resource Folder:"
|
||||||
|
|
||||||
|
[node name="HBoxContainer" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer/HBoxContainer"]
|
||||||
|
margin_left = 111.0
|
||||||
|
margin_right = 475.0
|
||||||
|
margin_bottom = 24.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
custom_constants/separation = 0
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_lock_": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="Path" type="LineEdit" parent="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
margin_right = 336.0
|
||||||
|
margin_bottom = 24.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
text = "res://assets/custom/upgrades/"
|
||||||
|
caret_blink = true
|
||||||
|
caret_blink_speed = 0.5
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_lock_": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="SelectDir" type="Button" parent="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer"]
|
||||||
|
margin_left = 336.0
|
||||||
|
margin_right = 364.0
|
||||||
|
margin_bottom = 24.0
|
||||||
|
hint_tooltip = "Open Folder"
|
||||||
|
icon = SubResource( 14 )
|
||||||
|
script = ExtResource( 4 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_lock_": true
|
||||||
|
}
|
||||||
|
icon_name = "Folder"
|
||||||
|
|
||||||
|
[node name="Label2" type="Label" parent="HeaderContentSplit/VBoxContainer/HBoxContainer"]
|
||||||
|
margin_left = 479.0
|
||||||
|
margin_top = 5.0
|
||||||
|
margin_right = 566.0
|
||||||
|
margin_bottom = 19.0
|
||||||
|
text = "Open Recent:"
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_lock_": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="RecentPaths" type="OptionButton" parent="HeaderContentSplit/VBoxContainer/HBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
margin_left = 570.0
|
||||||
|
margin_right = 934.0
|
||||||
|
margin_bottom = 24.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_lock_": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="DeletePath" type="Button" parent="HeaderContentSplit/VBoxContainer/HBoxContainer"]
|
||||||
|
margin_left = 938.0
|
||||||
|
margin_right = 966.0
|
||||||
|
margin_bottom = 24.0
|
||||||
|
hint_tooltip = "Delete Selected Path"
|
||||||
|
icon = SubResource( 14 )
|
||||||
|
script = ExtResource( 4 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_lock_": true
|
||||||
|
}
|
||||||
|
icon_name = "Remove"
|
||||||
|
|
||||||
|
[node name="Info" type="Button" parent="HeaderContentSplit/VBoxContainer/HBoxContainer"]
|
||||||
|
margin_left = 970.0
|
||||||
|
margin_right = 1020.0
|
||||||
|
margin_bottom = 24.0
|
||||||
|
text = "About"
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_lock_": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="MarginContainer" type="MarginContainer" parent="HeaderContentSplit"]
|
||||||
|
margin_top = 46.0
|
||||||
|
margin_right = 1020.0
|
||||||
|
margin_bottom = 596.0
|
||||||
|
mouse_filter = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_lock_": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="FooterContentSplit" type="VBoxContainer" parent="HeaderContentSplit/MarginContainer"]
|
||||||
|
margin_right = 1020.0
|
||||||
|
margin_bottom = 550.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_lock_": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="Panel" type="PanelContainer" parent="HeaderContentSplit/MarginContainer/FooterContentSplit"]
|
||||||
|
margin_right = 1020.0
|
||||||
|
margin_bottom = 522.0
|
||||||
|
mouse_filter = 2
|
||||||
|
size_flags_vertical = 3
|
||||||
|
custom_styles/panel = SubResource( 11 )
|
||||||
|
|
||||||
|
[node name="Scroll" type="ScrollContainer" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Panel"]
|
||||||
|
margin_left = 3.0
|
||||||
|
margin_top = 3.0
|
||||||
|
margin_right = 1017.0
|
||||||
|
margin_bottom = 519.0
|
||||||
|
mouse_filter = 1
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_lock_": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="MarginContainer" type="MarginContainer" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Panel/Scroll"]
|
||||||
|
margin_right = 5.65
|
||||||
|
custom_constants/margin_right = 0
|
||||||
|
custom_constants/margin_top = 0
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_lock_": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="TableGrid" type="GridContainer" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Panel/Scroll/MarginContainer"]
|
||||||
|
margin_right = 5.65
|
||||||
|
rect_min_size = Vector2( 5.65, 0 )
|
||||||
|
custom_constants/vseparation = 0
|
||||||
|
custom_constants/hseparation = 0
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_lock_": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="Footer" type="VBoxContainer" parent="HeaderContentSplit/MarginContainer/FooterContentSplit"]
|
||||||
|
margin_top = 526.0
|
||||||
|
margin_right = 1020.0
|
||||||
|
margin_bottom = 550.0
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_lock_": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="Search" type="HBoxContainer" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Footer"]
|
||||||
|
margin_right = 1020.0
|
||||||
|
margin_bottom = 24.0
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Footer/Search"]
|
||||||
|
margin_top = 5.0
|
||||||
|
margin_right = 190.0
|
||||||
|
margin_bottom = 19.0
|
||||||
|
text = "Search by GDScript Condition:"
|
||||||
|
|
||||||
|
[node name="Label2" type="Label" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Footer/Search"]
|
||||||
|
margin_left = 194.0
|
||||||
|
margin_top = 3.0
|
||||||
|
margin_right = 212.0
|
||||||
|
margin_bottom = 21.0
|
||||||
|
rect_min_size = Vector2( 18, 18 )
|
||||||
|
hint_tooltip = "Enter an expression. The table only show rows where the expression returns `true`.
|
||||||
|
|
||||||
|
You can use `res.<property_name>` to get a property, and `index` to get row number. Hit ENTER to run the search.
|
||||||
|
|
||||||
|
Try out these:
|
||||||
|
- (res.number_property > 0 and res.number_property < 100)
|
||||||
|
- (res.text_property != \"\")
|
||||||
|
- (\"a\" in res.text_property)
|
||||||
|
- (index < 5)"
|
||||||
|
mouse_filter = 0
|
||||||
|
mouse_default_cursor_shape = 16
|
||||||
|
text = "(?)"
|
||||||
|
align = 1
|
||||||
|
|
||||||
|
[node name="SearchCond" type="LineEdit" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Footer/Search"]
|
||||||
|
margin_left = 216.0
|
||||||
|
margin_right = 1020.0
|
||||||
|
margin_bottom = 24.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
text = "true"
|
||||||
|
|
||||||
|
[node name="Control" type="Control" parent="."]
|
||||||
|
margin_left = 2.0
|
||||||
|
margin_top = 2.0
|
||||||
|
margin_right = 1022.0
|
||||||
|
margin_bottom = 598.0
|
||||||
|
mouse_filter = 2
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_lock_": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="FileDialog" type="FileDialog" parent="Control"]
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
margin_left = -307.0
|
||||||
|
margin_top = -192.0
|
||||||
|
margin_right = 307.0
|
||||||
|
margin_bottom = 192.0
|
||||||
|
rect_min_size = Vector2( 150, 52.5 )
|
||||||
|
window_title = "Open a Folder"
|
||||||
|
mode_overrides_title = false
|
||||||
|
mode = 2
|
||||||
|
|
||||||
|
[node name="Info" type="AcceptDialog" parent="Control"]
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
margin_left = -320.0
|
||||||
|
margin_top = -152.0
|
||||||
|
margin_right = 320.0
|
||||||
|
margin_bottom = 152.0
|
||||||
|
window_title = "About"
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_group_": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="MarginContainer" type="MarginContainer" parent="Control/Info"]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
margin_left = 8.0
|
||||||
|
margin_top = 8.0
|
||||||
|
margin_right = -8.0
|
||||||
|
margin_bottom = -36.0
|
||||||
|
|
||||||
|
[node name="RichTextLabel" type="RichTextLabel" parent="Control/Info/MarginContainer"]
|
||||||
|
margin_right = 624.0
|
||||||
|
margin_bottom = 260.0
|
||||||
|
bbcode_enabled = true
|
||||||
|
bbcode_text = "[center]Edit Resources as Spreadsheet[/center]
|
||||||
|
|
||||||
|
\"Welp, it is what it sounds like!\"
|
||||||
|
|
||||||
|
Possible inputs:
|
||||||
|
- [code]Ctrl + Click / Cmd + Click[/code] - Select multiple cells in one column
|
||||||
|
- [code]Shift + Click[/code] - Select all cells between A and B in one column
|
||||||
|
- [code]Left/Right[/code] - Move cursor along cell text
|
||||||
|
- [code]Backspace/Delete[/code] - Erase text Left / Right from cursor
|
||||||
|
- [code]Home/End[/code] - Move cursor to start/end of cell
|
||||||
|
- [code]Ctrl + <move/erase> / Cmd + <move/erase>[/code] - Move through / Erase whole word
|
||||||
|
- [code]Ctrl/Cmd + C/V[/code] - Copy cells / Paste text into cells
|
||||||
|
- [code]Ctrl/Cmd + (Shift) + Z[/code] - The Savior
|
||||||
|
If clipboard contains as many lines as there are cells selected, each line is pasted into a separate cell.
|
||||||
|
|
||||||
|
Made by Don Tnowe. 2022.
|
||||||
|
[url]https://twitter.com/don_tnowe[/url]"
|
||||||
|
text = "Edit Resources as Spreadsheet
|
||||||
|
|
||||||
|
\"Welp, it is what it sounds like!\"
|
||||||
|
|
||||||
|
Possible inputs:
|
||||||
|
- Ctrl + Click / Cmd + Click - Select multiple cells in one column
|
||||||
|
- Shift + Click - Select all cells between A and B in one column
|
||||||
|
- Left/Right - Move cursor along cell text
|
||||||
|
- Backspace/Delete - Erase text Left / Right from cursor
|
||||||
|
- 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 + (Shift) + Z - The Savior
|
||||||
|
If clipboard contains as many lines as there are cells selected, each line is pasted into a separate cell.
|
||||||
|
|
||||||
|
Made by Don Tnowe. 2022.
|
||||||
|
https://twitter.com/don_tnowe"
|
||||||
|
|
||||||
|
[connection signal="focus_exited" from="." to="." method="_on_focus_exited"]
|
||||||
|
[connection signal="text_entered" from="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer/Path" to="." method="_on_Path_text_entered"]
|
||||||
|
[connection signal="pressed" from="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer/SelectDir" to="Control/FileDialog" method="popup_centered"]
|
||||||
|
[connection signal="item_selected" from="HeaderContentSplit/VBoxContainer/HBoxContainer/RecentPaths" to="." method="_on_RecentPaths_item_selected"]
|
||||||
|
[connection signal="pressed" from="HeaderContentSplit/VBoxContainer/HBoxContainer/DeletePath" to="." method="remove_selected_path_from_recent"]
|
||||||
|
[connection signal="pressed" from="HeaderContentSplit/VBoxContainer/HBoxContainer/Info" to="Control/Info" method="popup_centered"]
|
||||||
|
[connection signal="text_entered" from="HeaderContentSplit/MarginContainer/FooterContentSplit/Footer/Search/SearchCond" to="." method="_on_SearchCond_text_entered"]
|
||||||
|
[connection signal="dir_selected" from="Control/FileDialog" to="." method="_on_FileDialog_dir_selected"]
|
9
addons/resources_speadsheet_view/plugin.cfg
Normal file
9
addons/resources_speadsheet_view/plugin.cfg
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[plugin]
|
||||||
|
|
||||||
|
name="Edit Resources as Spreadsheet"
|
||||||
|
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="0.2"
|
||||||
|
script="plugin.gd"
|
39
addons/resources_speadsheet_view/plugin.gd
Normal file
39
addons/resources_speadsheet_view/plugin.gd
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
tool
|
||||||
|
extends EditorPlugin
|
||||||
|
|
||||||
|
var editor_view : Control
|
||||||
|
var undo_redo : UndoRedo
|
||||||
|
|
||||||
|
|
||||||
|
func _enter_tree() -> void:
|
||||||
|
editor_view = load(get_script().resource_path.get_base_dir() + "/editor_view.tscn").instance()
|
||||||
|
editor_view.editor_interface = get_editor_interface()
|
||||||
|
editor_view.editor_plugin = self
|
||||||
|
undo_redo = get_undo_redo()
|
||||||
|
get_editor_interface().get_editor_viewport().add_child(editor_view)
|
||||||
|
make_visible(false)
|
||||||
|
|
||||||
|
|
||||||
|
func _exit_tree() -> void:
|
||||||
|
if is_instance_valid(editor_view):
|
||||||
|
editor_view.queue_free()
|
||||||
|
|
||||||
|
|
||||||
|
func get_plugin_name():
|
||||||
|
return "Sheets"
|
||||||
|
|
||||||
|
|
||||||
|
func make_visible(visible):
|
||||||
|
if is_instance_valid(editor_view):
|
||||||
|
editor_view.visible = visible
|
||||||
|
if visible:
|
||||||
|
editor_view.display_folder(editor_view.current_path)
|
||||||
|
|
||||||
|
|
||||||
|
func has_main_screen():
|
||||||
|
return true
|
||||||
|
|
||||||
|
|
||||||
|
func get_plugin_icon():
|
||||||
|
# Until I add an actual icon, this'll do.
|
||||||
|
return get_editor_interface().get_base_control().get_icon("VisualScriptComment", "EditorIcons")
|
23
addons/resources_speadsheet_view/table_header.tscn
Normal file
23
addons/resources_speadsheet_view/table_header.tscn
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
[gd_scene format=2]
|
||||||
|
|
||||||
|
[node name="Header" type="HBoxContainer"]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
margin_right = -892.0
|
||||||
|
margin_bottom = -580.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
|
||||||
|
[node name="Button" type="Button" parent="."]
|
||||||
|
margin_right = 110.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 0
|
||||||
|
text = "resource_name"
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="."]
|
||||||
|
margin_left = 114.0
|
||||||
|
margin_top = 3.0
|
||||||
|
margin_right = 132.0
|
||||||
|
margin_bottom = 17.0
|
||||||
|
mouse_filter = 0
|
||||||
|
text = "|| "
|
157
addons/resources_speadsheet_view/text_editing_utils.gd
Normal file
157
addons/resources_speadsheet_view/text_editing_utils.gd
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
class_name TextEditingUtils
|
||||||
|
extends Reference
|
||||||
|
|
||||||
|
const non_typing_paragraph := "¶"
|
||||||
|
const non_typing_space := "●"
|
||||||
|
const whitespace_chars := [
|
||||||
|
ord(" "),
|
||||||
|
ord(","),
|
||||||
|
ord(";"),
|
||||||
|
ord("("),
|
||||||
|
ord(")"),
|
||||||
|
ord("."),
|
||||||
|
ord(non_typing_paragraph),
|
||||||
|
ord(non_typing_space),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
static func is_character_whitespace(text : String, idx : int) -> bool:
|
||||||
|
if idx <= 0: return true # Stop at the edges.
|
||||||
|
if idx >= text.length(): return true
|
||||||
|
return text.ord_at(idx) in whitespace_chars
|
||||||
|
|
||||||
|
|
||||||
|
static func show_non_typing(text : String) -> String:
|
||||||
|
text = text\
|
||||||
|
.replace(non_typing_paragraph, "\n")\
|
||||||
|
.replace(non_typing_space, " ")
|
||||||
|
|
||||||
|
if text.ends_with("\n"):
|
||||||
|
text = text.left(text.length() - 1) + non_typing_paragraph
|
||||||
|
|
||||||
|
elif text.ends_with(" "):
|
||||||
|
text = text.left(text.length() - 1) + non_typing_space
|
||||||
|
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
static func revert_non_typing(text : String) -> String:
|
||||||
|
if text.ends_with(non_typing_paragraph):
|
||||||
|
text = text.left(text.length() - 1) + "\n"
|
||||||
|
|
||||||
|
elif text.ends_with(non_typing_space):
|
||||||
|
text = text.left(text.length() - 1) + " "
|
||||||
|
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
static func multi_erase_right(edited_cells : Array, edit_cursor_positions : Array, callback_object : Object):
|
||||||
|
for i in edited_cells.size():
|
||||||
|
var cell = edited_cells[i]
|
||||||
|
var start_pos = edit_cursor_positions[i]
|
||||||
|
while true:
|
||||||
|
edit_cursor_positions[i] += 1
|
||||||
|
if !Input.is_key_pressed(KEY_CONTROL) or is_character_whitespace(cell.text, edit_cursor_positions[i]):
|
||||||
|
break
|
||||||
|
|
||||||
|
edit_cursor_positions[i] = min(
|
||||||
|
edit_cursor_positions[i],
|
||||||
|
edited_cells[i].text.length()
|
||||||
|
)
|
||||||
|
callback_object.set_cell(cell, (
|
||||||
|
cell.text.left(start_pos)
|
||||||
|
+ cell.text.substr(edit_cursor_positions[i])
|
||||||
|
))
|
||||||
|
edit_cursor_positions[i] = start_pos
|
||||||
|
|
||||||
|
|
||||||
|
static func multi_erase_left(edited_cells : Array, edit_cursor_positions : Array, callback_object : Object):
|
||||||
|
for i in edited_cells.size():
|
||||||
|
var cell = edited_cells[i]
|
||||||
|
var start_pos = edit_cursor_positions[i]
|
||||||
|
|
||||||
|
edit_cursor_positions[i] = _step_cursor(cell.text, edit_cursor_positions[i], -1)
|
||||||
|
var result_text = (
|
||||||
|
cell.text.substr(0, edit_cursor_positions[i])
|
||||||
|
+ cell.text.substr(start_pos)
|
||||||
|
)
|
||||||
|
callback_object.set_cell(cell, (
|
||||||
|
cell.text.substr(0, edit_cursor_positions[i])
|
||||||
|
+ cell.text.substr(start_pos)
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
static func multi_move_left(edited_cells : Array, edit_cursor_positions : Array):
|
||||||
|
for i in edit_cursor_positions.size():
|
||||||
|
edit_cursor_positions[i] = _step_cursor(edited_cells[i].text, edit_cursor_positions[i], -1)
|
||||||
|
|
||||||
|
|
||||||
|
static func multi_move_right(edited_cells : Array, edit_cursor_positions : Array):
|
||||||
|
for i in edit_cursor_positions.size():
|
||||||
|
edit_cursor_positions[i] = _step_cursor(edited_cells[i].text, edit_cursor_positions[i], 1)
|
||||||
|
|
||||||
|
|
||||||
|
static func multi_paste(edited_cells : Array, edit_cursor_positions : Array, callback_object : Object):
|
||||||
|
var pasted_lines := OS.clipboard.split("\n")
|
||||||
|
var paste_each_line := pasted_lines.size() == edited_cells.size()
|
||||||
|
|
||||||
|
for i in edited_cells.size():
|
||||||
|
if paste_each_line:
|
||||||
|
edit_cursor_positions[i] += pasted_lines[i].length()
|
||||||
|
|
||||||
|
else:
|
||||||
|
edit_cursor_positions[i] += OS.clipboard.length()
|
||||||
|
|
||||||
|
var cell = edited_cells[i]
|
||||||
|
callback_object.set_cell(cell, (
|
||||||
|
cell.text.left(edit_cursor_positions[i])
|
||||||
|
+ (pasted_lines[i] if paste_each_line else OS.clipboard)
|
||||||
|
+ cell.text.substr(edit_cursor_positions[i])
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
static func multi_copy(edited_cells : Array):
|
||||||
|
var copied_text := ""
|
||||||
|
|
||||||
|
for i in edited_cells.size():
|
||||||
|
copied_text += "\n" + edited_cells[i].text
|
||||||
|
|
||||||
|
# Cut the first \n out.
|
||||||
|
OS.clipboard = copied_text.substr(1)
|
||||||
|
|
||||||
|
|
||||||
|
static func multi_linefeed(edited_cells : Array, edit_cursor_positions : Array, callback_object : Object):
|
||||||
|
for i in edited_cells.size():
|
||||||
|
var cell = edited_cells[i]
|
||||||
|
callback_object.set_cell(cell, (
|
||||||
|
cell.text.left(edit_cursor_positions[i])
|
||||||
|
+ "\n"
|
||||||
|
+ cell.text.substr(edit_cursor_positions[i])
|
||||||
|
))
|
||||||
|
edit_cursor_positions[i] = min(edit_cursor_positions[i] + 1, cell.text.length())
|
||||||
|
|
||||||
|
|
||||||
|
static func multi_input(input_char : String, edited_cells : Array, edit_cursor_positions : Array, callback_object : Object):
|
||||||
|
for i in edited_cells.size():
|
||||||
|
var cell = edited_cells[i]
|
||||||
|
callback_object.set_cell(cell, (
|
||||||
|
cell.text.left(edit_cursor_positions[i])
|
||||||
|
+ input_char
|
||||||
|
+ cell.text.substr(edit_cursor_positions[i])
|
||||||
|
))
|
||||||
|
edit_cursor_positions[i] = min(edit_cursor_positions[i] + 1, cell.text.length())
|
||||||
|
|
||||||
|
|
||||||
|
static func _step_cursor(text : String, start : int, step : int = 1) -> int:
|
||||||
|
while true:
|
||||||
|
start += step
|
||||||
|
if !Input.is_key_pressed(KEY_CONTROL) or is_character_whitespace(text, start):
|
||||||
|
if start > text.length():
|
||||||
|
return text.length()
|
||||||
|
|
||||||
|
if start < 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
return start
|
||||||
|
|
||||||
|
return 0
|
31
addons/resources_speadsheet_view/typed_cells/basic.tscn
Normal file
31
addons/resources_speadsheet_view/typed_cells/basic.tscn
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
[gd_scene load_steps=2 format=2]
|
||||||
|
|
||||||
|
[sub_resource type="DynamicFont" id=1]
|
||||||
|
size = 8
|
||||||
|
|
||||||
|
[node name="Label" type="Label"]
|
||||||
|
margin_right = 58.0
|
||||||
|
margin_bottom = 14.0
|
||||||
|
rect_min_size = Vector2( 58, 0 )
|
||||||
|
mouse_filter = 0
|
||||||
|
size_flags_vertical = 9
|
||||||
|
|
||||||
|
[node name="LineEdit" type="LineEdit" parent="."]
|
||||||
|
show_behind_parent = true
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
mouse_filter = 2
|
||||||
|
custom_fonts/font = SubResource( 1 )
|
||||||
|
editable = false
|
||||||
|
expand_to_text_length = true
|
||||||
|
context_menu_enabled = false
|
||||||
|
virtual_keyboard_enabled = false
|
||||||
|
caret_blink = true
|
||||||
|
caret_blink_speed = 0.5
|
||||||
|
|
||||||
|
[node name="Selected" type="ColorRect" parent="."]
|
||||||
|
visible = false
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
mouse_filter = 2
|
||||||
|
color = Color( 1, 1, 1, 0.247059 )
|
70
example/my_custom_resource.gd
Normal file
70
example/my_custom_resource.gd
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
tool
|
||||||
|
class_name DynamicWheelItem
|
||||||
|
extends Resource
|
||||||
|
|
||||||
|
export var max_duplicates := 0
|
||||||
|
export var tags := "tag_1 tag_2 tag_3"
|
||||||
|
export var requires_one_of_tags := ""
|
||||||
|
export(String) var tag_delimeter = " "
|
||||||
|
export var base_weight := 10.0
|
||||||
|
export(String, MULTILINE) var multiplier_per_tag := ""
|
||||||
|
export(String, MULTILINE) var multiplier_if_tag_present := ""
|
||||||
|
export(String, MULTILINE) var multiplier_if_tag_not_present := ""
|
||||||
|
export(String, MULTILINE) var max_tags_present := ""
|
||||||
|
export(String) var list_item_delimeter = " "
|
||||||
|
export(String) var list_row_delimeter = ";"
|
||||||
|
|
||||||
|
var is_cached := false
|
||||||
|
var tag_array := []
|
||||||
|
var requires_one_of_tags_array := []
|
||||||
|
var multiplier_per_tag_dict := {}
|
||||||
|
var multiplier_if_tag_present_dict := {}
|
||||||
|
var multiplier_if_tag_not_present_dict := {}
|
||||||
|
var max_tags_present_dict := {}
|
||||||
|
|
||||||
|
|
||||||
|
func get_weight(owned_tags : Dictionary) -> float:
|
||||||
|
if !is_cached:
|
||||||
|
_cache_lists()
|
||||||
|
|
||||||
|
for k in max_tags_present_dict:
|
||||||
|
if owned_tags.get(k, 0) >= max_tags_present_dict[k]:
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
var result_weight := base_weight
|
||||||
|
for k in multiplier_per_tag_dict:
|
||||||
|
result_weight *= pow(multiplier_per_tag_dict[k], owned_tags.get(k, 0))
|
||||||
|
|
||||||
|
for k in multiplier_if_tag_not_present_dict:
|
||||||
|
if owned_tags.has(k):
|
||||||
|
result_weight *= multiplier_if_tag_present_dict[k]
|
||||||
|
|
||||||
|
for k in multiplier_if_tag_not_present_dict:
|
||||||
|
if owned_tags.has(k):
|
||||||
|
result_weight *= multiplier_if_tag_present_dict[k]
|
||||||
|
|
||||||
|
return result_weight
|
||||||
|
|
||||||
|
|
||||||
|
func _cache_lists():
|
||||||
|
tag_array = tags.split(tag_delimeter)
|
||||||
|
requires_one_of_tags_array = requires_one_of_tags.split(tag_delimeter)
|
||||||
|
|
||||||
|
multiplier_per_tag_dict.clear()
|
||||||
|
multiplier_if_tag_present_dict.clear()
|
||||||
|
multiplier_if_tag_not_present_dict.clear()
|
||||||
|
max_tags_present_dict.clear()
|
||||||
|
|
||||||
|
_cache_text_into_dictionary(multiplier_per_tag_dict, multiplier_per_tag)
|
||||||
|
_cache_text_into_dictionary(multiplier_if_tag_present_dict, multiplier_if_tag_present)
|
||||||
|
_cache_text_into_dictionary(multiplier_if_tag_not_present_dict, multiplier_if_tag_not_present)
|
||||||
|
_cache_text_into_dictionary(max_tags_present_dict, max_tags_present)
|
||||||
|
|
||||||
|
is_cached = true
|
||||||
|
|
||||||
|
|
||||||
|
func _cache_text_into_dictionary(dict : Dictionary, list_string : String):
|
||||||
|
for x in list_string.split(list_row_delimeter):
|
||||||
|
dict[x.left(x.find(list_item_delimeter))] = float(x.right(x.rfind(list_item_delimeter) + list_item_delimeter.length()))
|
||||||
|
|
||||||
|
print(dict)
|
19
example/upgrades/elemental.tres
Normal file
19
example/upgrades/elemental.tres
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[gd_resource type="Resource" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://example/my_custom_resource.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
resource_name = "Upgrade: Elemental Damage"
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
max_duplicates = 9
|
||||||
|
tags = "elemental"
|
||||||
|
requires_one_of_tags = ""
|
||||||
|
tag_delimeter = " "
|
||||||
|
base_weight = 10.0
|
||||||
|
multiplier_per_tag = ""
|
||||||
|
multiplier_if_tag_present = ""
|
||||||
|
multiplier_if_tag_not_present = "elemental 0"
|
||||||
|
max_tags_present = ""
|
||||||
|
list_item_delimeter = " "
|
||||||
|
list_row_delimeter = "
|
||||||
|
"
|
19
example/upgrades/health.tres
Normal file
19
example/upgrades/health.tres
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[gd_resource type="Resource" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://example/my_custom_resource.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
resource_name = "Upgrade: Health"
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
max_duplicates = 9
|
||||||
|
tags = "health melee"
|
||||||
|
requires_one_of_tags = ""
|
||||||
|
tag_delimeter = " "
|
||||||
|
base_weight = 10.0
|
||||||
|
multiplier_per_tag = "strength 1.5 melee 2.0"
|
||||||
|
multiplier_if_tag_present = ""
|
||||||
|
multiplier_if_tag_not_present = ""
|
||||||
|
max_tags_present = ""
|
||||||
|
list_item_delimeter = " "
|
||||||
|
list_row_delimeter = "
|
||||||
|
"
|
19
example/upgrades/up_aoe.tres
Normal file
19
example/upgrades/up_aoe.tres
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[gd_resource type="Resource" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://example/my_custom_resource.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
resource_name = "Upgrade: Area of Effect"
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
max_duplicates = 4
|
||||||
|
tags = "aoe"
|
||||||
|
requires_one_of_tags = ""
|
||||||
|
tag_delimeter = " "
|
||||||
|
base_weight = 10.0
|
||||||
|
multiplier_per_tag = ""
|
||||||
|
multiplier_if_tag_present = ""
|
||||||
|
multiplier_if_tag_not_present = "aoe 0"
|
||||||
|
max_tags_present = ""
|
||||||
|
list_item_delimeter = " "
|
||||||
|
list_row_delimeter = "
|
||||||
|
"
|
19
example/upgrades/up_magic.tres
Normal file
19
example/upgrades/up_magic.tres
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[gd_resource type="Resource" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://example/my_custom_resource.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
resource_name = "Upgrade: Magic"
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
max_duplicates = 9
|
||||||
|
tags = "magic"
|
||||||
|
requires_one_of_tags = ""
|
||||||
|
tag_delimeter = " "
|
||||||
|
base_weight = 10.0
|
||||||
|
multiplier_per_tag = ""
|
||||||
|
multiplier_if_tag_present = ""
|
||||||
|
multiplier_if_tag_not_present = "magic 0"
|
||||||
|
max_tags_present = ""
|
||||||
|
list_item_delimeter = " "
|
||||||
|
list_row_delimeter = "
|
||||||
|
"
|
19
example/upgrades/up_strength.tres
Normal file
19
example/upgrades/up_strength.tres
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[gd_resource type="Resource" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://example/my_custom_resource.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
resource_name = "Upgrade: Strength"
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
max_duplicates = 9
|
||||||
|
tags = "strength"
|
||||||
|
requires_one_of_tags = ""
|
||||||
|
tag_delimeter = " "
|
||||||
|
base_weight = 10.0
|
||||||
|
multiplier_per_tag = ""
|
||||||
|
multiplier_if_tag_present = ""
|
||||||
|
multiplier_if_tag_not_present = "strength 0"
|
||||||
|
max_tags_present = ""
|
||||||
|
list_item_delimeter = " "
|
||||||
|
list_row_delimeter = "
|
||||||
|
"
|
19
example/upgrades/weapon_axe.tres
Normal file
19
example/upgrades/weapon_axe.tres
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[gd_resource type="Resource" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://example/my_custom_resource.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
resource_name = "Weapon: Axe"
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
max_duplicates = 0
|
||||||
|
tags = "weapon strength aoe melee"
|
||||||
|
requires_one_of_tags = ""
|
||||||
|
tag_delimeter = " "
|
||||||
|
base_weight = 10.0
|
||||||
|
multiplier_per_tag = "strength 2.0"
|
||||||
|
multiplier_if_tag_present = ""
|
||||||
|
multiplier_if_tag_not_present = ""
|
||||||
|
max_tags_present = "weapon 4"
|
||||||
|
list_item_delimeter = " "
|
||||||
|
list_row_delimeter = "
|
||||||
|
"
|
19
example/upgrades/weapon_blizzard.tres
Normal file
19
example/upgrades/weapon_blizzard.tres
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[gd_resource type="Resource" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://example/my_custom_resource.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
resource_name = "Weapon: Blizzard"
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
max_duplicates = 0
|
||||||
|
tags = "weapon magic aoe elemental"
|
||||||
|
requires_one_of_tags = ""
|
||||||
|
tag_delimeter = " "
|
||||||
|
base_weight = 10.0
|
||||||
|
multiplier_per_tag = "magic 2.0"
|
||||||
|
multiplier_if_tag_present = ""
|
||||||
|
multiplier_if_tag_not_present = ""
|
||||||
|
max_tags_present = "weapon 4"
|
||||||
|
list_item_delimeter = " "
|
||||||
|
list_row_delimeter = "
|
||||||
|
"
|
19
example/upgrades/weapon_chaos_blast.tres
Normal file
19
example/upgrades/weapon_chaos_blast.tres
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[gd_resource type="Resource" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://example/my_custom_resource.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
resource_name = "Weapon: Chaos Blast"
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
max_duplicates = 0
|
||||||
|
tags = "weapon magic legendary chaosblast aoe"
|
||||||
|
requires_one_of_tags = ""
|
||||||
|
tag_delimeter = " "
|
||||||
|
base_weight = 1.0
|
||||||
|
multiplier_per_tag = "magic 2.0"
|
||||||
|
multiplier_if_tag_present = ""
|
||||||
|
multiplier_if_tag_not_present = ""
|
||||||
|
max_tags_present = "weapon 4"
|
||||||
|
list_item_delimeter = " "
|
||||||
|
list_row_delimeter = "
|
||||||
|
"
|
19
example/upgrades/weapon_dagger.tres
Normal file
19
example/upgrades/weapon_dagger.tres
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[gd_resource type="Resource" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://example/my_custom_resource.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
resource_name = "Weapon: Daggers"
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
max_duplicates = 0
|
||||||
|
tags = "weapon strength dagger projectile"
|
||||||
|
requires_one_of_tags = ""
|
||||||
|
tag_delimeter = " "
|
||||||
|
base_weight = 10.0
|
||||||
|
multiplier_per_tag = "strength 2.0"
|
||||||
|
multiplier_if_tag_present = ""
|
||||||
|
multiplier_if_tag_not_present = ""
|
||||||
|
max_tags_present = "weapon 4"
|
||||||
|
list_item_delimeter = " "
|
||||||
|
list_row_delimeter = "
|
||||||
|
"
|
19
example/upgrades/weapon_fireball.tres
Normal file
19
example/upgrades/weapon_fireball.tres
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[gd_resource type="Resource" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://example/my_custom_resource.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
resource_name = "Weapon: Fireball"
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
max_duplicates = 0
|
||||||
|
tags = "weapon magic fireball projectile elemental"
|
||||||
|
requires_one_of_tags = ""
|
||||||
|
tag_delimeter = " "
|
||||||
|
base_weight = 10.0
|
||||||
|
multiplier_per_tag = "magic 2.0"
|
||||||
|
multiplier_if_tag_present = ""
|
||||||
|
multiplier_if_tag_not_present = ""
|
||||||
|
max_tags_present = "weapon 4"
|
||||||
|
list_item_delimeter = " "
|
||||||
|
list_row_delimeter = "
|
||||||
|
"
|
19
example/upgrades/weapon_giga_sword.tres
Normal file
19
example/upgrades/weapon_giga_sword.tres
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[gd_resource type="Resource" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://example/my_custom_resource.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
resource_name = "Weapon: Giga Sword"
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
max_duplicates = 0
|
||||||
|
tags = "weapon strength legendary gigasword melee"
|
||||||
|
requires_one_of_tags = ""
|
||||||
|
tag_delimeter = " "
|
||||||
|
base_weight = 1.0
|
||||||
|
multiplier_per_tag = "strength 2.0"
|
||||||
|
multiplier_if_tag_present = ""
|
||||||
|
multiplier_if_tag_not_present = ""
|
||||||
|
max_tags_present = "weapon 4"
|
||||||
|
list_item_delimeter = " "
|
||||||
|
list_row_delimeter = "
|
||||||
|
"
|
19
example/upgrades/weapon_lightning.tres
Normal file
19
example/upgrades/weapon_lightning.tres
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[gd_resource type="Resource" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://example/my_custom_resource.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
resource_name = "Weapon: Lightning"
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
max_duplicates = 0
|
||||||
|
tags = "weapon magic lightning elemental"
|
||||||
|
requires_one_of_tags = ""
|
||||||
|
tag_delimeter = " "
|
||||||
|
base_weight = 10.0
|
||||||
|
multiplier_per_tag = "magic 2.0"
|
||||||
|
multiplier_if_tag_present = ""
|
||||||
|
multiplier_if_tag_not_present = ""
|
||||||
|
max_tags_present = "weapon 4"
|
||||||
|
list_item_delimeter = " "
|
||||||
|
list_row_delimeter = "
|
||||||
|
"
|
19
example/upgrades/weapon_spear.tres
Normal file
19
example/upgrades/weapon_spear.tres
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[gd_resource type="Resource" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://example/my_custom_resource.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
resource_name = "Weapon: Spear"
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
max_duplicates = 0
|
||||||
|
tags = "weapon strength spear melee"
|
||||||
|
requires_one_of_tags = ""
|
||||||
|
tag_delimeter = " "
|
||||||
|
base_weight = 10.0
|
||||||
|
multiplier_per_tag = "strength 2.0"
|
||||||
|
multiplier_if_tag_present = ""
|
||||||
|
multiplier_if_tag_not_present = ""
|
||||||
|
max_tags_present = "weapon 4"
|
||||||
|
list_item_delimeter = " "
|
||||||
|
list_row_delimeter = "
|
||||||
|
"
|
35
icon.png.import
Normal file
35
icon.png.import
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://icon.png"
|
||||||
|
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/bptc_ldr=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=true
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
process/invert_color=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
0
images/.gdignore
Normal file
0
images/.gdignore
Normal file
BIN
images/2022-09-20-00-05-43.png
Normal file
BIN
images/2022-09-20-00-05-43.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 86 KiB |
35
images/2022-09-20-00-05-43.png.import
Normal file
35
images/2022-09-20-00-05-43.png.import
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/2022-09-20-00-05-43.png-d44ad438e580d1568f353ee6177cce73.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://images/2022-09-20-00-05-43.png"
|
||||||
|
dest_files=[ "res://.import/2022-09-20-00-05-43.png-d44ad438e580d1568f353ee6177cce73.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/bptc_ldr=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=true
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
process/invert_color=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
60
project.godot
Normal file
60
project.godot
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
; Engine configuration file.
|
||||||
|
; It's best edited using the editor UI and not directly,
|
||||||
|
; since the parameters that go here are not all obvious.
|
||||||
|
;
|
||||||
|
; Format:
|
||||||
|
; [section] ; section goes between []
|
||||||
|
; param=value ; assign values to parameters
|
||||||
|
|
||||||
|
config_version=4
|
||||||
|
|
||||||
|
_global_script_classes=[ {
|
||||||
|
"base": "Resource",
|
||||||
|
"class": "DynamicWheelItem",
|
||||||
|
"language": "GDScript",
|
||||||
|
"path": "res://example/my_custom_resource.gd"
|
||||||
|
}, {
|
||||||
|
"base": "Reference",
|
||||||
|
"class": "TextEditingUtils",
|
||||||
|
"language": "GDScript",
|
||||||
|
"path": "res://addons/resources_speadsheet_view/text_editing_utils.gd"
|
||||||
|
}, {
|
||||||
|
"base": "Button",
|
||||||
|
"class": "ThemeIconButton",
|
||||||
|
"language": "GDScript",
|
||||||
|
"path": "res://addons/resources_speadsheet_view/editor_icon_button.gd"
|
||||||
|
}, {
|
||||||
|
"base": "Control",
|
||||||
|
"class": "ThemeStylebox",
|
||||||
|
"language": "GDScript",
|
||||||
|
"path": "res://addons/resources_speadsheet_view/editor_stylebox_overrider.gd"
|
||||||
|
} ]
|
||||||
|
_global_script_class_icons={
|
||||||
|
"DynamicWheelItem": "",
|
||||||
|
"TextEditingUtils": "",
|
||||||
|
"ThemeIconButton": "",
|
||||||
|
"ThemeStylebox": ""
|
||||||
|
}
|
||||||
|
|
||||||
|
[application]
|
||||||
|
|
||||||
|
config/name="Edit Resources as Spreadsheets"
|
||||||
|
config/icon="res://icon.png"
|
||||||
|
|
||||||
|
[editor_plugins]
|
||||||
|
|
||||||
|
enabled=PoolStringArray( "res://addons/resources_speadsheet_view/plugin.cfg" )
|
||||||
|
|
||||||
|
[gui]
|
||||||
|
|
||||||
|
common/drop_mouse_on_gui_input_disabled=true
|
||||||
|
|
||||||
|
[physics]
|
||||||
|
|
||||||
|
common/enable_pause_aware_picking=true
|
||||||
|
|
||||||
|
[rendering]
|
||||||
|
|
||||||
|
quality/driver/driver_name="GLES2"
|
||||||
|
vram_compression/import_etc=true
|
||||||
|
vram_compression/import_etc2=false
|
Loading…
Reference in New Issue
Block a user