Added resource table plugin
This commit is contained in:
146
addons/resources_spreadsheet_view/main_screen/class_filter.gd
Normal file
146
addons/resources_spreadsheet_view/main_screen/class_filter.gd
Normal file
@@ -0,0 +1,146 @@
|
||||
@tool
|
||||
extends Control
|
||||
|
||||
@onready var editor_view := $"../../../../.."
|
||||
@onready var node_options := $"Class"
|
||||
@onready var node_subclasses_check := $"Subclasses"
|
||||
|
||||
var found_builtins : Array[String] = []
|
||||
var found_scripts : Array[Script] = []
|
||||
var selected_builtin := &""
|
||||
var selected_script : Script
|
||||
var selected_is_valid := false
|
||||
var include_subclasses := true
|
||||
|
||||
|
||||
func _ready():
|
||||
node_options.item_selected.connect(_on_item_selected)
|
||||
node_subclasses_check.toggled.connect(_on_subclasses_toggled)
|
||||
|
||||
|
||||
func fill(resources : Array):
|
||||
node_options.clear()
|
||||
found_scripts.clear()
|
||||
found_builtins.clear()
|
||||
var class_set := {}
|
||||
for x in resources:
|
||||
class_set[x.get_script()] = true
|
||||
class_set[StringName(x.get_class())] = true
|
||||
var current_s : Script = x.get_script()
|
||||
while current_s != null:
|
||||
current_s = current_s.get_base_script()
|
||||
if class_set.has(current_s):
|
||||
break
|
||||
|
||||
class_set[current_s] = true
|
||||
|
||||
var current_c : StringName = x.get_class()
|
||||
while true:
|
||||
if current_c == &"Resource":
|
||||
break
|
||||
|
||||
current_c = ClassDB.get_parent_class(current_c)
|
||||
if class_set.has(current_c):
|
||||
break
|
||||
|
||||
class_set[current_c] = true
|
||||
|
||||
class_set.erase(null)
|
||||
class_set.erase("Resource")
|
||||
|
||||
for k in class_set:
|
||||
if k is StringName:
|
||||
found_builtins.append(k)
|
||||
|
||||
if k is Script:
|
||||
found_scripts.append(k)
|
||||
|
||||
# Add builtins, then script classes, in order.
|
||||
node_options.add_item("<all>")
|
||||
for x in found_builtins:
|
||||
node_options.add_item(x)
|
||||
if has_theme_icon(x, &"EditorIcons"):
|
||||
node_options.set_item_icon(-1, get_theme_icon(x, &"EditorIcons"))
|
||||
|
||||
else:
|
||||
node_options.set_item_icon(-1, get_theme_icon(&"Object", &"EditorIcons"))
|
||||
|
||||
for x in found_scripts:
|
||||
node_options.add_item(x.resource_path.get_file().get_basename().to_pascal_case())
|
||||
node_options.set_item_icon(-1, get_theme_icon(&"Script", &"EditorIcons"))
|
||||
|
||||
node_options.add_item("")
|
||||
|
||||
# Filter is disabled if the already selected class is not in the set.
|
||||
if not class_set.has(selected_script) and not class_set.has(selected_builtin):
|
||||
selected_is_valid = false
|
||||
|
||||
# When the list is cleared, text and icon are cleared too. Setting to -1 explicitly allows changing icon and label
|
||||
node_options.selected = -1
|
||||
if not selected_is_valid:
|
||||
node_options.set_item_icon(-1, null)
|
||||
|
||||
elif selected_builtin == &"" or selected_builtin == &"Resource":
|
||||
node_options.set_item_icon(-1, get_theme_icon("Script", "EditorIcons"))
|
||||
|
||||
else:
|
||||
node_options.set_item_icon(-1, get_theme_icon(selected_builtin, "EditorIcons"))
|
||||
|
||||
show()
|
||||
|
||||
|
||||
func clear():
|
||||
selected_is_valid = false
|
||||
|
||||
|
||||
func filter(resource : Resource) -> bool:
|
||||
if not selected_is_valid:
|
||||
return true
|
||||
|
||||
if resource.get_class() != selected_builtin:
|
||||
if include_subclasses and selected_script == null:
|
||||
var cur_class := StringName(resource.get_class())
|
||||
while cur_class != &"Object":
|
||||
cur_class = ClassDB.get_parent_class(cur_class)
|
||||
if cur_class == selected_builtin:
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
if selected_script != null and resource.get_script() != selected_script:
|
||||
if include_subclasses:
|
||||
var cur_class : Script = resource.get_script()
|
||||
while cur_class != null:
|
||||
cur_class = cur_class.get_base_script()
|
||||
if cur_class == selected_script:
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
|
||||
return true
|
||||
|
||||
|
||||
func _on_item_selected(index : int):
|
||||
if index == 0:
|
||||
selected_builtin = &""
|
||||
selected_script = null
|
||||
selected_is_valid = false
|
||||
|
||||
elif index <= found_builtins.size():
|
||||
selected_builtin = found_builtins[index - 1]
|
||||
selected_script = null
|
||||
selected_is_valid = true
|
||||
|
||||
elif index <= found_builtins.size() + found_scripts.size():
|
||||
selected_script = found_scripts[index - found_builtins.size() - 1]
|
||||
selected_builtin = selected_script.get_instance_base_type()
|
||||
selected_is_valid = true
|
||||
|
||||
node_options.tooltip_text = "Selected: %s" % node_options.get_item_text(index)
|
||||
editor_view.refresh()
|
||||
|
||||
|
||||
func _on_subclasses_toggled(state : bool):
|
||||
include_subclasses = state
|
||||
editor_view.refresh()
|
||||
@@ -0,0 +1 @@
|
||||
uid://dbnhniu1anvc7
|
||||
@@ -0,0 +1,182 @@
|
||||
@tool
|
||||
extends Control
|
||||
|
||||
const TablesPluginSettingsClass := preload("res://addons/resources_spreadsheet_view/settings_grid.gd")
|
||||
|
||||
@export var table_header_scene : PackedScene
|
||||
|
||||
@onready var editor_view : Control = $"../../../.."
|
||||
@onready var hide_columns_button : MenuButton = $"../../MenuStrip/VisibleCols"
|
||||
@onready var grid : Container = $"../../../MarginContainer/FooterContentSplit/Panel/Scroll/MarginContainer/TableGrid"
|
||||
|
||||
|
||||
var hidden_columns := {}:
|
||||
get:
|
||||
var result := {}
|
||||
for k_path in column_properties:
|
||||
var result_one_path := {}
|
||||
result[k_path] = result_one_path
|
||||
for k_column in column_properties[k_path]:
|
||||
for k_property in column_properties[k_path][k_column]:
|
||||
if k_property == &"visibility" && [k_property]:
|
||||
result[k_path][k_column] = true
|
||||
|
||||
return result
|
||||
var column_properties := {}
|
||||
var columns := []:
|
||||
set(v):
|
||||
columns = v
|
||||
for x in get_children():
|
||||
remove_child(x)
|
||||
x.queue_free()
|
||||
|
||||
var new_node : Control
|
||||
for x in v:
|
||||
new_node = table_header_scene.instantiate()
|
||||
new_node.manager = self
|
||||
add_child(new_node)
|
||||
new_node.set_label(x)
|
||||
new_node.get_node("Button").pressed.connect(editor_view._set_sorting.bind(x))
|
||||
_update_column_sizes()
|
||||
|
||||
|
||||
func _ready():
|
||||
hide_columns_button\
|
||||
.get_popup()\
|
||||
.id_pressed\
|
||||
.connect(_on_visible_cols_id_pressed)
|
||||
$"../../../MarginContainer/FooterContentSplit/Panel/Scroll"\
|
||||
.get_h_scroll_bar()\
|
||||
.value_changed\
|
||||
.connect(_on_h_scroll_changed)
|
||||
|
||||
|
||||
func update():
|
||||
_update_hidden_columns()
|
||||
_update_column_sizes()
|
||||
|
||||
|
||||
func hide_column(column_index : int):
|
||||
set_column_property(column_index, &"visibility", 0)
|
||||
editor_view.save_data()
|
||||
update()
|
||||
|
||||
|
||||
func set_column_property(column_index : int, property_key : StringName, property_value):
|
||||
var dict := column_properties
|
||||
if !dict.has(editor_view.current_path):
|
||||
dict[editor_view.current_path] = {}
|
||||
|
||||
dict = dict[editor_view.current_path]
|
||||
if !dict.has(columns[column_index]):
|
||||
dict[columns[column_index]] = {}
|
||||
|
||||
dict = dict[columns[column_index]]
|
||||
dict[property_key] = property_value
|
||||
|
||||
|
||||
func get_column_property(column_index : int, property_key : StringName, property_default = null):
|
||||
var dict := column_properties
|
||||
if !dict.has(editor_view.current_path):
|
||||
return property_default
|
||||
|
||||
dict = dict[editor_view.current_path]
|
||||
if !dict.has(columns[column_index]):
|
||||
return property_default
|
||||
|
||||
dict = dict[columns[column_index]]
|
||||
return dict.get(property_key, property_default)
|
||||
|
||||
|
||||
func select_column(column_index : int):
|
||||
editor_view.select_column(column_index)
|
||||
|
||||
|
||||
func _update_column_sizes():
|
||||
if grid.get_child_count() == 0:
|
||||
return
|
||||
|
||||
await get_tree().process_frame
|
||||
var column_headers := get_children()
|
||||
|
||||
if grid.get_child_count() < column_headers.size(): return
|
||||
if column_headers.size() != columns.size():
|
||||
editor_view.refresh()
|
||||
return
|
||||
|
||||
var clip_text : bool = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "clip_headers")
|
||||
var visible_column_minsizes : Array[float] = []
|
||||
for i in column_headers.size():
|
||||
var header = column_headers[i]
|
||||
if header.visible:
|
||||
header.get_child(0).clip_text = clip_text
|
||||
visible_column_minsizes.append(header.get_combined_minimum_size().x)
|
||||
|
||||
grid.visible_column_minsizes = visible_column_minsizes
|
||||
await get_tree().process_frame
|
||||
|
||||
# Abort if the node has been deleted since.
|
||||
if !is_instance_valid(column_headers[0]):
|
||||
return
|
||||
|
||||
get_parent().custom_minimum_size.y = column_headers[0].get_combined_minimum_size().y
|
||||
var column_positions : Array = grid.visible_column_positions
|
||||
var i := 0
|
||||
for x in column_headers:
|
||||
if !x.visible:
|
||||
continue
|
||||
|
||||
var pos : float = column_positions[i]
|
||||
x.position.x = pos
|
||||
x.size.x = column_positions[i + 1] - pos
|
||||
i += 1
|
||||
|
||||
|
||||
func _update_hidden_columns():
|
||||
var current_path : String = editor_view.current_path
|
||||
var rows_shown : int = editor_view.last_row - editor_view.first_row
|
||||
|
||||
if !column_properties.has(current_path):
|
||||
column_properties[current_path] = {
|
||||
"resource_local_to_scene" : { &"visibility" : 0 },
|
||||
"resource_name" : { &"visibility" : 0 },
|
||||
"metadata/_custom_type_script" : { &"visibility" : 0 },
|
||||
}
|
||||
editor_view.save_data()
|
||||
|
||||
var visible_column_count := 0
|
||||
for i in columns.size():
|
||||
var column_visible : bool = get_column_property(i, &"visibility", 1) != 0
|
||||
get_child(i).visible = column_visible
|
||||
for j in rows_shown:
|
||||
grid.get_child(j * columns.size() + i).visible = column_visible
|
||||
|
||||
if column_visible:
|
||||
visible_column_count += 1
|
||||
|
||||
|
||||
func _on_h_scroll_changed(value):
|
||||
position.x = -value
|
||||
|
||||
|
||||
func _on_visible_cols_about_to_popup():
|
||||
var popup := hide_columns_button.get_popup()
|
||||
popup.clear()
|
||||
popup.hide_on_checkable_item_selection = false
|
||||
for i in columns.size():
|
||||
popup.add_check_item(columns[i].capitalize(), i)
|
||||
popup.set_item_checked(i, get_column_property(i, &"visibility", 1) != 0)
|
||||
|
||||
|
||||
func _on_visible_cols_id_pressed(id : int):
|
||||
var popup := hide_columns_button.get_popup()
|
||||
if popup.is_item_checked(id):
|
||||
popup.set_item_checked(id, false)
|
||||
set_column_property(id, &"visibility", 0)
|
||||
|
||||
else:
|
||||
popup.set_item_checked(id, true)
|
||||
set_column_property(id, &"visibility", 1)
|
||||
|
||||
editor_view.save_data()
|
||||
update()
|
||||
@@ -0,0 +1 @@
|
||||
uid://ot866hxu2g4m
|
||||
@@ -0,0 +1,73 @@
|
||||
@tool
|
||||
extends Container
|
||||
|
||||
var visible_column_minsizes : Array = []:
|
||||
set(v):
|
||||
visible_column_minsizes = v
|
||||
queue_sort()
|
||||
var visible_column_positions : Array[float] = []
|
||||
var _cached_minimum_size := Vector2.ZERO
|
||||
|
||||
|
||||
func _notification(what : int) -> void:
|
||||
if what == NOTIFICATION_SORT_CHILDREN:
|
||||
var visible_children : Array[Control] = []
|
||||
for x in get_children():
|
||||
if x is Control and x.visible:
|
||||
visible_children.append(x)
|
||||
|
||||
sort_children(visible_children)
|
||||
|
||||
|
||||
func _get_minimum_size() -> Vector2:
|
||||
return _cached_minimum_size
|
||||
|
||||
|
||||
func get_visible_column_position(index : int):
|
||||
pass
|
||||
|
||||
|
||||
func sort_children(children : Array[Control]) -> void:
|
||||
var column_count := visible_column_minsizes.size()
|
||||
if column_count == 0:
|
||||
return
|
||||
|
||||
var column_minsizes : Array[float] = []
|
||||
var row_minsizes : Array[float] = []
|
||||
column_minsizes.resize(column_count)
|
||||
row_minsizes.resize(children.size() / column_count + 1)
|
||||
|
||||
for i in visible_column_minsizes.size():
|
||||
column_minsizes[i] = visible_column_minsizes[i]
|
||||
|
||||
var current_cell := Vector2i.ZERO
|
||||
for x in children:
|
||||
var minsize := x.get_combined_minimum_size()
|
||||
column_minsizes[current_cell.x] = maxf(column_minsizes[current_cell.x], minsize.x)
|
||||
row_minsizes[current_cell.y] = maxf(row_minsizes[current_cell.y], minsize.y)
|
||||
current_cell.x += 1
|
||||
if current_cell.x == column_count:
|
||||
current_cell.x = 0
|
||||
current_cell.y += 1
|
||||
|
||||
var current_pos := Vector2.ZERO
|
||||
current_cell = Vector2i.ZERO
|
||||
for x in children:
|
||||
var cur_size := Vector2(column_minsizes[current_cell.x], row_minsizes[current_cell.y])
|
||||
fit_child_in_rect(x, Rect2(current_pos, cur_size))
|
||||
current_pos.x += cur_size.x
|
||||
current_cell.x += 1
|
||||
if current_cell.x == column_count:
|
||||
current_cell.x = 0
|
||||
current_cell.y += 1
|
||||
current_pos.x = 0.0
|
||||
current_pos.y += cur_size.y
|
||||
|
||||
_cached_minimum_size = Vector2.ZERO
|
||||
visible_column_positions.resize(column_minsizes.size() + 1)
|
||||
for i in column_minsizes.size():
|
||||
_cached_minimum_size.x += column_minsizes[i]
|
||||
visible_column_positions[i + 1] = _cached_minimum_size.x
|
||||
|
||||
for x in row_minsizes:
|
||||
_cached_minimum_size.y += x
|
||||
@@ -0,0 +1 @@
|
||||
uid://dky1oatlfcbuf
|
||||
@@ -0,0 +1,173 @@
|
||||
@tool
|
||||
extends Control
|
||||
|
||||
@export var editor_view_path : NodePath
|
||||
|
||||
@export_enum("Filter", "Process", "Sort") var mode := 0
|
||||
@export var title := ""
|
||||
@export var default_text := "":
|
||||
set(v):
|
||||
default_text = v
|
||||
if _textfield == null:
|
||||
await ready
|
||||
|
||||
_textfield.text = v
|
||||
@export_multiline var default_text_ml := "":
|
||||
set(v):
|
||||
default_text_ml = v
|
||||
if _textfield_ml == null:
|
||||
await ready
|
||||
|
||||
_textfield_ml.text = v
|
||||
@export var function_save_key := ""
|
||||
|
||||
var _textfield : LineEdit
|
||||
var _textfield_ml : TextEdit
|
||||
var _togglable_popup : PopupPanel
|
||||
var _saved_function_index_label : Label
|
||||
|
||||
var _saved_functions : Array = []
|
||||
var _saved_function_selected := -1
|
||||
|
||||
|
||||
func load_saved_functions(func_dict : Dictionary):
|
||||
if !func_dict.has(function_save_key):
|
||||
func_dict[function_save_key] = [default_text_ml]
|
||||
|
||||
_saved_functions = func_dict[function_save_key]
|
||||
_on_saved_function_selected(0)
|
||||
|
||||
|
||||
func _ready():
|
||||
var toggle_button := Button.new()
|
||||
var popup_box := VBoxContainer.new()
|
||||
var popup_buttons_box := HBoxContainer.new()
|
||||
var title_label := Label.new()
|
||||
var submit_button := Button.new()
|
||||
var move_label := Label.new()
|
||||
var move_button_l := Button.new()
|
||||
var move_button_r := Button.new()
|
||||
_textfield = LineEdit.new()
|
||||
_togglable_popup = PopupPanel.new()
|
||||
_textfield_ml = TextEdit.new()
|
||||
_saved_function_index_label = Label.new()
|
||||
|
||||
add_child(_textfield)
|
||||
add_child(toggle_button)
|
||||
_textfield.add_child(_togglable_popup)
|
||||
_togglable_popup.add_child(popup_box)
|
||||
popup_box.add_child(title_label)
|
||||
popup_box.add_child(_textfield_ml)
|
||||
popup_box.add_child(popup_buttons_box)
|
||||
popup_buttons_box.add_child(submit_button)
|
||||
popup_buttons_box.add_child(move_label)
|
||||
popup_buttons_box.add_child(move_button_l)
|
||||
popup_buttons_box.add_child(_saved_function_index_label)
|
||||
popup_buttons_box.add_child(move_button_r)
|
||||
|
||||
title_label.text = title
|
||||
|
||||
toggle_button.icon = get_theme_icon("Collapse", "EditorIcons")
|
||||
toggle_button.pressed.connect(_on_expand_pressed)
|
||||
|
||||
_textfield.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
_textfield.text_submitted.connect(_on_text_submitted.unbind(1))
|
||||
|
||||
_textfield_ml.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
_textfield_ml.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
|
||||
submit_button.text = "Run multiline!"
|
||||
submit_button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
submit_button.pressed.connect(_on_text_submitted)
|
||||
|
||||
move_label.text = "Choose saved:"
|
||||
move_button_l.icon = get_theme_icon("PagePrevious", "EditorIcons")
|
||||
move_button_l.pressed.connect(_on_saved_function_bumped.bind(-1))
|
||||
_on_saved_function_selected(0)
|
||||
move_button_r.icon = get_theme_icon("PageNext", "EditorIcons")
|
||||
move_button_r.pressed.connect(_on_saved_function_bumped.bind(+1))
|
||||
|
||||
|
||||
|
||||
func _on_expand_pressed():
|
||||
_togglable_popup.popup(Rect2i(_textfield.get_screen_position(), Vector2(size.x, 256.0)))
|
||||
|
||||
|
||||
func _on_text_submitted():
|
||||
[_table_filter, _table_process][mode].call()
|
||||
_saved_functions[_saved_function_selected] = _textfield_ml.text
|
||||
get_node(editor_view_path).save_data.call_deferred()
|
||||
|
||||
|
||||
func _get_script_source_code(first_line : String):
|
||||
var new_text := ""
|
||||
if !_togglable_popup.visible:
|
||||
new_text = _textfield.text
|
||||
if new_text == "":
|
||||
new_text = default_text
|
||||
|
||||
return first_line + "\treturn " + new_text
|
||||
|
||||
else:
|
||||
new_text = _textfield_ml.text
|
||||
if new_text == "":
|
||||
new_text = default_text_ml
|
||||
|
||||
var text_split := new_text.split("\n")
|
||||
for i in text_split.size():
|
||||
text_split[i] = "\t" + text_split[i]
|
||||
|
||||
return first_line + "\n".join(text_split)
|
||||
|
||||
|
||||
func _table_filter():
|
||||
var new_script := GDScript.new()
|
||||
new_script.source_code = _get_script_source_code("static func can_show(res : Resource, index : int) -> bool:\n")
|
||||
new_script.reload()
|
||||
|
||||
var editor_view := get_node(editor_view_path)
|
||||
editor_view.search_cond = new_script.can_show
|
||||
editor_view.refresh()
|
||||
|
||||
|
||||
func _table_process():
|
||||
var new_script := GDScript.new()
|
||||
new_script.source_code = _get_script_source_code("static func get_result(value : Variant, res : Resource, all_res : Array[Resource], row_index : int) -> Variant:\n")
|
||||
new_script.reload()
|
||||
|
||||
var editor_view := get_node(editor_view_path)
|
||||
var new_script_instance := new_script.new()
|
||||
var values : Array = editor_view.get_edited_cells_values()
|
||||
|
||||
var edited_rows : Array[int] = editor_view._selection.get_edited_rows()
|
||||
var edited_resources := edited_rows.map(func(x): return editor_view.rows[x])
|
||||
for i in values.size():
|
||||
values[i] = new_script_instance.get_result(values[i], editor_view.rows[edited_rows[i]], edited_resources, i)
|
||||
|
||||
editor_view.set_edited_cells_values(values)
|
||||
|
||||
|
||||
func _on_saved_function_selected(new_index : int):
|
||||
if new_index < 0:
|
||||
new_index = 0
|
||||
|
||||
if _saved_function_selected == _saved_functions.size() - 1 and _textfield_ml.text == default_text_ml:
|
||||
_saved_functions.resize(_saved_functions.size() - 1)
|
||||
|
||||
elif _saved_function_selected >= 0:
|
||||
_saved_functions[_saved_function_selected] = _textfield_ml.text
|
||||
|
||||
_saved_function_selected = new_index
|
||||
if new_index >= _saved_functions.size():
|
||||
_saved_functions.resize(new_index + 1)
|
||||
for i in _saved_functions.size():
|
||||
if _saved_functions[i] == null:
|
||||
_saved_functions[i] = default_text_ml
|
||||
|
||||
_textfield_ml.text = _saved_functions[new_index]
|
||||
_saved_function_index_label.text = "%d/%d" % [new_index + 1, _saved_functions.size()]
|
||||
get_node(editor_view_path).save_data.call_deferred()
|
||||
|
||||
|
||||
func _on_saved_function_bumped(increment : int):
|
||||
_on_saved_function_selected(_saved_function_selected + increment)
|
||||
@@ -0,0 +1 @@
|
||||
uid://desytritrg7nu
|
||||
@@ -0,0 +1,60 @@
|
||||
@tool
|
||||
extends ColorRect
|
||||
|
||||
const TablesPluginSettingsClass := preload("res://addons/resources_spreadsheet_view/settings_grid.gd")
|
||||
|
||||
@onready var editor_view : Control = $"../../../../../.."
|
||||
@onready var grid_scroll : ScrollContainer = $"../../Scroll"
|
||||
@onready var grid : Container = $"../../Scroll/MarginContainer/TableGrid"
|
||||
|
||||
var children : Array[Control] = []
|
||||
var children_copy_cells : Array[Control] = []
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
grid_scroll.get_h_scroll_bar().value_changed.connect(_on_scroll_updated, CONNECT_DEFERRED)
|
||||
grid_scroll.get_v_scroll_bar().value_changed.connect(_on_scroll_updated, CONNECT_DEFERRED)
|
||||
|
||||
|
||||
func _on_grid_updated() -> void:
|
||||
if editor_view.rows.size() == 0:
|
||||
hide()
|
||||
return
|
||||
|
||||
visible = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "freeze_first_column")
|
||||
for x in get_children():
|
||||
x.queue_free()
|
||||
|
||||
children.clear()
|
||||
children_copy_cells.clear()
|
||||
size.x = 0.0
|
||||
|
||||
await get_tree().process_frame
|
||||
|
||||
var first_visible_column := 0
|
||||
for i in editor_view.columns.size():
|
||||
if grid.get_child(i).visible:
|
||||
first_visible_column = i
|
||||
break
|
||||
|
||||
var total_column_count : int = editor_view.columns.size()
|
||||
children.resize(grid.get_child_count() / total_column_count)
|
||||
children_copy_cells.resize(children.size())
|
||||
for i in children.size():
|
||||
children_copy_cells[i] = grid.get_child(total_column_count * i + first_visible_column)
|
||||
children[i] = children_copy_cells[i].duplicate()
|
||||
children[i].mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
add_child(children[i])
|
||||
size.x = maxf(size.x, children_copy_cells[i].size.x)
|
||||
|
||||
size.y = grid.size.y
|
||||
color = get_theme_color(&"background", &"Editor")
|
||||
color.a *= 0.9
|
||||
_on_scroll_updated(0.0)
|
||||
|
||||
|
||||
func _on_scroll_updated(_new_value : float):
|
||||
position = Vector2(0.0, -grid_scroll.scroll_vertical)
|
||||
for i in children.size():
|
||||
children[i].size = children_copy_cells[i].size
|
||||
children[i].position = children_copy_cells[i].position
|
||||
@@ -0,0 +1 @@
|
||||
uid://dwf6rnqofdagb
|
||||
167
addons/resources_spreadsheet_view/main_screen/input_handler.gd
Normal file
167
addons/resources_spreadsheet_view/main_screen/input_handler.gd
Normal file
@@ -0,0 +1,167 @@
|
||||
@tool
|
||||
extends Node
|
||||
|
||||
const TablesPluginEditorViewClass := preload("res://addons/resources_spreadsheet_view/editor_view.gd")
|
||||
const TablesPluginSelectionManagerClass := preload("res://addons/resources_spreadsheet_view/main_screen/selection_manager.gd")
|
||||
const TextEditingUtilsClass := preload("res://addons/resources_spreadsheet_view/text_editing_utils.gd")
|
||||
|
||||
@onready var editor_view : TablesPluginEditorViewClass = get_parent()
|
||||
@onready var selection : TablesPluginSelectionManagerClass = get_node("../SelectionManager")
|
||||
|
||||
|
||||
func _on_cell_gui_input(event : InputEvent, cell_node : Control):
|
||||
var cell := selection.get_cell_node_position(cell_node)
|
||||
if event is InputEventMouseButton:
|
||||
editor_view.grab_focus()
|
||||
if event.button_index == MOUSE_BUTTON_RIGHT and event.pressed:
|
||||
if !cell in selection.edited_cells:
|
||||
selection.deselect_all_cells()
|
||||
selection.select_cell(cell)
|
||||
|
||||
selection.rightclick_cells()
|
||||
|
||||
if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
|
||||
if event.is_command_or_control_pressed():
|
||||
if cell in selection.edited_cells:
|
||||
selection.deselect_cell(cell)
|
||||
|
||||
else:
|
||||
selection.select_cell(cell)
|
||||
|
||||
elif Input.is_key_pressed(KEY_SHIFT):
|
||||
selection.select_cells_to(cell)
|
||||
|
||||
else:
|
||||
selection.deselect_all_cells()
|
||||
selection.select_cell(cell)
|
||||
|
||||
|
||||
func _gui_input(event : InputEvent):
|
||||
if event is InputEventMouseButton:
|
||||
if event.button_index == MOUSE_BUTTON_RIGHT and event.is_pressed():
|
||||
selection.rightclick_cells()
|
||||
|
||||
if event.button_index == MOUSE_BUTTON_LEFT:
|
||||
editor_view.grab_focus()
|
||||
if !event.pressed:
|
||||
selection.deselect_all_cells()
|
||||
|
||||
|
||||
func _input(event : InputEvent):
|
||||
if !event is InputEventKey or !event.pressed:
|
||||
return
|
||||
|
||||
if !editor_view.has_focus() or selection.edited_cells.size() == 0:
|
||||
return
|
||||
|
||||
if event.keycode == KEY_CTRL or event.keycode == KEY_SHIFT or event.keycode == KEY_META:
|
||||
# Modifier keys do not get processed.
|
||||
return
|
||||
|
||||
# Ctrl + Z (before, and instead of, committing the action!)
|
||||
if event.is_command_or_control_pressed():
|
||||
if event.keycode == KEY_Z or event.keycode == KEY_Y:
|
||||
return
|
||||
|
||||
_key_specific_action(event)
|
||||
editor_view.grab_focus()
|
||||
editor_view.editor_interface.get_resource_filesystem().scan()
|
||||
|
||||
|
||||
func _key_specific_action(event : InputEvent):
|
||||
var column := selection.get_cell_column(selection.edited_cells[0])
|
||||
var ctrl_pressed : bool = event.is_command_or_control_pressed()
|
||||
|
||||
# BETWEEN-CELL NAVIGATION
|
||||
var grid_move_offset := (10 if ctrl_pressed else 1)
|
||||
if event.keycode == KEY_UP:
|
||||
_move_selection_on_grid(0, -grid_move_offset)
|
||||
|
||||
elif event.keycode == KEY_DOWN:
|
||||
_move_selection_on_grid(0, +grid_move_offset)
|
||||
|
||||
elif Input.is_key_pressed(KEY_SHIFT) and event.keycode == KEY_TAB:
|
||||
_move_selection_on_grid(-grid_move_offset, 0)
|
||||
|
||||
elif event.keycode == KEY_TAB:
|
||||
_move_selection_on_grid(+grid_move_offset, 0)
|
||||
|
||||
elif ctrl_pressed and event.keycode == KEY_C:
|
||||
TextEditingUtilsClass.multi_copy(selection.edited_cells_text)
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
# Ctrl + V
|
||||
elif ctrl_pressed and event.keycode == KEY_V and editor_view.columns[column] != "resource_path":
|
||||
selection.clipboard_paste()
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
# TEXT CARET MOVEMENT
|
||||
var caret_move_offset := TextEditingUtilsClass.get_caret_movement_from_key(event.keycode)
|
||||
if TextEditingUtilsClass.multi_move_caret(caret_move_offset, selection.edited_cells_text, selection.edit_cursor_positions, ctrl_pressed):
|
||||
selection.queue_redraw()
|
||||
return
|
||||
|
||||
# The following actions do not work on non-editable cells.
|
||||
if !selection.column_editors[column].is_text() or editor_view.columns[column] == "resource_path":
|
||||
return
|
||||
|
||||
# ERASING
|
||||
elif event.keycode == KEY_BACKSPACE:
|
||||
editor_view.set_edited_cells_values_text(TextEditingUtilsClass.multi_erase_left(
|
||||
selection.edited_cells_text, selection.edit_cursor_positions, ctrl_pressed
|
||||
))
|
||||
|
||||
elif event.keycode == KEY_DELETE:
|
||||
editor_view.set_edited_cells_values_text(TextEditingUtilsClass.multi_erase_right(
|
||||
selection.edited_cells_text, selection.edit_cursor_positions, ctrl_pressed
|
||||
))
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
# And finally, text typing.
|
||||
elif event.keycode == KEY_ENTER:
|
||||
editor_view.set_edited_cells_values_text(TextEditingUtilsClass.multi_input(
|
||||
"\n", selection.edited_cells_text, selection.edit_cursor_positions
|
||||
))
|
||||
|
||||
elif event.unicode != 0 and event.unicode != 127:
|
||||
editor_view.set_edited_cells_values_text(TextEditingUtilsClass.multi_input(
|
||||
char(event.unicode), selection.edited_cells_text, selection.edit_cursor_positions
|
||||
))
|
||||
|
||||
selection.queue_redraw()
|
||||
|
||||
|
||||
func _move_selection_on_grid(move_h : int, move_v : int):
|
||||
var selected_cells := selection.edited_cells.duplicate()
|
||||
var num_columns := editor_view.columns.size()
|
||||
var num_rows := editor_view.rows.size()
|
||||
var new_child_pos := Vector2i(0, 0)
|
||||
for i in selected_cells.size():
|
||||
new_child_pos = selected_cells[i]
|
||||
for move_count in 1000:
|
||||
if move_v != 0 and (new_child_pos.y + move_v >= num_rows or new_child_pos.y + move_v < 0):
|
||||
break
|
||||
|
||||
new_child_pos.x += move_h
|
||||
new_child_pos.y += move_v
|
||||
if new_child_pos.x < 0:
|
||||
new_child_pos.x = num_columns - 1
|
||||
if new_child_pos.y > 0:
|
||||
new_child_pos.y -= 1
|
||||
|
||||
if new_child_pos.x >= num_columns:
|
||||
new_child_pos.x = 0
|
||||
if new_child_pos.y < num_rows - 1:
|
||||
new_child_pos.y += 1
|
||||
|
||||
if selection.get_cell_node_from_position(new_child_pos) == null:
|
||||
break
|
||||
|
||||
if selection.get_cell_node_from_position(new_child_pos).is_visible_in_tree():
|
||||
break
|
||||
|
||||
selected_cells[i] = new_child_pos
|
||||
|
||||
editor_view.grab_focus()
|
||||
selection.deselect_all_cells()
|
||||
selection.select_cells(selected_cells)
|
||||
@@ -0,0 +1 @@
|
||||
uid://brea0xl3xhde0
|
||||
@@ -0,0 +1,54 @@
|
||||
@tool
|
||||
extends OptionButton
|
||||
|
||||
@onready var editor_view := $"../../../../.."
|
||||
|
||||
var recent_paths := []
|
||||
|
||||
|
||||
func _ready():
|
||||
item_selected.connect(_on_item_selected)
|
||||
|
||||
|
||||
func load_paths(paths):
|
||||
clear()
|
||||
for x in paths:
|
||||
add_path_to_recent(x, true)
|
||||
|
||||
selected = recent_paths.size() - 1
|
||||
|
||||
|
||||
func add_path_to_recent(path : String, is_loading : bool = false):
|
||||
if path in recent_paths: return
|
||||
|
||||
var idx_in_array := recent_paths.find(path)
|
||||
if idx_in_array != -1:
|
||||
remove_item(idx_in_array)
|
||||
recent_paths.remove_at(idx_in_array)
|
||||
|
||||
recent_paths.append(path)
|
||||
add_item(path)
|
||||
select(get_item_count() - 1)
|
||||
|
||||
if !is_loading:
|
||||
editor_view.save_data()
|
||||
|
||||
|
||||
func remove_selected_path_from_recent():
|
||||
if get_item_count() == 0:
|
||||
return
|
||||
|
||||
var idx_in_array := selected
|
||||
recent_paths.remove_at(idx_in_array)
|
||||
remove_item(idx_in_array)
|
||||
|
||||
if get_item_count() != 0:
|
||||
select(0)
|
||||
editor_view.display_folder(recent_paths[0])
|
||||
editor_view.save_data()
|
||||
|
||||
|
||||
func _on_item_selected(index : int):
|
||||
editor_view.current_path = recent_paths[index]
|
||||
editor_view.node_folder_path.text = recent_paths[index]
|
||||
editor_view.refresh()
|
||||
@@ -0,0 +1 @@
|
||||
uid://1f6sthbkwbwq
|
||||
@@ -0,0 +1,191 @@
|
||||
@tool
|
||||
extends MarginContainer
|
||||
|
||||
enum {
|
||||
EDITBOX_DUPLICATE = 1,
|
||||
EDITBOX_RENAME,
|
||||
EDITBOX_DELETE,
|
||||
}
|
||||
|
||||
const TextEditingUtilsClass := preload("res://addons/resources_spreadsheet_view/text_editing_utils.gd")
|
||||
const TablesPluginSettingsClass := preload("res://addons/resources_spreadsheet_view/settings_grid.gd")
|
||||
|
||||
@onready var editor_view := $"../.."
|
||||
@onready var selection := $"../../SelectionManager"
|
||||
|
||||
@onready var editbox_node := $"Control/ColorRect/Popup"
|
||||
@onready var editbox_label : Label = editbox_node.get_node("Panel/VBoxContainer/Label")
|
||||
@onready var editbox_input : LineEdit = 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")
|
||||
)
|
||||
editbox_input.text_submitted.connect(func(_new_text): _on_editbox_accepted())
|
||||
close()
|
||||
|
||||
|
||||
func _on_grid_cells_rightclicked(cells):
|
||||
open(cells)
|
||||
|
||||
|
||||
func _on_grid_cells_selected(cells):
|
||||
open(cells, true, true)
|
||||
|
||||
|
||||
func open(cells : Array, pin_to_cell : bool = false, from_leftclick : bool = false):
|
||||
if cells.size() == 0 or (from_leftclick and !ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "context_menu_on_leftclick")):
|
||||
hide()
|
||||
cell = null
|
||||
return
|
||||
|
||||
if pin_to_cell:
|
||||
cell = selection.get_cell_node_from_position(cells[-1])
|
||||
set_deferred(&"global_position", Vector2(
|
||||
cell.global_position.x + cell.size.x,
|
||||
cell.global_position.y
|
||||
))
|
||||
|
||||
else:
|
||||
cell = null
|
||||
set_deferred(&"global_position", get_global_mouse_position() + Vector2.ONE)
|
||||
|
||||
show()
|
||||
size = Vector2.ZERO
|
||||
top_level = true
|
||||
$"Control2/Label".text = str(cells.size()) + (" Cells" if cells.size() % 10 != 1 else " Cell")
|
||||
$"GridContainer/Rename".visible = editor_view.has_row_names()
|
||||
$"GridContainer/SoloOpen".visible = editor_view.column_can_solo_open(editor_view.get_selected_column())
|
||||
|
||||
|
||||
func close():
|
||||
pass
|
||||
|
||||
|
||||
func _input(event : InputEvent):
|
||||
if !editor_view.is_visible_in_tree():
|
||||
close()
|
||||
return
|
||||
|
||||
if event is InputEventMouseButton and event.is_pressed():
|
||||
close()
|
||||
return
|
||||
|
||||
if event is InputEventKey:
|
||||
if event.is_pressed() and event.is_command_or_control_pressed():
|
||||
global_position = get_global_mouse_position() + Vector2.ONE
|
||||
if cell != null:
|
||||
global_position = Vector2(
|
||||
cell.global_position.x + cell.size.x,
|
||||
cell.global_position.y
|
||||
)
|
||||
|
||||
# Dupe
|
||||
if event.keycode == KEY_D:
|
||||
_on_Duplicate_pressed()
|
||||
return
|
||||
|
||||
# Rename
|
||||
if event.keycode == KEY_R:
|
||||
_on_Rename_pressed()
|
||||
return
|
||||
|
||||
|
||||
func _on_Duplicate_pressed():
|
||||
_show_editbox(EDITBOX_DUPLICATE)
|
||||
|
||||
|
||||
func _on_CbCopy_pressed():
|
||||
TextEditingUtilsClass.multi_copy(selection.edited_cells_text)
|
||||
|
||||
|
||||
func _on_CbPaste_pressed():
|
||||
selection.clipboard_paste()
|
||||
|
||||
|
||||
func _on_Rename_pressed():
|
||||
_show_editbox(EDITBOX_RENAME)
|
||||
|
||||
|
||||
func _on_Delete_pressed():
|
||||
_show_editbox(EDITBOX_DELETE)
|
||||
|
||||
|
||||
func _on_SoloOpen_pressed():
|
||||
var resources_to_open_unique := {}
|
||||
for x in editor_view.get_edited_cells_values():
|
||||
if x is Array:
|
||||
for y in x:
|
||||
resources_to_open_unique[y] = true
|
||||
|
||||
if x is Resource:
|
||||
resources_to_open_unique[x] = true
|
||||
|
||||
if resources_to_open_unique.size() > 0:
|
||||
editor_view.display_resources(resources_to_open_unique.keys())
|
||||
|
||||
|
||||
func _show_editbox(action):
|
||||
editbox_action = action
|
||||
match action:
|
||||
EDITBOX_DUPLICATE:
|
||||
if !editor_view.has_row_names():
|
||||
_on_editbox_accepted()
|
||||
return
|
||||
|
||||
if selection.edited_cells.size() == 1:
|
||||
editbox_label.text = "Input new row's name..."
|
||||
editbox_input.text = 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 = 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 = editor_view.get_last_selected_row()\
|
||||
.resource_path.get_file().get_basename()
|
||||
|
||||
show()
|
||||
editbox_input.grab_focus()
|
||||
editbox_input.caret_column = 999999999
|
||||
editbox_node.size = Vector2.ZERO
|
||||
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:
|
||||
editor_view.duplicate_selected_rows(editbox_input.text)
|
||||
|
||||
EDITBOX_RENAME:
|
||||
editor_view.rename_row(editor_view.get_last_selected_row(), editbox_input.text)
|
||||
|
||||
EDITBOX_DELETE:
|
||||
editor_view.delete_selected_rows()
|
||||
|
||||
_on_editbox_closed()
|
||||
@@ -0,0 +1 @@
|
||||
uid://dhsfesyigu88y
|
||||
@@ -0,0 +1,191 @@
|
||||
[gd_scene load_steps=7 format=3 uid="uid://b51hnttsie7k5"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://dyxdmrhopt5i0" path="res://addons/resources_spreadsheet_view/editor_icon_button.gd" id="1"]
|
||||
[ext_resource type="Script" uid="uid://dhsfesyigu88y" path="res://addons/resources_spreadsheet_view/main_screen/selection_actions.gd" id="1_qv6ov"]
|
||||
[ext_resource type="Script" uid="uid://duxju2vxsk50o" path="res://addons/resources_spreadsheet_view/editor_color_setter.gd" id="2_a4ihj"]
|
||||
|
||||
[sub_resource type="Image" id="Image_qja2v"]
|
||||
data = {
|
||||
"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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"]
|
||||
image = SubResource("Image_qja2v")
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_r2l2b"]
|
||||
content_margin_left = 4.0
|
||||
content_margin_top = 4.0
|
||||
content_margin_right = 4.0
|
||||
content_margin_bottom = 4.0
|
||||
bg_color = Color(1, 0.365, 0.365, 1)
|
||||
draw_center = false
|
||||
border_width_left = 2
|
||||
border_width_top = 2
|
||||
border_width_right = 2
|
||||
border_width_bottom = 2
|
||||
corner_detail = 1
|
||||
|
||||
[node name="SelectionActions" type="MarginContainer"]
|
||||
offset_right = 80.0
|
||||
offset_bottom = 52.0
|
||||
size_flags_horizontal = 9
|
||||
mouse_filter = 2
|
||||
script = ExtResource("1_qv6ov")
|
||||
|
||||
[node name="Control2" type="Panel" parent="."]
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="ColorRect" type="ColorRect" parent="Control2"]
|
||||
show_behind_parent = true
|
||||
layout_mode = 0
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="ColorRect2" type="ColorRect" parent="Control2"]
|
||||
modulate = Color(0, 0, 0, 1)
|
||||
show_behind_parent = true
|
||||
layout_mode = 1
|
||||
anchors_preset = 9
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -2.0
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
script = ExtResource("2_a4ihj")
|
||||
|
||||
[node name="Label" type="Label" parent="Control2"]
|
||||
layout_mode = 0
|
||||
offset_top = -26.0
|
||||
offset_right = 57.0
|
||||
text = "Actions"
|
||||
vertical_alignment = 2
|
||||
|
||||
[node name="ColorRect3" type="Panel" parent="Control2/Label"]
|
||||
show_behind_parent = true
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -2.0
|
||||
offset_top = 2.0
|
||||
offset_right = 2.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="GridContainer" type="GridContainer" parent="."]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 9
|
||||
size_flags_vertical = 9
|
||||
mouse_filter = 2
|
||||
columns = 3
|
||||
|
||||
[node name="Duplicate" type="Button" parent="GridContainer"]
|
||||
layout_mode = 2
|
||||
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"]
|
||||
layout_mode = 2
|
||||
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"]
|
||||
layout_mode = 2
|
||||
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"]
|
||||
layout_mode = 2
|
||||
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"]
|
||||
layout_mode = 2
|
||||
tooltip_text = "DELETE Selected Rows"
|
||||
mouse_filter = 1
|
||||
icon = SubResource("2")
|
||||
script = ExtResource("1")
|
||||
icon_name = "Remove"
|
||||
|
||||
[node name="SoloOpen" type="Button" parent="GridContainer"]
|
||||
layout_mode = 2
|
||||
tooltip_text = "Open selected cells as new table"
|
||||
mouse_filter = 1
|
||||
icon = SubResource("2")
|
||||
script = ExtResource("1")
|
||||
icon_name = "Object"
|
||||
|
||||
[node name="Control" type="Control" parent="."]
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="ColorRect" type="ColorRect" parent="Control"]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_right = -80.0
|
||||
offset_bottom = -52.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
color = Color(0, 0, 0, 0.498039)
|
||||
|
||||
[node name="Popup" type="MarginContainer" parent="Control/ColorRect"]
|
||||
layout_mode = 0
|
||||
offset_top = 100.0
|
||||
offset_right = 140.0
|
||||
offset_bottom = 196.0
|
||||
|
||||
[node name="Panel" type="PanelContainer" parent="Control/ColorRect/Popup"]
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_r2l2b")
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="Control/ColorRect/Popup/Panel"]
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="Label" type="Label" parent="Control/ColorRect/Popup/Panel/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Input new name..."
|
||||
|
||||
[node name="LineEdit" type="LineEdit" parent="Control/ColorRect/Popup/Panel/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Control/ColorRect/Popup/Panel/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
alignment = 1
|
||||
|
||||
[node name="Button" type="Button" parent="Control/ColorRect/Popup/Panel/VBoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "OK"
|
||||
|
||||
[node name="Button2" type="Button" parent="Control/ColorRect/Popup/Panel/VBoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
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="GridContainer/SoloOpen" to="." method="_on_SoloOpen_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"]
|
||||
@@ -0,0 +1,321 @@
|
||||
@tool
|
||||
extends Control
|
||||
|
||||
signal cells_selected(cells_positions)
|
||||
signal cells_rightclicked(cells_positions)
|
||||
|
||||
const EditorViewClass := preload("res://addons/resources_spreadsheet_view/editor_view.gd")
|
||||
const TextEditingUtilsClass := preload("res://addons/resources_spreadsheet_view/text_editing_utils.gd")
|
||||
|
||||
@export var cell_editor_classes : Array[Script] = []
|
||||
|
||||
@onready var node_property_editors : VBoxContainer = $"../HeaderContentSplit/MarginContainer/FooterContentSplit/Footer/PropertyEditors"
|
||||
@onready var scrollbar : ScrollContainer = $"../HeaderContentSplit/MarginContainer/FooterContentSplit/Panel/Scroll"
|
||||
|
||||
@onready var editor_view : EditorViewClass = get_parent()
|
||||
|
||||
var edited_cells : Array = []
|
||||
var edited_cells_text : Array = []
|
||||
var edit_cursor_positions : Array[int] = []
|
||||
|
||||
var all_cell_editors : Array = []
|
||||
var column_editors : Array[Object] = []
|
||||
var inspector_resource : Resource
|
||||
|
||||
|
||||
func _ready():
|
||||
# Load cell editors and instantiate them
|
||||
for x in cell_editor_classes:
|
||||
all_cell_editors.append(x.new())
|
||||
all_cell_editors[all_cell_editors.size() - 1].hint_strings_array = editor_view.column_hint_strings
|
||||
|
||||
get_parent()\
|
||||
.editor_interface\
|
||||
.get_inspector()\
|
||||
.property_edited\
|
||||
.connect(_on_inspector_property_edited)
|
||||
|
||||
scrollbar.get_h_scroll_bar().value_changed.connect(queue_redraw.unbind(1), CONNECT_DEFERRED)
|
||||
scrollbar.get_v_scroll_bar().value_changed.connect(queue_redraw.unbind(1), CONNECT_DEFERRED)
|
||||
|
||||
if ProjectSettings.get_setting(editor_view.TablesPluginSettingsClass.PREFIX + "fold_docks", false):
|
||||
for x in node_property_editors.get_children():
|
||||
x.resize_set_hidden(true)
|
||||
|
||||
|
||||
func _draw():
|
||||
if edited_cells.size() == 0 or edit_cursor_positions.size() != edited_cells.size() or !column_editors[edited_cells[0].x].is_text():
|
||||
return
|
||||
|
||||
var font := get_theme_font(&"font", &"Label")
|
||||
var font_size := get_theme_font_size(&"font", &"Label")
|
||||
var caret_color := get_theme_color(&"caret_color", &"LineEdit")
|
||||
var label_padding_left := 2.0
|
||||
var newline_char := 10
|
||||
for i in edited_cells.size():
|
||||
var cell : Control = get_cell_node_from_position(edited_cells[i])
|
||||
var caret_rect := Rect2()
|
||||
if cell.has_method(&"get_character_bounds"):
|
||||
if edited_cells_text[i].length() == edit_cursor_positions[i]:
|
||||
caret_rect = cell.get_character_bounds(edit_cursor_positions[i] - 1)
|
||||
caret_rect.position.x += caret_rect.size.x
|
||||
|
||||
else:
|
||||
caret_rect = cell.get_character_bounds(edit_cursor_positions[i])
|
||||
|
||||
caret_rect.size.x = 1.0
|
||||
|
||||
else:
|
||||
caret_rect = TextEditingUtilsClass.get_caret_rect(edited_cells_text[i], edit_cursor_positions[i], font, font_size, label_padding_left, 1.0)
|
||||
|
||||
caret_rect.position += cell.global_position - global_position
|
||||
draw_rect(caret_rect, caret_color)
|
||||
|
||||
|
||||
func initialize_editors(column_values, column_types, column_hints):
|
||||
_set_visible_selected(false)
|
||||
column_editors.clear()
|
||||
for i in column_values.size():
|
||||
for x in all_cell_editors:
|
||||
if x.can_edit_value(column_values[i], column_types[i], column_hints[i], i):
|
||||
column_editors.append(x)
|
||||
break
|
||||
|
||||
|
||||
func deselect_all_cells():
|
||||
_set_visible_selected(false)
|
||||
edited_cells.clear()
|
||||
edited_cells_text.clear()
|
||||
edit_cursor_positions.clear()
|
||||
_selection_changed()
|
||||
|
||||
|
||||
func deselect_cell(cell : Vector2i):
|
||||
var idx := edited_cells.find(cell)
|
||||
if idx == -1: return
|
||||
|
||||
edited_cells.remove_at(idx)
|
||||
if edited_cells_text.size() != 0:
|
||||
edited_cells_text.remove_at(idx)
|
||||
edit_cursor_positions.remove_at(idx)
|
||||
|
||||
var cell_node := get_cell_node_from_position(cell)
|
||||
if cell_node != null:
|
||||
column_editors[get_cell_column(cell)].set_selected(cell_node, false)
|
||||
|
||||
_selection_changed()
|
||||
|
||||
|
||||
func select_cell(cell : Vector2i):
|
||||
var column_index := get_cell_column(cell)
|
||||
if edited_cells.size() == 0 or edited_cells[0].x == cell.x:
|
||||
_add_cell_to_selection(cell)
|
||||
_try_open_docks(cell)
|
||||
inspector_resource = editor_view.rows[get_cell_row(cell)]
|
||||
editor_view.editor_plugin.get_editor_interface().edit_resource(inspector_resource)
|
||||
|
||||
_selection_changed()
|
||||
|
||||
|
||||
func select_cells(cells : Array):
|
||||
var last_selectible := Vector2i(-1, -1)
|
||||
var started_empty := edited_cells.size() == 0
|
||||
for x in cells:
|
||||
if started_empty or edited_cells[0].x != x.x:
|
||||
_add_cell_to_selection(x)
|
||||
if get_cell_node_from_position(x) != null:
|
||||
last_selectible = x
|
||||
|
||||
if last_selectible != Vector2i(-1, -1):
|
||||
select_cell(last_selectible)
|
||||
|
||||
|
||||
func select_cells_to(cell : Vector2i):
|
||||
var column_index := get_cell_column(cell)
|
||||
if edited_cells.size() == 0 or column_index != get_cell_column(edited_cells[-1]):
|
||||
return
|
||||
|
||||
var row_start := get_cell_row(edited_cells[-1])
|
||||
var row_end := get_cell_row(cell)
|
||||
var edge_shift := -1 if row_start > row_end else 1
|
||||
row_start += edge_shift
|
||||
row_end += edge_shift
|
||||
|
||||
var column_editor := column_editors[column_index]
|
||||
for i in range(row_start, row_end, edge_shift):
|
||||
var cur_cell := Vector2i(column_index, i)
|
||||
var cur_cell_node := get_cell_node_from_position(cur_cell)
|
||||
if cur_cell not in edited_cells:
|
||||
edited_cells.append(cur_cell)
|
||||
|
||||
var cur_cell_value = editor_view.io.get_value(editor_view.rows[cur_cell.y], editor_view.columns[cur_cell.x])
|
||||
var cur_cell_text : String = column_editor.to_text(cur_cell_value)
|
||||
edited_cells_text.append(cur_cell_text)
|
||||
edit_cursor_positions.append(cur_cell_text.length())
|
||||
|
||||
if cur_cell_node == null or !cur_cell_node.visible or cur_cell_node.mouse_filter == MOUSE_FILTER_IGNORE:
|
||||
# When showing several classes, empty cells will be non-selectable.
|
||||
continue
|
||||
|
||||
column_editors[column_index].set_selected(cur_cell_node, true)
|
||||
|
||||
_selection_changed()
|
||||
|
||||
|
||||
func rightclick_cells():
|
||||
cells_rightclicked.emit(edited_cells)
|
||||
|
||||
|
||||
func is_cell_node_selected(cell : Control) -> bool:
|
||||
return get_cell_node_position(cell) in edited_cells
|
||||
|
||||
|
||||
func is_cell_selected(cell : Vector2i) -> bool:
|
||||
return cell in edited_cells
|
||||
|
||||
|
||||
func can_select_cell(cell : Vector2i) -> bool:
|
||||
if edited_cells.size() == 0:
|
||||
return true
|
||||
|
||||
if (
|
||||
get_cell_column(cell)
|
||||
!= get_cell_column(edited_cells[0])
|
||||
):
|
||||
return false
|
||||
|
||||
return !cell in edited_cells
|
||||
|
||||
|
||||
func get_cell_node_from_position(cell_pos : Vector2i) -> Control:
|
||||
var cell_index := (cell_pos.y - editor_view.first_row) * editor_view.columns.size() + cell_pos.x
|
||||
if cell_index < 0 or cell_index >= editor_view.node_table_root.get_child_count():
|
||||
return null
|
||||
|
||||
return editor_view.node_table_root.get_child(cell_index)
|
||||
|
||||
|
||||
func get_cell_node_position(cell : Control) -> Vector2i:
|
||||
var col_count := editor_view.columns.size()
|
||||
var cell_index := cell.get_index()
|
||||
return Vector2i(cell_index % col_count, cell_index / col_count + editor_view.first_row)
|
||||
|
||||
|
||||
func get_cell_column(cell : Vector2i) -> int:
|
||||
return cell.x
|
||||
|
||||
|
||||
func get_cell_row(cell : Vector2i) -> int:
|
||||
return cell.y
|
||||
|
||||
|
||||
func get_edited_rows() -> Array[int]:
|
||||
var rows : Array[int] = []
|
||||
rows.resize(edited_cells.size())
|
||||
for i in rows.size():
|
||||
rows[i] = get_cell_row(edited_cells[i])
|
||||
|
||||
return rows
|
||||
|
||||
|
||||
func clipboard_paste():
|
||||
if column_editors[edited_cells[0].x].is_text():
|
||||
editor_view.set_edited_cells_values(
|
||||
TextEditingUtilsClass.multi_paste(
|
||||
edited_cells_text,
|
||||
edit_cursor_positions,
|
||||
)
|
||||
)
|
||||
|
||||
elif DisplayServer.clipboard_has():
|
||||
var values := []
|
||||
values.resize(edited_cells.size())
|
||||
var pasted_lines := DisplayServer.clipboard_get().replace("\r", "").split("\n")
|
||||
var paste_each_line := pasted_lines.size() == values.size()
|
||||
|
||||
for i in values.size():
|
||||
values[i] = str_to_var(
|
||||
pasted_lines[i] if paste_each_line else DisplayServer.clipboard_get()
|
||||
)
|
||||
|
||||
editor_view.set_edited_cells_values(values)
|
||||
|
||||
|
||||
func _selection_changed():
|
||||
queue_redraw()
|
||||
cells_selected.emit(edited_cells)
|
||||
|
||||
|
||||
func _set_visible_selected(state : bool):
|
||||
for x in edited_cells:
|
||||
var cell_node := get_cell_node_from_position(x)
|
||||
if cell_node != null:
|
||||
column_editors[get_cell_column(x)].set_selected(cell_node, state)
|
||||
|
||||
|
||||
func _add_cell_to_selection(cell : Vector2i):
|
||||
if !edited_cells.has(cell):
|
||||
edited_cells.append(cell)
|
||||
|
||||
var column_editor := column_editors[get_cell_column(cell)]
|
||||
var cell_node := get_cell_node_from_position(cell)
|
||||
if cell_node != null:
|
||||
column_editor.set_selected(cell_node, true)
|
||||
|
||||
var cell_value = editor_view.io.get_value(editor_view.rows[cell.y], editor_view.columns[cell.x])
|
||||
var text_value : String = column_editor.to_text(cell_value)
|
||||
edited_cells_text.append(text_value)
|
||||
edit_cursor_positions.append(text_value.length())
|
||||
|
||||
|
||||
func _update_selected_cells_text():
|
||||
if edited_cells_text.size() == 0:
|
||||
return
|
||||
|
||||
var column_editor := column_editors[get_cell_column(edited_cells[0])]
|
||||
if !column_editor.text_update_on_edit():
|
||||
return
|
||||
|
||||
for i in edited_cells.size():
|
||||
edited_cells_text[i] = column_editor.to_text(editor_view.io.get_value(
|
||||
editor_view.rows[edited_cells[i].y],
|
||||
editor_view.columns[edited_cells[i].x],
|
||||
))
|
||||
edit_cursor_positions[i] = edited_cells_text[i].length()
|
||||
|
||||
|
||||
func _try_open_docks(cell : Vector2i):
|
||||
var column_index := get_cell_column(cell)
|
||||
var row = editor_view.rows[get_cell_row(cell)]
|
||||
var column := editor_view.columns[column_index]
|
||||
var type := editor_view.column_types[column_index]
|
||||
var hints := editor_view.column_hints[column_index]
|
||||
|
||||
for x in node_property_editors.get_children():
|
||||
x.visible = x.try_edit_value(editor_view.io.get_value(row, column), type, hints)
|
||||
x.get_node(x.path_property_name).text = column
|
||||
|
||||
|
||||
func _on_inspector_property_edited(property : StringName):
|
||||
if !editor_view.is_visible_in_tree(): return
|
||||
if inspector_resource != editor_view.editor_plugin.get_editor_interface().get_inspector().get_edited_object():
|
||||
return
|
||||
|
||||
if editor_view.columns[get_cell_column(edited_cells[0])] != property:
|
||||
var columns := editor_view.columns
|
||||
var previously_edited := edited_cells.duplicate()
|
||||
var new_column := columns.find(property)
|
||||
deselect_all_cells()
|
||||
for i in previously_edited.size():
|
||||
_add_cell_to_selection(Vector2i(new_column, previously_edited[i].y))
|
||||
|
||||
var new_value = inspector_resource[property]
|
||||
var values := []
|
||||
values.resize(edited_cells.size())
|
||||
values.fill(new_value)
|
||||
if new_value is Resource and new_value.resource_path == "":
|
||||
for i in values.size():
|
||||
values[i] = new_value.duplicate()
|
||||
|
||||
editor_view.set_edited_cells_values.call_deferred(values)
|
||||
_try_open_docks(edited_cells[0])
|
||||
@@ -0,0 +1 @@
|
||||
uid://ce5uido7e30hd
|
||||
@@ -0,0 +1,72 @@
|
||||
@tool
|
||||
extends HBoxContainer
|
||||
|
||||
var manager : Control
|
||||
|
||||
|
||||
func set_label(label : String):
|
||||
$"Button".text = label.capitalize()
|
||||
$"Button".tooltip_text = label + "\nClick to sort."
|
||||
|
||||
|
||||
func _ready():
|
||||
$"Button".gui_input.connect(_on_main_gui_input)
|
||||
$"Button2".about_to_popup.connect(_on_about_to_popup)
|
||||
$"Button2".get_popup().id_pressed.connect(_on_list_id_pressed)
|
||||
|
||||
|
||||
func _on_about_to_popup():
|
||||
var menu_popup : PopupMenu = $"Button2".get_popup()
|
||||
menu_popup.clear()
|
||||
menu_popup.add_item("Select All", 0)
|
||||
menu_popup.add_item("Hide", 1)
|
||||
|
||||
if !manager.editor_view.column_can_solo_open(get_index()):
|
||||
menu_popup.add_item("(not a Resource property)", 2)
|
||||
menu_popup.set_item_disabled(2, true)
|
||||
menu_popup.add_separator("", 3)
|
||||
|
||||
else:
|
||||
menu_popup.add_item("Open Sub-Resources of Column", 2)
|
||||
|
||||
if manager.editor_view.get_edited_cells_values().size() == 0 or manager.editor_view.get_selected_column() != get_index():
|
||||
menu_popup.add_item("(none selected)", 3)
|
||||
menu_popup.set_item_disabled(3, true)
|
||||
|
||||
else:
|
||||
menu_popup.add_item("Open Sub-Resources in Selection", 3)
|
||||
|
||||
|
||||
func _on_main_gui_input(event : InputEvent):
|
||||
if event is InputEventMouseButton and event.pressed:
|
||||
var popup : Popup = $"Button2".get_popup()
|
||||
if event.button_index == MOUSE_BUTTON_RIGHT:
|
||||
_on_about_to_popup()
|
||||
popup.visible = !popup.visible
|
||||
popup.size = Vector2.ZERO
|
||||
popup.position = Vector2i(get_global_mouse_position()) + get_viewport().position
|
||||
|
||||
else:
|
||||
popup.visible = false
|
||||
|
||||
|
||||
func _on_list_id_pressed(id : int):
|
||||
match id:
|
||||
0:
|
||||
manager.select_column(get_index())
|
||||
1:
|
||||
manager.hide_column(get_index())
|
||||
2:
|
||||
manager.editor_view.column_solo_open(get_index())
|
||||
3:
|
||||
var resources_to_open_unique := {}
|
||||
for x in manager.editor_view.get_edited_cells_values():
|
||||
if x is Array:
|
||||
for y in x:
|
||||
resources_to_open_unique[y] = true
|
||||
|
||||
if x is Resource:
|
||||
resources_to_open_unique[x] = true
|
||||
|
||||
if resources_to_open_unique.size() > 0:
|
||||
manager.editor_view.display_resources(resources_to_open_unique.keys())
|
||||
@@ -0,0 +1 @@
|
||||
uid://dxcn2ds2d4qcx
|
||||
@@ -0,0 +1,23 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://d1s6oihqedvo5"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://dxcn2ds2d4qcx" path="res://addons/resources_spreadsheet_view/main_screen/table_header.gd" id="1_5fd1m"]
|
||||
[ext_resource type="Script" uid="uid://dyxdmrhopt5i0" path="res://addons/resources_spreadsheet_view/editor_icon_button.gd" id="2_0ymob"]
|
||||
|
||||
[node name="Header" type="HBoxContainer"]
|
||||
offset_right = 179.0
|
||||
offset_bottom = 31.0
|
||||
size_flags_horizontal = 3
|
||||
script = ExtResource("1_5fd1m")
|
||||
|
||||
[node name="Button" type="Button" parent="."]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 0
|
||||
text = "resource_name"
|
||||
clip_text = true
|
||||
|
||||
[node name="Button2" type="MenuButton" parent="."]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 9
|
||||
script = ExtResource("2_0ymob")
|
||||
icon_name = "ArrowDown"
|
||||
118
addons/resources_spreadsheet_view/main_screen/table_pages.gd
Normal file
118
addons/resources_spreadsheet_view/main_screen/table_pages.gd
Normal file
@@ -0,0 +1,118 @@
|
||||
@tool
|
||||
extends HBoxContainer
|
||||
|
||||
@onready var node_editor_view_root : Control = $"../../../.."
|
||||
|
||||
var rows_per_page := 50
|
||||
var current_page := 0
|
||||
|
||||
|
||||
func update_page_count(array : Array) -> int:
|
||||
var page_count : int = (node_editor_view_root.rows.size() - 1) / rows_per_page + 1
|
||||
node_editor_view_root.first_row = min(current_page, page_count) * rows_per_page
|
||||
node_editor_view_root.last_row = min(node_editor_view_root.first_row + rows_per_page, array.size())
|
||||
return page_count
|
||||
|
||||
|
||||
func _on_grid_updated():
|
||||
if node_editor_view_root.rows.size() == 0:
|
||||
return
|
||||
|
||||
visible = true
|
||||
var page_count := update_page_count(node_editor_view_root.rows)
|
||||
var pagelist_node := $"Scroll/Pagelist"
|
||||
for x in pagelist_node.get_children():
|
||||
x.queue_free()
|
||||
|
||||
var button_group := ButtonGroup.new()
|
||||
var btns := []
|
||||
btns.resize(page_count)
|
||||
for i in page_count:
|
||||
var btn := Button.new()
|
||||
btns[i] = btn
|
||||
btn.toggle_mode = true
|
||||
btn.button_group = button_group
|
||||
btn.text = str(i + 1)
|
||||
btn.pressed.connect(_on_button_pressed.bind(btn))
|
||||
btn.size_flags_vertical = SIZE_SHRINK_CENTER
|
||||
pagelist_node.add_child(btn)
|
||||
|
||||
var pagelist_line := HSeparator.new()
|
||||
pagelist_line.size_flags_horizontal = SIZE_EXPAND_FILL
|
||||
pagelist_node.add_child(pagelist_line)
|
||||
btns[current_page].button_pressed = true
|
||||
|
||||
var sort_property : StringName = node_editor_view_root.sorting_by
|
||||
if sort_property == "": sort_property = "resource_path"
|
||||
var sort_type : int = node_editor_view_root.column_types[node_editor_view_root.columns.find(sort_property)]
|
||||
var property_values := []
|
||||
property_values.resize(page_count)
|
||||
if(node_editor_view_root.rows.size() == 0):
|
||||
return
|
||||
|
||||
for i in page_count:
|
||||
property_values[i] = node_editor_view_root.rows[i * rows_per_page].get(sort_property)
|
||||
|
||||
if sort_type == TYPE_FLOAT or sort_type == TYPE_INT:
|
||||
for i in page_count:
|
||||
btns[i].text = str(property_values[i])
|
||||
|
||||
elif sort_type == TYPE_COLOR:
|
||||
for i in page_count:
|
||||
btns[i].self_modulate = property_values[i] * 0.75 + Color(0.25, 0.25, 0.25, 1.0)
|
||||
|
||||
elif sort_type == TYPE_STRING:
|
||||
var strings := []
|
||||
strings.resize(page_count)
|
||||
for i in page_count:
|
||||
strings[i] = property_values[i].get_file()
|
||||
if strings[i] == "":
|
||||
strings[i] = str(i)
|
||||
|
||||
_fill_buttons_with_prefixes(btns, strings, page_count)
|
||||
|
||||
elif sort_type == TYPE_OBJECT:
|
||||
var strings := []
|
||||
strings.resize(page_count + 1)
|
||||
for i in page_count:
|
||||
if is_instance_valid(property_values[i]):
|
||||
strings[i] = property_values[i].resource_path.get_file()
|
||||
|
||||
_fill_buttons_with_prefixes(btns, strings, page_count)
|
||||
|
||||
|
||||
func _fill_buttons_with_prefixes(btns : Array, strings : Array, page_count : int):
|
||||
for i in page_count:
|
||||
if strings[i] == null:
|
||||
continue
|
||||
|
||||
if i == 0:
|
||||
btns[0].text = strings[0][0]
|
||||
continue
|
||||
|
||||
for j in strings[i].length():
|
||||
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
|
||||
|
||||
for i in page_count - 1:
|
||||
btns[i].text = btns[i].text + "-" + btns[i + 1].text
|
||||
|
||||
btns[page_count - 1].text += "-[End]"
|
||||
|
||||
|
||||
func _on_button_pressed(button):
|
||||
button.button_pressed = true
|
||||
current_page = button.get_index()
|
||||
_update_view()
|
||||
|
||||
|
||||
func _on_LineEdit_value_changed(value):
|
||||
rows_per_page = value
|
||||
current_page = 0
|
||||
_update_view()
|
||||
|
||||
|
||||
func _update_view():
|
||||
node_editor_view_root.refresh(false)
|
||||
@@ -0,0 +1 @@
|
||||
uid://dc76nawgefkbh
|
||||
Reference in New Issue
Block a user