diff --git a/addons/resources_speadsheet_view/editor_view.gd b/addons/resources_speadsheet_view/editor_view.gd index c56e8a4..1fe9c91 100644 --- a/addons/resources_speadsheet_view/editor_view.gd +++ b/addons/resources_speadsheet_view/editor_view.gd @@ -40,7 +40,7 @@ var edited_cells_text := [] var edit_cursor_positions := [] var inspector_resource : Resource var search_cond : Reference -var io := SpreadsheetEditFormatTres.new() +var io : Reference var hidden_columns := {} var first_row := 0 @@ -56,8 +56,6 @@ func _ready(): get_node(path_hide_columns_button).get_popup()\ .connect("id_pressed", self, "_on_VisibleCols_id_pressed") - io.editor_view = self - # Load saved recent paths var file := File.new() if file.file_exists(save_data_path): @@ -95,9 +93,9 @@ func _on_filesystem_changed(): func display_folder(folderpath : String, sort_by : String = "", sort_reverse : bool = false, force_rebuild : bool = false): - if folderpath == "": return # Root folder resources tend to have MANY properties. + if folderpath == "": return # Root folder resources tend to have MANY properties.W $"HeaderContentSplit/MarginContainer/FooterContentSplit/Panel/Label".visible = false - if folderpath.ends_with(".tres"): + if folderpath.ends_with(".tres") && !folderpath.ends_with(SpreadsheetImport.SUFFIX): folderpath = folderpath.get_base_dir() + "/" if search_cond == null: @@ -118,7 +116,7 @@ func display_folder(folderpath : String, sort_by : String = "", sort_reverse : b _update_hidden_columns() _update_column_sizes() - yield(get_tree(), "idle_frame") + yield(get_tree().create_timer(0.5), "timeout") if get_node(path_table_root).get_child_count() == 0: display_folder(folderpath, sort_by, sort_reverse, force_rebuild) @@ -130,8 +128,35 @@ func refresh(force_rebuild : bool = true): display_folder(current_path, sorting_by, sorting_reverse, force_rebuild) -func _load_resources_from_folder(folderpath : String, sort_by : String, sort_reverse : bool): - rows = io.import_from_path(folderpath, funcref(self, "insert_row_sorted"), sort_by, sort_reverse) +func _load_resources_from_folder(path : String, sort_by : String, sort_reverse : bool): + if path.ends_with("/"): + io = SpreadsheetEditFormatTres.new() + + else: + io = load(path).view_script.new() + + io.editor_view = self + rows = io.import_from_path(path, funcref(self, "insert_row_sorted"), sort_by, sort_reverse) + + +func fill_property_data(res): + columns.clear() + column_types.clear() + column_hints.clear() + column_hint_strings.clear() + column_editors.clear() + var column_index = -1 + for x in res.get_property_list(): + if x["usage"] & PROPERTY_USAGE_EDITOR != 0 and x["name"] != "script": + column_index += 1 + columns.append(x["name"]) + column_types.append(x["type"]) + column_hints.append(x["hint"]) + column_hint_strings.append(x["hint_string"].split(",")) + for y in all_cell_editors: + if y.can_edit_value(io.get_value(res, x["name"]), x["type"], x["hint"], column_index): + column_editors.append(y) + break func insert_row_sorted(res : Resource, rows : Array, sort_by : String, sort_reverse : bool): @@ -348,10 +373,10 @@ func _on_RecentPaths_item_selected(index : int): 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 _on_FileDialog_dir_selected(path : String): + get_node(path_folder_path).text = path + add_path_to_recent(path) + display_folder(path) func deselect_all_cells(): @@ -687,7 +712,11 @@ func _move_selection_on_grid(move_h : int, move_v : int): func _update_resources(update_rows : Array, update_cells : Array, update_column : int, values : Array): + var saved_indices = [] + saved_indices.resize(update_rows.size()) for i in update_rows.size(): + var row = _get_cell_row(update_cells[i]) + saved_indices[i] = row column_editors[update_column].set_value(update_cells[i], values[i]) values[i] = _try_convert(values[i], column_types[update_column]) if values[i] == null: @@ -696,9 +725,9 @@ func _update_resources(update_rows : Array, update_cells : Array, update_column io.set_value( update_rows[i], columns[update_column], - convert(values[i], column_types[update_column]) + values[i], + row ) - io.save_entry(rows, i) if column_types[update_column] == TYPE_COLOR: for j in columns.size() - update_column: if j != 0 and column_types[j + update_column] == TYPE_COLOR: @@ -711,6 +740,7 @@ func _update_resources(update_rows : Array, update_cells : Array, update_column values[i] ) + io.save_entries(rows, saved_indices) _update_column_sizes() diff --git a/addons/resources_speadsheet_view/editor_view.tscn b/addons/resources_speadsheet_view/editor_view.tscn index ff80765..b0d83b7 100644 --- a/addons/resources_speadsheet_view/editor_view.tscn +++ b/addons/resources_speadsheet_view/editor_view.tscn @@ -535,7 +535,8 @@ margin_bottom = 192.0 rect_min_size = Vector2( 150, 52.5 ) window_title = "Open a Folder" mode_overrides_title = false -mode = 2 +mode = 3 +filters = PoolStringArray( "*_spreadsheet_import.tres" ) [node name="FileDialogText" type="FileDialog" parent="Control"] anchor_left = 0.5 @@ -753,4 +754,5 @@ text = "Enable" [connection signal="text_entered" from="HeaderContentSplit/MarginContainer/FooterContentSplit/Footer/Search/SearchCond" to="." method="_on_SearchCond_text_entered"] [connection signal="text_entered" from="HeaderContentSplit/MarginContainer/FooterContentSplit/Footer/Search/ProcessExpr" to="." method="_on_ProcessExpr_text_entered"] [connection signal="dir_selected" from="Control/FileDialog" to="." method="_on_FileDialog_dir_selected"] +[connection signal="file_selected" from="Control/FileDialog" to="." method="_on_FileDialog_dir_selected"] [connection signal="file_selected" from="Control/FileDialogText" to="Control/ImportExport" method="_on_FileDialogText_file_selected"] diff --git a/addons/resources_speadsheet_view/import_export/formats_edit/edit_base.gd b/addons/resources_speadsheet_view/import_export/formats_edit/edit_base.gd index 2ee04a1..28420c1 100644 --- a/addons/resources_speadsheet_view/import_export/formats_edit/edit_base.gd +++ b/addons/resources_speadsheet_view/import_export/formats_edit/edit_base.gd @@ -7,12 +7,12 @@ var editor_view : Control func get_value(entry, key : String): pass -## Override to define writing behaviour. This is NOT supposed to save - use `save_entry`. -func set_value(entry, key : String, value): +## Override to define writing behaviour. This is NOT supposed to save - use `save_entries`. +func set_value(entry, key : String, value, index : int): pass ## Override to define how the data gets saved. -func save_entry(all_entries : Array, index : int): +func save_entries(all_entries : Array, indices : Array): pass ## Override to allow editing rows from the Inspector. diff --git a/addons/resources_speadsheet_view/import_export/formats_edit/edit_csv.gd b/addons/resources_speadsheet_view/import_export/formats_edit/edit_csv.gd new file mode 100644 index 0000000..cedf105 --- /dev/null +++ b/addons/resources_speadsheet_view/import_export/formats_edit/edit_csv.gd @@ -0,0 +1,71 @@ +class_name SpreadsheetEditFormatCsv +extends SpreadsheetEditFormatTres + +var import_data +var csv_rows = [] +var resource_original_positions = {} +var timer : SceneTreeTimer + + +func get_value(entry, key : String): + return entry.get(key) + + +func set_value(entry, key : String, value, index : int): + entry.set(key, value) + csv_rows[resource_original_positions[entry]] = import_data.resource_to_strings(entry) + + +func save_entries(all_entries : Array, indices : Array, repeat : bool = true): + if timer == null || timer.time_left <= 0.0: + var file = File.new() + file.open(import_data.edited_path, File.WRITE) + if import_data.remove_first_row: + var names = [] + names.resize(import_data.prop_names.size()) + for i in names.size(): + names[i] = TextEditingUtils.string_snake_to_naming_case(import_data.prop_names[i]) + + file.store_csv_line(names, import_data.delimeter) + + for x in csv_rows: + file.store_csv_line(x, import_data.delimeter) + + file.close() + if repeat: + timer = editor_view.get_tree().create_timer(5.0) + timer.connect("timeout", self, "save_entries", [all_entries, indices, false]) + + +func create_resource(entry) -> Resource: + return entry + + +func import_from_path(path : String, insert_func : FuncRef, sort_by : String, sort_reverse : bool = false) -> Array: + import_data = load(path) + var file = File.new() + file.open(import_data.edited_path, File.READ) + + var line + var first = true + csv_rows = [] + while !file.eof_reached(): + line = file.get_csv_line(import_data.delimeter) + if first && import_data.remove_first_row: + line = " " + first = false + continue + + if csv_rows.size() == 0 || line.size() == csv_rows[0].size(): + csv_rows.append(line) + + var rows := [] + var res : Resource + resource_original_positions.clear() + for i in csv_rows.size(): + res = import_data.strings_to_resource(csv_rows[i]) + insert_func.call_func(res, rows, sort_by, sort_reverse) + resource_original_positions[res] = i + + editor_view.fill_property_data(rows[0]) + return rows diff --git a/addons/resources_speadsheet_view/import_export/formats_edit/edit_tres.gd b/addons/resources_speadsheet_view/import_export/formats_edit/edit_tres.gd index 2b8c603..5c09f68 100644 --- a/addons/resources_speadsheet_view/import_export/formats_edit/edit_tres.gd +++ b/addons/resources_speadsheet_view/import_export/formats_edit/edit_tres.gd @@ -6,12 +6,13 @@ func get_value(entry, key : String): return entry.get(key) -func set_value(entry, key : String, value): +func set_value(entry, key : String, value, index : int): entry.set(key, value) -func save_entry(all_entries : Array, index : int): - ResourceSaver.save(all_entries[index].resource_path, all_entries[index]) +func save_entries(all_entries : Array, indices : Array): + for x in indices: + ResourceSaver.save(all_entries[x].resource_path, all_entries[x]) func create_resource(entry) -> Resource: @@ -35,24 +36,7 @@ func import_from_path(folderpath : String, insert_func : FuncRef, sort_by : Stri filepath = folderpath + filepath res = load(filepath) if !is_instance_valid(cur_dir_script): - editor_view.columns.clear() - editor_view.column_types.clear() - editor_view.column_hints.clear() - editor_view.column_hint_strings.clear() - editor_view.column_editors.clear() - var column_index = -1 - for x in res.get_property_list(): - if x["usage"] & PROPERTY_USAGE_EDITOR != 0 and x["name"] != "script": - column_index += 1 - editor_view.columns.append(x["name"]) - editor_view.column_types.append(x["type"]) - editor_view.column_hints.append(x["hint"]) - editor_view.column_hint_strings.append(x["hint_string"].split(",")) - for y in editor_view.all_cell_editors: - if y.can_edit_value(get_value(res, x["name"]), x["type"], x["hint"], column_index): - editor_view.column_editors.append(y) - break - + editor_view.fill_property_data(res) cur_dir_script = res.get_script() if !(sort_by in res): sort_by = "resource_path" diff --git a/addons/resources_speadsheet_view/import_export/import_export_dialog.gd b/addons/resources_speadsheet_view/import_export/import_export_dialog.gd index 95d1a31..5c8b6b0 100644 --- a/addons/resources_speadsheet_view/import_export/import_export_dialog.gd +++ b/addons/resources_speadsheet_view/import_export/import_export_dialog.gd @@ -10,25 +10,25 @@ onready var node_filename_props := $"TabContainer/Import/MarginContainer/ScrollC onready var prop_list := $"TabContainer/Import/MarginContainer/ScrollContainer/VBoxContainer" var entries := [] -var uniques := {} var property_used_as_filename := 0 var import_data : SpreadsheetImport -var delimeter := "," func _on_FileDialogText_file_selected(path : String): import_data = SpreadsheetImport.new() - import_data.path = path + import_data.initialize(path) + _open_dialog() popup_centered() func _open_dialog(): node_classname_field.text = TextEditingUtils\ - .string_snake_to_naming_case(import_data.path.get_file().get_basename())\ + .string_snake_to_naming_case(import_data.edited_path.get_file().get_basename())\ .replace(" ", "") - + import_data.script_classname = node_classname_field.text + _load_entries() _load_property_names() _create_prop_editors() @@ -36,17 +36,17 @@ func _open_dialog(): func _load_entries(): var file = File.new() - file.open(import_data.path, File.READ) + file.open(import_data.edited_path, File.READ) - delimeter = ";" - var text_lines := [file.get_line().split(delimeter)] + import_data.delimeter = ";" + var text_lines := [file.get_line().split(import_data.delimeter)] var line = text_lines[0] if line.size() == 1: - delimeter = "," - text_lines[0] = text_lines[0][0].split(delimeter) + import_data.delimeter = "," + text_lines[0] = text_lines[0][0].split(import_data.delimeter) while !file.eof_reached(): - line = file.get_csv_line(delimeter) + line = file.get_csv_line(import_data.delimeter) if line.size() == text_lines[0].size(): text_lines.append(line) @@ -99,7 +99,8 @@ func _generate_class(): new_script.source_code = "extends Resource\n\n" # Enums - uniques = {} + var uniques = {} + import_data.uniques = uniques for i in import_data.prop_types.size(): if import_data.prop_types[i] == SpreadsheetImport.PropType.ENUM: var cur_value := "" @@ -114,21 +115,22 @@ func _generate_class(): if !uniques[i].has(cur_value): uniques[i][cur_value] = uniques[i].size() - new_script.source_code += import_data.create_enum_for_prop(i, uniques) - + new_script.source_code += import_data.create_enum_for_prop(i) + # Properties for i in import_data.prop_names.size(): new_script.source_code += import_data.create_property_line_for_prop(i) - ResourceSaver.save(import_data.path.get_basename() + ".gd", new_script) + ResourceSaver.save(import_data.edited_path.get_basename() + ".gd", new_script) new_script.reload() - new_script = load(import_data.path.get_basename() + ".gd") # Because when instanced, objects have a copy of the script - import_data.new_script = new_script + + # Because when instanced, objects have a copy of the script + import_data.new_script = load(import_data.edited_path.get_basename() + ".gd") func _export_tres_folder(): var dir = Directory.new() - dir.make_dir_recursive(import_data.path.get_basename()) + dir.make_dir_recursive(import_data.edited_path.get_basename()) import_data.prop_used_as_filename = import_data.prop_names[property_used_as_filename] var new_res : Resource @@ -136,7 +138,7 @@ func _export_tres_folder(): if import_data.remove_first_row && i == 0: continue - new_res = import_data.strings_to_resource(entries[i], uniques) + new_res = import_data.strings_to_resource(entries[i]) ResourceSaver.save(new_res.resource_path, new_res) @@ -145,7 +147,7 @@ func _on_Ok_pressed(): _generate_class() _export_tres_folder() yield(get_tree(), "idle_frame") - editor_view.display_folder(import_data.path.get_basename()) + editor_view.display_folder(import_data.edited_path.get_basename() + "/") yield(get_tree(), "idle_frame") editor_view.refresh() @@ -155,7 +157,7 @@ func _on_OkSafe_pressed(): _generate_class() import_data.save() yield(get_tree(), "idle_frame") - editor_view.display_folder(import_data.path.get_basename()) + editor_view.display_folder(import_data.resource_path) yield(get_tree(), "idle_frame") editor_view.refresh() diff --git a/addons/resources_speadsheet_view/import_export/spreadsheet_import.gd b/addons/resources_speadsheet_view/import_export/spreadsheet_import.gd index 57f01f3..29c9d8e 100644 --- a/addons/resources_speadsheet_view/import_export/spreadsheet_import.gd +++ b/addons/resources_speadsheet_view/import_export/spreadsheet_import.gd @@ -1,6 +1,9 @@ +tool class_name SpreadsheetImport extends Resource +const SUFFIX := "_spreadsheet_import.tres" + enum PropType { BOOL, INT, @@ -16,23 +19,33 @@ enum PropType { MAX, } -var prop_types := [] -var prop_names := [] +export var prop_types : Array +export var prop_names : Array -var path := "res://" -var prop_used_as_filename := "name" -var script_classname := "" -var remove_first_row := true +export var edited_path := "res://" +export var prop_used_as_filename := "" +export var script_classname := "" +export var remove_first_row := true -var new_script : GDScript +export var new_script : GDScript +export var view_script : Script = SpreadsheetEditFormatCsv +export var delimeter := ";" + +export var uniques : Dictionary + + +func initialize(path): + resource_path = path.get_basename() + SUFFIX + edited_path = path + prop_types = [] + prop_names = [] func save(): - resource_path = path.get_basename() + "_spreadsheet_import.tres" - ResourceSaver.save(resource_path, self) + ResourceSaver.call_deferred("save", edited_path.get_basename() + SUFFIX, self) -func string_to_property(string : String, col_index : int, uniques : Dictionary): +func string_to_property(string : String, col_index : int): match prop_types[col_index]: PropType.STRING: return string @@ -61,6 +74,30 @@ func string_to_property(string : String, col_index : int, uniques : Dictionary): return int(uniques[col_index][string.to_upper().replace(" ", "_")]) +func property_to_string(value, col_index : int): + match prop_types[col_index]: + PropType.STRING: + return value + + PropType.BOOL: + return str(value) # TODO: make this actually persist + + PropType.REAL, PropType.INT: + return str(value) + + PropType.COLOR: + return value.to_html() + + PropType.OBJECT: + return value.resource_path + + PropType.ENUM: + var dict = uniques[col_index] + for k in dict: + if dict[k] == value: + return TextEditingUtils.string_snake_to_naming_case(k) + + func create_property_line_for_prop(col_index : int): var result = "export var " + prop_names[col_index] + " :" match prop_types[col_index]: @@ -93,7 +130,7 @@ func create_property_line_for_prop(col_index : int): ) + "= 0\n" -func create_enum_for_prop(col_index, uniques): +func create_enum_for_prop(col_index): var result := ( "enum " + TextEditingUtils.string_snake_to_naming_case(prop_names[col_index]).replace(" ", "") @@ -111,10 +148,21 @@ func create_enum_for_prop(col_index, uniques): return result -func strings_to_resource(strings : Array, uniques : Dictionary): +func strings_to_resource(strings : Array): var new_res = new_script.new() for j in prop_names.size(): - new_res.set(prop_names[j], string_to_property(strings[j], j, uniques)) + new_res.set(prop_names[j], string_to_property(strings[j], j)) + + if prop_used_as_filename != "": + new_res.resource_path = edited_path.get_basename() + "/" + new_res.get(prop_used_as_filename) + ".tres" - new_res.resource_path = path.get_basename() + "/" + new_res.get(prop_used_as_filename) + ".tres" return new_res + + +func resource_to_strings(res : Resource): + var strings := [] + strings.resize(prop_names.size()) + for i in prop_names.size(): + strings[i] = property_to_string(res.get(prop_names[i]), i) + + return PoolStringArray(strings) diff --git a/project.godot b/project.godot index 18efc8a..90dfbd3 100644 --- a/project.godot +++ b/project.godot @@ -34,6 +34,11 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://addons/resources_speadsheet_view/import_export/formats_edit/edit_base.gd" }, { +"base": "SpreadsheetEditFormatTres", +"class": "SpreadsheetEditFormatCsv", +"language": "GDScript", +"path": "res://addons/resources_speadsheet_view/import_export/formats_edit/edit_csv.gd" +}, { "base": "SpreadsheetEditFormat", "class": "SpreadsheetEditFormatTres", "language": "GDScript", @@ -58,6 +63,11 @@ _global_script_classes=[ { "class": "ThemeStylebox", "language": "GDScript", "path": "res://addons/resources_speadsheet_view/editor_stylebox_overrider.gd" +}, { +"base": "Resource", +"class": "TrainBigmartsalesprediction", +"language": "GDScript", +"path": "res://aa/train_BigMartSalesPrediction.gd" } ] _global_script_class_icons={ "CellEditor": "", @@ -65,11 +75,13 @@ _global_script_class_icons={ "SettingsGrid": "", "SheetsDockEditor": "", "SpreadsheetEditFormat": "", +"SpreadsheetEditFormatCsv": "", "SpreadsheetEditFormatTres": "", "SpreadsheetImport": "", "TextEditingUtils": "", "ThemeIconButton": "", -"ThemeStylebox": "" +"ThemeStylebox": "", +"TrainBigmartsalesprediction": "" } color_rows=false color_arrays=true