From d9313e105bb6a01d3cc7c205c582d5a58b7a1eea Mon Sep 17 00:00:00 2001 From: Relintai Date: Sat, 16 Jul 2022 18:07:46 +0200 Subject: [PATCH] Also added the world_generator addon. --- world_generator/plugin.cfg | 7 + world_generator/plugin.gd | 78 +++ world_generator/raycast/world_gen_raycast.gd | 32 ++ world_generator/resources/continent.gd | 39 ++ world_generator/resources/subzone.gd | 7 + .../resources/world_gen_base_resource.gd | 182 +++++++ world_generator/resources/world_gen_world.gd | 63 +++ .../resources/world_generator_settings.gd | 88 ++++ world_generator/resources/zone.gd | 39 ++ world_generator/test/test_world.tres | 351 +++++++++++++ world_generator/ui/DataList.gd | 175 +++++++ world_generator/ui/DataList.tscn | 84 +++ world_generator/ui/MainScreen.gd | 21 + world_generator/ui/MainScreen.tscn | 47 ++ world_generator/ui/RectEditor.gd | 12 + world_generator/ui/RectEditor.tscn | 54 ++ world_generator/ui/RectView.gd | 116 +++++ world_generator/ui/RectViewNode.gd | 227 ++++++++ world_generator/ui/RectViewNode.tscn | 11 + world_generator/ui/ResourcePropertyList.gd | 492 ++++++++++++++++++ world_generator/ui/ResourcePropertyList.tscn | 81 +++ world_generator/ui/WorldTab.gd | 19 + world_generator/ui/tabs/Continent.gd | 56 ++ world_generator/ui/tabs/Continent.tscn | 100 ++++ world_generator/ui/tabs/SubZone.gd | 122 +++++ world_generator/ui/tabs/SubZone.tscn | 49 ++ world_generator/ui/tabs/World.tscn | 82 +++ world_generator/ui/tabs/Zone.gd | 92 ++++ world_generator/ui/tabs/Zone.tscn | 105 ++++ .../widgets/EditorResourceWidget.gd | 80 +++ .../widgets/EditorResourceWidget.tscn | 23 + world_generator/widgets/EditorZoomWidget.gd | 218 ++++++++ world_generator/widgets/EditorZoomWidget.tscn | 8 + 33 files changed, 3160 insertions(+) create mode 100644 world_generator/plugin.cfg create mode 100644 world_generator/plugin.gd create mode 100644 world_generator/raycast/world_gen_raycast.gd create mode 100644 world_generator/resources/continent.gd create mode 100644 world_generator/resources/subzone.gd create mode 100644 world_generator/resources/world_gen_base_resource.gd create mode 100644 world_generator/resources/world_gen_world.gd create mode 100644 world_generator/resources/world_generator_settings.gd create mode 100644 world_generator/resources/zone.gd create mode 100644 world_generator/test/test_world.tres create mode 100644 world_generator/ui/DataList.gd create mode 100644 world_generator/ui/DataList.tscn create mode 100644 world_generator/ui/MainScreen.gd create mode 100644 world_generator/ui/MainScreen.tscn create mode 100644 world_generator/ui/RectEditor.gd create mode 100644 world_generator/ui/RectEditor.tscn create mode 100644 world_generator/ui/RectView.gd create mode 100644 world_generator/ui/RectViewNode.gd create mode 100644 world_generator/ui/RectViewNode.tscn create mode 100644 world_generator/ui/ResourcePropertyList.gd create mode 100644 world_generator/ui/ResourcePropertyList.tscn create mode 100644 world_generator/ui/WorldTab.gd create mode 100644 world_generator/ui/tabs/Continent.gd create mode 100644 world_generator/ui/tabs/Continent.tscn create mode 100644 world_generator/ui/tabs/SubZone.gd create mode 100644 world_generator/ui/tabs/SubZone.tscn create mode 100644 world_generator/ui/tabs/World.tscn create mode 100644 world_generator/ui/tabs/Zone.gd create mode 100644 world_generator/ui/tabs/Zone.tscn create mode 100644 world_generator/widgets/EditorResourceWidget.gd create mode 100644 world_generator/widgets/EditorResourceWidget.tscn create mode 100644 world_generator/widgets/EditorZoomWidget.gd create mode 100644 world_generator/widgets/EditorZoomWidget.tscn diff --git a/world_generator/plugin.cfg b/world_generator/plugin.cfg new file mode 100644 index 0000000..0680fe4 --- /dev/null +++ b/world_generator/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="WorldGenerator" +description="" +author="Relintai" +version="" +script="plugin.gd" diff --git a/world_generator/plugin.gd b/world_generator/plugin.gd new file mode 100644 index 0000000..f6a33fa --- /dev/null +++ b/world_generator/plugin.gd @@ -0,0 +1,78 @@ +tool +extends EditorPlugin + +var SWorldGeneratorSettings = preload("res://addons/world_generator/resources/world_generator_settings.gd") + +var SWorldGenBaseResource = preload("res://addons/world_generator/resources/world_gen_base_resource.gd") +var SWorldGenWorld = preload("res://addons/world_generator/resources/world_gen_world.gd") +var SContinent = preload("res://addons/world_generator/resources/continent.gd") +var SZone = preload("res://addons/world_generator/resources/zone.gd") +var SSubZone = preload("res://addons/world_generator/resources/subzone.gd") + +var editor_packed_scene = preload("res://addons/world_generator/ui/MainScreen.tscn") +var editor_scene = null + +var tool_button : ToolButton = null + +func _enter_tree(): + add_custom_type("WorldGeneratorSettings", "Resource", SWorldGeneratorSettings, null) + + add_custom_type("WorldGenBaseResource", "Resource", SWorldGenBaseResource, null) + #Don't change the base to "WorldGenBaseResource" else it will complain about a non-existant class + #Also it works perfectly like this + add_custom_type("WorldGenWorld", "Resource", SWorldGenWorld, null) + add_custom_type("Continent", "Resource", SContinent, null) + add_custom_type("Zone", "Resource", SZone, null) + add_custom_type("SubZone", "Resource", SSubZone, null) + + editor_scene = editor_packed_scene.instance() + editor_scene.set_plugin(self) + + tool_button = add_control_to_bottom_panel(editor_scene, "World Editor") + tool_button.hide() + +func _exit_tree(): + remove_custom_type("WorldGeneratorSettings") + + remove_custom_type("WorldGenBaseResource") + remove_custom_type("WorldGenWorld") + remove_custom_type("Continent") + remove_custom_type("Zone") + remove_custom_type("SubZone") + + remove_control_from_bottom_panel(editor_scene) + + +func handles(object): + return object is WorldGenWorld + +func edit(object): + #if editor_scene: + # make_bottom_panel_item_visible(editor_scene) + + if object is WorldGenWorld: + var wgw : WorldGenWorld = object as WorldGenWorld + wgw.setup() + editor_scene.set_wgworld(wgw) + +func make_visible(visible): + if tool_button: + if visible: + tool_button.show() + else: + #if tool_button.pressed: + # tool_button.pressed = false + + if !tool_button.pressed: + tool_button.hide() + +func get_plugin_icon(): + return null + +func get_plugin_name(): + return "WorldGeneratorEditor" + +func has_main_screen(): + return false + + diff --git a/world_generator/raycast/world_gen_raycast.gd b/world_generator/raycast/world_gen_raycast.gd new file mode 100644 index 0000000..2a80373 --- /dev/null +++ b/world_generator/raycast/world_gen_raycast.gd @@ -0,0 +1,32 @@ +tool +extends Reference +class_name WorldGenRaycast + +var current_index : int = -1 +var base_resources : Array = Array() +var local_positions : PoolVector2Array = PoolVector2Array() +var local_uvs : PoolVector2Array = PoolVector2Array() + +func get_local_position() -> Vector2: + return local_positions[current_index] + +func get_local_uv() -> Vector2: + return local_uvs[current_index] + +# WorldGenBaseResource (can't explicitly add -> cyclic dependency) +func get_resource(): + return base_resources[current_index] + +func next() -> bool: + current_index += 1 + + return base_resources.size() > current_index + +func size() -> int: + return base_resources.size() + +# base_resource -> WorldGenBaseResource +func add_data(base_resource, local_pos : Vector2, local_uv : Vector2) -> void: + base_resources.append(base_resource) + local_positions.append(local_pos) + local_uvs.append(local_uv) diff --git a/world_generator/resources/continent.gd b/world_generator/resources/continent.gd new file mode 100644 index 0000000..a1e7438 --- /dev/null +++ b/world_generator/resources/continent.gd @@ -0,0 +1,39 @@ +tool +extends "res://addons/world_generator/resources/world_gen_base_resource.gd" +class_name Continent + +export(Array) var zones : Array + +func get_content() -> Array: + return zones + +func set_content(arr : Array) -> void: + zones = arr + +func create_content(item_name : String = "") -> void: + var zone : Zone = Zone.new() + zone.resource_name = item_name + + var r : Rect2 = get_rect() + r.position = Vector2() + r.size.x /= 10.0 + r.size.y /= 10.0 + + zone.set_rect(r) + + add_content(zone) + +func add_content(entry : WorldGenBaseResource) -> void: + zones.append(entry) + entry.set_parent_pos(get_parent_pos() + get_rect().position) + emit_changed() + +func remove_content_entry(entry : WorldGenBaseResource) -> void: + for i in range(zones.size()): + if zones[i] == entry: + zones.remove(i) + emit_changed() + return + +func setup_property_inspector(inspector) -> void: + .setup_property_inspector(inspector) diff --git a/world_generator/resources/subzone.gd b/world_generator/resources/subzone.gd new file mode 100644 index 0000000..416682a --- /dev/null +++ b/world_generator/resources/subzone.gd @@ -0,0 +1,7 @@ +tool +extends "res://addons/world_generator/resources/world_gen_base_resource.gd" +class_name SubZone + +func setup_property_inspector(inspector) -> void: + .setup_property_inspector(inspector) + diff --git a/world_generator/resources/world_gen_base_resource.gd b/world_generator/resources/world_gen_base_resource.gd new file mode 100644 index 0000000..bb85616 --- /dev/null +++ b/world_generator/resources/world_gen_base_resource.gd @@ -0,0 +1,182 @@ +tool +extends Resource +class_name WorldGenBaseResource + +export(Rect2) var rect : Rect2 = Rect2(0, 0, 100, 100) +export(bool) var locked : bool = false + +var _parent_pos : Vector2 = Vector2() + +func setup() -> void: + _setup() + + for c in get_content(): + if c: + c.set_parent_pos(_parent_pos + get_rect().position) + c.setup() + +func _setup() -> void: + pass + +func get_rect() -> Rect2: + return rect + +func set_rect(r : Rect2) -> void: + rect = r + emit_changed() + +func get_locked() -> bool: + return locked + +func set_locked(r : bool) -> void: + locked = r + emit_changed() + +func get_parent_pos() -> Vector2: + return _parent_pos + +func set_parent_pos(parent_pos : Vector2) -> void: + _parent_pos = parent_pos + + for c in get_content(): + if c: + c.set_parent_pos(_parent_pos + get_rect().position) + +func get_content() -> Array: + return Array() + +func set_content(arr : Array) -> void: + pass + +func add_content(entry : WorldGenBaseResource) -> void: + pass + +func create_content(item_name : String = "") -> void: + pass + +func remove_content_entry(entry : WorldGenBaseResource) -> void: + pass + +func get_content_with_name(name : String) -> WorldGenBaseResource: + if resource_name == name: + return self + + for c in get_content(): + if c: + var cc = c.get_content_with_name(name) + if cc: + return cc + + return null + +func get_all_contents_with_name(name : String) -> Array: + var arr : Array = Array() + + if resource_name == name: + arr.append(self) + + for c in get_content(): + if c: + var cc : Array = c.get_all_contents_with_name(name) + arr.append_array(cc) + + return arr + +func duplicate_content_entry(entry : WorldGenBaseResource, add : bool = true) -> WorldGenBaseResource: + var de : WorldGenBaseResource = entry.duplicate(true) + de.resource_name += " (Duplicate)" + + if add: + add_content(de) + + return de + +func setup_terra_library(library : TerrainLibrary, pseed : int) -> void: + _setup_terra_library(library, pseed) + + for c in get_content(): + if c: + c.setup_terra_library(library, pseed) + +func _setup_terra_library(library : TerrainLibrary, pseed : int) -> void: + pass + +func generate_terra_chunk(chunk: TerrainChunk, pseed : int, spawn_mobs: bool) -> void: + var p : Vector2 = Vector2(chunk.get_position_x(), chunk.get_position_z()) + + var raycast : WorldGenRaycast = get_hit_stack(p) + + if raycast.size() == 0: + _generate_terra_chunk_fallback(chunk, pseed, spawn_mobs) + return + + while raycast.next(): + raycast.get_resource()._generate_terra_chunk(chunk, pseed, spawn_mobs, raycast) + +func _generate_terra_chunk(chunk: TerrainChunk, pseed : int, spawn_mobs: bool, raycast : WorldGenRaycast) -> void: + pass + +func _generate_terra_chunk_fallback(chunk: TerrainChunk, pseed : int, spawn_mobs: bool) -> void: + chunk.channel_ensure_allocated(TerrainChunkDefault.DEFAULT_CHANNEL_TYPE, 1) + chunk.channel_ensure_allocated(TerrainChunkDefault.DEFAULT_CHANNEL_ISOLEVEL, 1) + chunk.set_voxel(1, 0, 0, TerrainChunkDefault.DEFAULT_CHANNEL_ISOLEVEL) + +func generate_map(pseed : int) -> Image: + var img : Image = Image.new() + + img.create(get_rect().size.x, get_rect().size.y, false, Image.FORMAT_RGBA8) + + add_to_map(img, pseed) + + return img + +func add_to_map(img : Image, pseed : int) -> void: + _add_to_map(img, pseed) + + for c in get_content(): + if c: + c.add_to_map(img, pseed) + +func _add_to_map(img : Image, pseed : int) -> void: + pass + +func get_hit_stack(pos : Vector2, raycast : WorldGenRaycast = null) -> WorldGenRaycast: + var r : Rect2 = get_rect() + var local_pos : Vector2 = pos - rect.position + r.position = Vector2() + + if !raycast: + raycast = WorldGenRaycast.new() + + if r.has_point(local_pos): + var local_uv : Vector2 = local_pos / rect.size + raycast.add_data(self, local_pos, local_uv) + + for c in get_content(): + if c: + c.get_hit_stack(local_pos, raycast) + + return raycast + +func get_editor_rect_border_color() -> Color: + return Color(1, 1, 1, 1) + +func get_editor_rect_color() -> Color: + return Color(1, 1, 1, 0.9) + +func get_editor_rect_border_size() -> int: + return 2 + +func get_editor_font_color() -> Color: + return Color(0, 0, 0, 1) + +func get_editor_class() -> String: + return "WorldGenBaseResource" + +func get_editor_additional_text() -> String: + return "WorldGenBaseResource" + +func setup_property_inspector(inspector) -> void: + inspector.add_slot_line_edit("get_name", "set_name", "Name") + inspector.add_slot_rect2("get_rect", "set_rect", "Rect", 1) + inspector.add_slot_bool("get_locked", "set_locked", "Locked") diff --git a/world_generator/resources/world_gen_world.gd b/world_generator/resources/world_gen_world.gd new file mode 100644 index 0000000..1d8eb22 --- /dev/null +++ b/world_generator/resources/world_gen_world.gd @@ -0,0 +1,63 @@ +tool +extends "res://addons/world_generator/resources/world_gen_base_resource.gd" +class_name WorldGenWorld + +export(Array) var continents : Array + +func get_content() -> Array: + return continents + +func set_content(arr : Array) -> void: + continents = arr + +func create_content(item_name : String = "") -> void: + var continent : Continent = Continent.new() + continent.resource_name = item_name + + add_content(continent) + +func add_content(entry : WorldGenBaseResource) -> void: + var r : Rect2 = get_rect() + r.position = Vector2() + r.size.x /= 10.0 + r.size.y /= 10.0 + + entry.set_rect(r) + + continents.append(entry) + entry.set_parent_pos(get_parent_pos() + get_rect().position) + emit_changed() + +func remove_content_entry(entry : WorldGenBaseResource) -> void: + for i in range(continents.size()): + if continents[i] == entry: + continents.remove(i) + emit_changed() + return + +func setup_property_inspector(inspector) -> void: + .setup_property_inspector(inspector) + +func generate_terra_chunk(chunk: TerrainChunk, pseed : int, spawn_mobs: bool) -> void: + var p : Vector2 = Vector2(chunk.get_position_x(), chunk.get_position_z()) + + var raycast : WorldGenRaycast = get_hit_stack(p) + + if raycast.size() == 0: + _generate_terra_chunk_fallback(chunk, pseed, spawn_mobs) + return + + _generate_terra_chunk(chunk, pseed, spawn_mobs, raycast) + + while raycast.next(): + raycast.get_resource()._generate_terra_chunk(chunk, pseed, spawn_mobs, raycast) + + +func _generate_terra_chunk(chunk: TerrainChunk, pseed : int, spawn_mobs: bool, raycast : WorldGenRaycast) -> void: + pass + +func _generate_terra_chunk_fallback(chunk: TerrainChunk, pseed : int, spawn_mobs: bool) -> void: + chunk.channel_ensure_allocated(TerrainChunkDefault.DEFAULT_CHANNEL_TYPE, 1) + chunk.channel_ensure_allocated(TerrainChunkDefault.DEFAULT_CHANNEL_ISOLEVEL, 1) + chunk.set_voxel(1, 0, 0, TerrainChunkDefault.DEFAULT_CHANNEL_ISOLEVEL) + diff --git a/world_generator/resources/world_generator_settings.gd b/world_generator/resources/world_generator_settings.gd new file mode 100644 index 0000000..91a01aa --- /dev/null +++ b/world_generator/resources/world_generator_settings.gd @@ -0,0 +1,88 @@ +tool +extends Resource +class_name WorldGeneratorSettings + +export(PoolStringArray) var continent_class_folders : PoolStringArray +export(PoolStringArray) var zone_class_folders : PoolStringArray +export(PoolStringArray) var subzone_class_folders : PoolStringArray + +enum WorldGeneratorScriptType { + CONTINENT = 0, + ZONE = 1, + SUBZONE = 2, +}; + +func evaluate_scripts(script_type : int, tree : Tree) -> void: + if (script_type == WorldGeneratorScriptType.CONTINENT): + evaluate_continent_scripts(tree) + elif (script_type == WorldGeneratorScriptType.ZONE): + evaluate_zone_scripts(tree) + elif (script_type == WorldGeneratorScriptType.SUBZONE): + evaluate_subzone_scripts(tree) + +func evaluate_continent_scripts(tree : Tree) -> void: + tree.clear() + + var root : TreeItem = tree.create_item() + root.set_text(0, "Continent") + root.set_meta("class_name", "Continent") + + for s in continent_class_folders: + evaluate_folder(s, tree, root) + + root.select(0) + +func evaluate_zone_scripts(tree : Tree) -> void: + tree.clear() + + var root : TreeItem = tree.create_item() + root.set_text(0, "Zone") + root.set_meta("class_name", "Zone") + + for s in zone_class_folders: + evaluate_folder(s, tree, root) + + root.select(0) + +func evaluate_subzone_scripts(tree : Tree) -> void: + tree.clear() + + var root : TreeItem = tree.create_item() + root.set_text(0, "SubZone") + root.set_meta("class_name", "SubZone") + + for s in subzone_class_folders: + evaluate_folder(s, tree, root) + + root.select(0) + +func evaluate_folder(folder : String, tree : Tree, root : TreeItem) -> void: + var ti : TreeItem = null + + var dir = Directory.new() + if dir.open(folder) == OK: + dir.list_dir_begin() + var file_name = dir.get_next() + while file_name != "": + if !dir.current_is_dir(): + #print("Found file: " + file_name) + + if !ti: + var n : String = folder.substr(folder.find_last("/") + 1) + + if n != "": + ti = tree.create_item(root) + ti.set_text(0, n) + else: + ti = root + + var e : TreeItem = tree.create_item(ti) + + e.set_text(0, file_name.get_file()) + e.set_meta("file", folder + "/" + file_name) + + file_name = dir.get_next() + else: + print("An error occurred when trying to access the path.") + + diff --git a/world_generator/resources/zone.gd b/world_generator/resources/zone.gd new file mode 100644 index 0000000..c0c2368 --- /dev/null +++ b/world_generator/resources/zone.gd @@ -0,0 +1,39 @@ +tool +extends "res://addons/world_generator/resources/world_gen_base_resource.gd" +class_name Zone + +export(Array) var subzones : Array + +func get_content() -> Array: + return subzones + +func set_content(arr : Array) -> void: + subzones = arr + +func create_content(item_name : String = "") -> void: + var subzone : SubZone = SubZone.new() + subzone.resource_name = item_name + + var r : Rect2 = get_rect() + r.position = Vector2() + r.size.x /= 10.0 + r.size.y /= 10.0 + + subzone.set_rect(r) + + add_content(subzone) + +func add_content(entry : WorldGenBaseResource) -> void: + subzones.append(entry) + entry.set_parent_pos(get_parent_pos() + get_rect().position) + emit_changed() + +func remove_content_entry(entry : WorldGenBaseResource) -> void: + for i in range(subzones.size()): + if subzones[i] == entry: + subzones.remove(i) + emit_changed() + return + +func setup_property_inspector(inspector) -> void: + .setup_property_inspector(inspector) diff --git a/world_generator/test/test_world.tres b/world_generator/test/test_world.tres new file mode 100644 index 0000000..387c353 --- /dev/null +++ b/world_generator/test/test_world.tres @@ -0,0 +1,351 @@ +[gd_resource type="Resource" load_steps=40 format=2] + +[ext_resource path="res://addons/world_generator/resources/world_gen_world.gd" type="Script" id=1] +[ext_resource path="res://addons/world_generator/resources/continent.gd" type="Script" id=2] +[ext_resource path="res://addons/world_generator/resources/zone.gd" type="Script" id=3] +[ext_resource path="res://addons/world_generator/resources/subzone.gd" type="Script" id=4] +[ext_resource path="res://scripts/world_generator/continents/test_continent.gd" type="Script" id=5] +[ext_resource path="res://scripts/world_generator/zones/test_zone.gd" type="Script" id=6] +[ext_resource path="res://scripts/world_generator/subzones/test_subzone.gd" type="Script" id=7] + +[sub_resource type="Resource" id=14] +resource_name = "qwe" +script = ExtResource( 4 ) +rect = Rect2( 21, 25, 150, 79 ) +locked = false + +[sub_resource type="Resource" id=15] +resource_name = "we" +script = ExtResource( 4 ) +rect = Rect2( 7, 9, 54, 34 ) +locked = false + +[sub_resource type="Resource" id=34] +resource_name = "yy" +script = ExtResource( 7 ) +rect = Rect2( 66, 11, 100, 91 ) +locked = false + +[sub_resource type="Resource" id=8] +resource_name = "asdasr" +script = ExtResource( 3 ) +rect = Rect2( 35, 21, 191.4, 127.8 ) +locked = false +subzones = [ SubResource( 14 ), SubResource( 15 ), SubResource( 34 ) ] + +[sub_resource type="Resource" id=13] +resource_name = "qqq" +script = ExtResource( 3 ) +rect = Rect2( 17, 59, 200.4, 52 ) +locked = false +subzones = [ ] + +[sub_resource type="Resource" id=24] +resource_name = "trtrtr" +script = ExtResource( 3 ) +rect = Rect2( 0, 0, 57.1, 45.8 ) +locked = false +subzones = [ ] + +[sub_resource type="GDScript" id=25] +script/source = "tool +extends \"res://addons/world_generator/resources/world_gen_base_resource.gd\" +class_name Zone + +export(Array) var subzones : Array + +func get_content() -> Array: + return subzones + +func set_content(arr : Array) -> void: + subzones = arr + +func create_content(item_name : String = \"\") -> void: + var subzone : SubZone = SubZone.new() + subzone.resource_name = item_name + + var r : Rect2 = get_rect() + r.position = Vector2() + r.size.x /= 10.0 + r.size.y /= 10.0 + + subzone.set_rect(r) + + add_content(subzone) + +func add_content(entry : WorldGenBaseResource) -> void: + subzones.append(entry) + emit_changed() + +func remove_content_entry(entry : WorldGenBaseResource) -> void: + for i in range(subzones.size()): + if subzones[i] == entry: + subzones.remove(i) + emit_changed() + return + +func setup_property_inspector(inspector) -> void: + .setup_property_inspector(inspector) +" + +[sub_resource type="Resource" id=26] +resource_name = "trtrtr (Duplicate)" +script = SubResource( 25 ) +rect = Rect2( 64, 6, 158.1, 39.8 ) +locked = false +subzones = [ ] + +[sub_resource type="Resource" id=32] +resource_name = "tttte" +script = ExtResource( 3 ) +rect = Rect2( 103, 28, 100, 100 ) +locked = false +subzones = [ ] + +[sub_resource type="Resource" id=35] +resource_name = "yu" +script = ExtResource( 6 ) +rect = Rect2( 88, 21, 100, 100 ) +locked = false +subzones = [ ] + +[sub_resource type="Resource" id=1] +resource_name = "wwww" +script = ExtResource( 2 ) +rect = Rect2( 163, 35, 241, 158 ) +zones = [ SubResource( 8 ), SubResource( 13 ), SubResource( 24 ), SubResource( 26 ), SubResource( 32 ), SubResource( 35 ) ] + +[sub_resource type="Resource" id=2] +resource_name = "efefef" +script = ExtResource( 2 ) +rect = Rect2( 107, 271, 100, 49 ) + +[sub_resource type="Resource" id=3] +resource_name = "grgrg" +script = ExtResource( 2 ) +rect = Rect2( 498, 185, 100, 100 ) + +[sub_resource type="Resource" id=9] +resource_name = "asd" +script = ExtResource( 3 ) +rect = Rect2( 528, 34, 0, 0 ) +locked = false +subzones = [ ] + +[sub_resource type="Resource" id=10] +resource_name = "qqq" +script = ExtResource( 3 ) +rect = Rect2( 528, 34, 0, 0 ) +locked = false +subzones = [ ] + +[sub_resource type="Resource" id=4] +resource_name = "qwdasd" +script = ExtResource( 2 ) +rect = Rect2( 522, 29, 63, 54 ) +zones = [ SubResource( 9 ), SubResource( 10 ) ] + +[sub_resource type="Resource" id=11] +resource_name = "q" +script = ExtResource( 3 ) +rect = Rect2( 14, 11, 53, 59 ) +locked = false +subzones = [ ] + +[sub_resource type="Resource" id=5] +resource_name = "qwe" +script = ExtResource( 2 ) +rect = Rect2( 473, 331, 100, 100 ) +zones = [ SubResource( 11 ) ] + +[sub_resource type="GDScript" id=16] +script/source = "tool +extends \"res://addons/world_generator/resources/world_gen_base_resource.gd\" +class_name Continent + +export(Array) var zones : Array + +func get_content() -> Array: + return zones + +func set_content(arr : Array) -> void: + zones = arr + +func create_content(item_name : String = \"\") -> void: + var zone : Zone = Zone.new() + zone.resource_name = item_name + + var r : Rect2 = get_rect() + r.position = Vector2() + r.size.x /= 10.0 + r.size.y /= 10.0 + + zone.set_rect(r) + + add_content(zone) + +func add_content(entry : WorldGenBaseResource) -> void: + zones.append(entry) + emit_changed() + +func remove_content_entry(entry : WorldGenBaseResource) -> void: + for i in range(zones.size()): + if zones[i] == entry: + zones.remove(i) + emit_changed() + return + +func setup_property_inspector(inspector) -> void: + .setup_property_inspector(inspector) +" + +[sub_resource type="Resource" id=17] +resource_name = "qwetwwqasd" +script = SubResource( 16 ) +rect = Rect2( 473, 331, 100, 100 ) +locked = false +zones = [ SubResource( 11 ) ] + +[sub_resource type="GDScript" id=18] +script/source = "tool +extends \"res://addons/world_generator/resources/world_gen_base_resource.gd\" +class_name Continent + +export(Array) var zones : Array + +func get_content() -> Array: + return zones + +func set_content(arr : Array) -> void: + zones = arr + +func create_content(item_name : String = \"\") -> void: + var zone : Zone = Zone.new() + zone.resource_name = item_name + + var r : Rect2 = get_rect() + r.position = Vector2() + r.size.x /= 10.0 + r.size.y /= 10.0 + + zone.set_rect(r) + + add_content(zone) + +func add_content(entry : WorldGenBaseResource) -> void: + zones.append(entry) + emit_changed() + +func remove_content_entry(entry : WorldGenBaseResource) -> void: + for i in range(zones.size()): + if zones[i] == entry: + zones.remove(i) + emit_changed() + return + +func setup_property_inspector(inspector) -> void: + .setup_property_inspector(inspector) +" + +[sub_resource type="Resource" id=19] +resource_name = "qwesat" +script = SubResource( 18 ) +rect = Rect2( 613, 346, 100, 100 ) +locked = false +zones = [ SubResource( 11 ) ] + +[sub_resource type="Resource" id=20] +resource_name = "ggg" +script = ExtResource( 2 ) +rect = Rect2( 26, 51, 100, 100 ) + +[sub_resource type="GDScript" id=21] +script/source = "tool +extends \"res://addons/world_generator/resources/world_gen_base_resource.gd\" +class_name Continent + +export(Array) var zones : Array + +func get_content() -> Array: + return zones + +func set_content(arr : Array) -> void: + zones = arr + +func create_content(item_name : String = \"\") -> void: + var zone : Zone = Zone.new() + zone.resource_name = item_name + + var r : Rect2 = get_rect() + r.position = Vector2() + r.size.x /= 10.0 + r.size.y /= 10.0 + + zone.set_rect(r) + + add_content(zone) + +func add_content(entry : WorldGenBaseResource) -> void: + zones.append(entry) + emit_changed() + +func remove_content_entry(entry : WorldGenBaseResource) -> void: + for i in range(zones.size()): + if zones[i] == entry: + zones.remove(i) + emit_changed() + return + +func setup_property_inspector(inspector) -> void: + .setup_property_inspector(inspector) +" + +[sub_resource type="Resource" id=22] +resource_name = "ggg (Duplicate)" +script = SubResource( 21 ) +rect = Rect2( 33, 181, 100, 100 ) +locked = false +zones = [ ] + +[sub_resource type="Resource" id=23] +resource_name = "eeqqq" +script = ExtResource( 2 ) +rect = Rect2( 256, 365, 100, 100 ) + +[sub_resource type="Resource" id=27] +resource_name = "asd" +script = ExtResource( 2 ) +rect = Rect2( 337, 79, 100, 100 ) + +[sub_resource type="Resource" id=28] +resource_name = "asd" +script = ExtResource( 2 ) +rect = Rect2( 244, 234, 100, 100 ) + +[sub_resource type="Resource" id=29] +script = ExtResource( 2 ) +rect = Rect2( 377, 69, 284, 238 ) + +[sub_resource type="Resource" id=30] +resource_name = "tttttt" +script = ExtResource( 2 ) +rect = Rect2( 188, 225, 233, 259 ) + +[sub_resource type="Resource" id=31] +resource_name = "ttttyuqtttt" +script = ExtResource( 2 ) +rect = Rect2( 339, 76, 220, 170 ) + +[sub_resource type="Resource" id=33] +resource_name = "qttt" +script = ExtResource( 5 ) +rect = Rect2( 99, 78, 213, 105 ) +locked = false +zones = [ ] + +[resource] +resource_name = "asdasdsse" +script = ExtResource( 1 ) +rect = Rect2( 0, 0, 1000, 1000 ) +locked = false +continents = [ SubResource( 1 ), SubResource( 2 ), SubResource( 3 ), SubResource( 4 ), SubResource( 5 ), SubResource( 17 ), SubResource( 19 ), SubResource( 20 ), SubResource( 22 ), SubResource( 23 ), SubResource( 27 ), SubResource( 28 ), SubResource( 29 ), SubResource( 30 ), SubResource( 31 ), SubResource( 33 ) ] diff --git a/world_generator/ui/DataList.gd b/world_generator/ui/DataList.gd new file mode 100644 index 0000000..fa28289 --- /dev/null +++ b/world_generator/ui/DataList.gd @@ -0,0 +1,175 @@ +tool +extends Tree + +export(int, "Continent,Zone,Sub Zone") var class_types : int = 0 + +var edited_resource : WorldGenBaseResource = null +var name_edited_resource : WorldGenBaseResource = null + +var _ignore_changed_event : bool = false + +var _plugin : EditorPlugin = null +var _undo_redo : UndoRedo = null + +func _init(): + connect("item_activated", self, "on_item_activated") + +func set_plugin(plugin : EditorPlugin) -> void: + _plugin = plugin + _undo_redo = _plugin.get_undo_redo() + +func _enter_tree(): + var dir : Directory = Directory.new() + + if dir.file_exists("res://world_generator_settings.tres"): + var wgs : WorldGeneratorSettings = load("res://world_generator_settings.tres") as WorldGeneratorSettings + + if !wgs: + return + + wgs.evaluate_scripts(class_types, $NameDialog/VBoxContainer/Tree) + +func add_item(item_name : String = "") -> void: + if !edited_resource: + return + + var ti : TreeItem = $NameDialog/VBoxContainer/Tree.get_selected() + + if !ti: + return + + var e : WorldGenBaseResource = null + + if ti.has_meta("class_name"): + var cn : String = ti.get_meta("class_name") + + if cn == "Continent": + e = Continent.new() + elif cn == "Zone": + e = Zone.new() + elif cn == "SubZone": + e = SubZone.new() + + elif ti.has_meta("file"): + var cls = load(ti.get_meta("file")) + + if cls: + e = cls.new() + + if !e: + return + + e.resource_name = item_name + + #edited_resource.add_content(e) + #remove_content_entry + + _undo_redo.create_action("WE: Created Entry") + _undo_redo.add_do_method(edited_resource, "add_content", e) + _undo_redo.add_undo_method(edited_resource, "remove_content_entry", e) + _undo_redo.commit_action() + +func refresh() -> void: + clear() + + if !edited_resource: + return + + var root : TreeItem = create_item() + + var data : Array = edited_resource.get_content() + + for d in data: + if d: + var n : String = d.resource_name + + if n == "": + n = "" + + var item : TreeItem = create_item(root) + + item.set_text(0, n) + item.set_meta("res", d) + +func set_edited_resource(res : WorldGenBaseResource)-> void: + if edited_resource: + edited_resource.disconnect("changed", self, "on_resource_changed") + + edited_resource = res + + if edited_resource: + edited_resource.connect("changed", self, "on_resource_changed") + + refresh() + +func add_button_pressed() -> void: + $NameDialog/VBoxContainer/LineEdit.text = "" + $NameDialog.popup_centered() + +func name_dialog_ok_pressed() -> void: + add_item($NameDialog/VBoxContainer/LineEdit.text) + +func name_edit_dialog_ok_pressed() -> void: + if name_edited_resource: + name_edited_resource.resource_name = $NameEditDialog/VBoxContainer/LineEdit.text + name_edited_resource.emit_changed() + name_edited_resource = null + on_resource_changed() + +func delete_button_pressed() -> void: + var item : TreeItem = get_selected() + + if !item: + return + + var item_resource = item.get_meta("res") + + if !item_resource: + return + + #edited_resource.remove_content_entry(item_resource) + + _undo_redo.create_action("WE: Created Entry") + _undo_redo.add_do_method(edited_resource, "remove_content_entry", item_resource) + _undo_redo.add_undo_method(edited_resource, "add_content", item_resource) + _undo_redo.commit_action() + +func duplicate_button_pressed() -> void: + var item : TreeItem = get_selected() + + if !item: + return + + var item_resource = item.get_meta("res") + + if !item_resource: + return + + #edited_resource.duplicate_content_entry(item_resource) + + var de = edited_resource.duplicate_content_entry(item_resource, false) + + _undo_redo.create_action("WE: Created Entry") + _undo_redo.add_do_method(edited_resource, "add_content", de) + _undo_redo.add_undo_method(edited_resource, "remove_content_entry", de) + _undo_redo.commit_action() + +func on_resource_changed() -> void: + if _ignore_changed_event: + return + + call_deferred("refresh") + +func on_item_activated() -> void: + var item : TreeItem = get_selected() + + if !item: + return + + name_edited_resource = item.get_meta("res") + + if !name_edited_resource: + return + + $NameEditDialog/VBoxContainer/LineEdit.text = name_edited_resource.resource_name + $NameEditDialog.popup_centered() diff --git a/world_generator/ui/DataList.tscn b/world_generator/ui/DataList.tscn new file mode 100644 index 0000000..7852c4d --- /dev/null +++ b/world_generator/ui/DataList.tscn @@ -0,0 +1,84 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://addons/world_generator/ui/DataList.gd" type="Script" id=1] + +[node name="DataList" type="Tree"] +anchor_right = 1.0 +anchor_bottom = 1.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +hide_root = true +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="NameDialog" type="ConfirmationDialog" parent="."] +margin_right = 329.0 +margin_bottom = 313.0 +window_title = "Name" +resizable = true +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="VBoxContainer" type="VBoxContainer" parent="NameDialog"] +margin_left = 8.0 +margin_top = 8.0 +margin_right = 321.0 +margin_bottom = 277.0 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Label2" type="Label" parent="NameDialog/VBoxContainer"] +margin_right = 313.0 +margin_bottom = 14.0 +text = "Class" + +[node name="Tree" type="Tree" parent="NameDialog/VBoxContainer"] +margin_top = 18.0 +margin_right = 313.0 +margin_bottom = 223.0 +rect_min_size = Vector2( 0, 200 ) +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="Label" type="Label" parent="NameDialog/VBoxContainer"] +margin_top = 227.0 +margin_right = 313.0 +margin_bottom = 241.0 +text = "Name" + +[node name="LineEdit" type="LineEdit" parent="NameDialog/VBoxContainer"] +margin_top = 245.0 +margin_right = 313.0 +margin_bottom = 269.0 + +[node name="NameEditDialog" type="ConfirmationDialog" parent="."] +margin_right = 223.0 +margin_bottom = 82.0 +window_title = "Name" +resizable = true +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="VBoxContainer" type="VBoxContainer" parent="NameEditDialog"] +margin_left = 8.0 +margin_top = 8.0 +margin_right = 215.0 +margin_bottom = 50.0 + +[node name="Label" type="Label" parent="NameEditDialog/VBoxContainer"] +margin_right = 207.0 +margin_bottom = 14.0 +text = "Name" + +[node name="LineEdit" type="LineEdit" parent="NameEditDialog/VBoxContainer"] +margin_top = 18.0 +margin_right = 207.0 +margin_bottom = 42.0 + +[connection signal="confirmed" from="NameDialog" to="." method="name_dialog_ok_pressed"] +[connection signal="confirmed" from="NameEditDialog" to="." method="name_edit_dialog_ok_pressed"] diff --git a/world_generator/ui/MainScreen.gd b/world_generator/ui/MainScreen.gd new file mode 100644 index 0000000..a6512c5 --- /dev/null +++ b/world_generator/ui/MainScreen.gd @@ -0,0 +1,21 @@ +tool +extends PanelContainer + +var edited_world + +func set_plugin(plugin : EditorPlugin) -> void: + $TabContainer/World.set_plugin(plugin) + $TabContainer/Continent.set_plugin(plugin) + $TabContainer/Zone.set_plugin(plugin) + $TabContainer/SubZone.set_plugin(plugin) + +func refresh() -> void: + $TabContainer/World.set_wgworld(edited_world) + $TabContainer/Continent.set_wgworld(edited_world) + $TabContainer/Zone.set_wgworld(edited_world) + $TabContainer/SubZone.set_wgworld(edited_world) + +func set_wgworld(wgw : WorldGenWorld) -> void: + edited_world = wgw + + refresh() diff --git a/world_generator/ui/MainScreen.tscn b/world_generator/ui/MainScreen.tscn new file mode 100644 index 0000000..b3a81e7 --- /dev/null +++ b/world_generator/ui/MainScreen.tscn @@ -0,0 +1,47 @@ +[gd_scene load_steps=6 format=2] + +[ext_resource path="res://addons/world_generator/ui/MainScreen.gd" type="Script" id=1] +[ext_resource path="res://addons/world_generator/ui/tabs/World.tscn" type="PackedScene" id=2] +[ext_resource path="res://addons/world_generator/ui/tabs/Continent.tscn" type="PackedScene" id=3] +[ext_resource path="res://addons/world_generator/ui/tabs/Zone.tscn" type="PackedScene" id=4] +[ext_resource path="res://addons/world_generator/ui/tabs/SubZone.tscn" type="PackedScene" id=5] + +[node name="WorldGenerator" type="PanelContainer"] +anchor_right = 1.0 +anchor_bottom = 1.0 +rect_min_size = Vector2( 0, 200 ) +size_flags_vertical = 3 +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="TabContainer" type="TabContainer" parent="."] +margin_left = 7.0 +margin_top = 7.0 +margin_right = 1017.0 +margin_bottom = 593.0 +tab_align = 0 + +[node name="World" parent="TabContainer" instance=ExtResource( 2 )] + +[node name="Continent" parent="TabContainer" instance=ExtResource( 3 )] +visible = false +margin_left = 4.0 +margin_top = 32.0 +margin_right = -4.0 +margin_bottom = -4.0 + +[node name="Zone" parent="TabContainer" instance=ExtResource( 4 )] +visible = false +margin_left = 4.0 +margin_top = 32.0 +margin_right = -4.0 +margin_bottom = -4.0 + +[node name="SubZone" parent="TabContainer" instance=ExtResource( 5 )] +visible = false +margin_left = 4.0 +margin_top = 32.0 +margin_right = -4.0 +margin_bottom = -4.0 diff --git a/world_generator/ui/RectEditor.gd b/world_generator/ui/RectEditor.gd new file mode 100644 index 0000000..d86112e --- /dev/null +++ b/world_generator/ui/RectEditor.gd @@ -0,0 +1,12 @@ +tool +extends PanelContainer + +func _init(): +# Control/EditorZoomWidget + pass + +func set_plugin(plugin : EditorPlugin) -> void: + $ScrollContainer/MarginContainer/RectView.set_plugin(plugin) + +func set_edited_resource(res : WorldGenBaseResource): + $ScrollContainer/MarginContainer/RectView.set_edited_resource(res) diff --git a/world_generator/ui/RectEditor.tscn b/world_generator/ui/RectEditor.tscn new file mode 100644 index 0000000..ae622a3 --- /dev/null +++ b/world_generator/ui/RectEditor.tscn @@ -0,0 +1,54 @@ +[gd_scene load_steps=4 format=2] + +[ext_resource path="res://addons/world_generator/ui/RectEditor.gd" type="Script" id=1] +[ext_resource path="res://addons/world_generator/widgets/EditorZoomWidget.tscn" type="PackedScene" id=2] +[ext_resource path="res://addons/world_generator/ui/RectView.gd" type="Script" id=3] + +[node name="RectEditor" type="PanelContainer"] +anchor_right = 1.0 +anchor_bottom = 1.0 +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="ScrollContainer" type="ScrollContainer" parent="."] +margin_left = 7.0 +margin_top = 7.0 +margin_right = 1017.0 +margin_bottom = 593.0 + +[node name="MarginContainer" type="MarginContainer" parent="ScrollContainer"] +margin_right = 400.0 +margin_bottom = 400.0 +custom_constants/margin_right = 200 +custom_constants/margin_top = 200 +custom_constants/margin_left = 200 +custom_constants/margin_bottom = 200 + +[node name="RectView" type="Control" parent="ScrollContainer/MarginContainer"] +margin_left = 200.0 +margin_top = 200.0 +margin_right = 200.0 +margin_bottom = 200.0 +script = ExtResource( 3 ) +zoom_widget_path = NodePath("../../../Control/EditorZoomWidget") + +[node name="Control" type="Control" parent="."] +margin_left = 7.0 +margin_top = 7.0 +margin_right = 1017.0 +margin_bottom = 593.0 +mouse_filter = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="EditorZoomWidget" parent="Control" instance=ExtResource( 2 )] +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_right = 115.0 +margin_bottom = 22.0 +custom_constants/separation = -8 +__meta__ = { +"_edit_use_anchors_": false +} diff --git a/world_generator/ui/RectView.gd b/world_generator/ui/RectView.gd new file mode 100644 index 0000000..61b2b4a --- /dev/null +++ b/world_generator/ui/RectView.gd @@ -0,0 +1,116 @@ +tool +extends Control + +var rect_editor_node_scene : PackedScene = preload("res://addons/world_generator/ui/RectViewNode.tscn") + +export(NodePath) var zoom_widget_path : NodePath = "" + +var _rect_scale : float = 1 + +var edited_resource : WorldGenBaseResource = null +var edited_resource_current_size : Vector2 = Vector2() + +var _plugin : EditorPlugin = null +var _undo_redo : UndoRedo = null + +func _enter_tree(): + var zoom_widget : Node = get_node_or_null(zoom_widget_path) + + if !zoom_widget: + return + + if !zoom_widget.is_connected("zoom_changed", self, "on_zoom_changed"): + zoom_widget.connect("zoom_changed", self, "on_zoom_changed") + + if !is_connected("visibility_changed", self, "on_visibility_changed"): + connect("visibility_changed", self, "on_visibility_changed") + +func set_plugin(plugin : EditorPlugin) -> void: + _plugin = plugin + _undo_redo = _plugin.get_undo_redo() + +func on_visibility_changed() -> void: + call_deferred("apply_zoom") + +func apply_zoom() -> void: + if !edited_resource: + return + + var rect : Rect2 = edited_resource.rect + edited_resource_current_size = rect.size + rect.position = rect.position * _rect_scale + rect.size = rect.size * _rect_scale + set_custom_minimum_size(rect.size) + + var p : MarginContainer = get_parent() as MarginContainer + + p.add_constant_override("margin_left", min(rect.size.x / 4.0, 50 * _rect_scale)) + p.add_constant_override("margin_right", min(rect.size.x / 4.0, 50 * _rect_scale)) + p.add_constant_override("margin_top", min(rect.size.y / 4.0, 50 * _rect_scale)) + p.add_constant_override("margin_bottom", min(rect.size.y / 4.0, 50 * _rect_scale)) + + for c in get_children(): + c.set_editor_rect_scale(_rect_scale) + +func on_zoom_changed(zoom : float) -> void: + _rect_scale = zoom + apply_zoom() + +func _draw(): + draw_rect(Rect2(Vector2(), get_size()), Color(0.2, 0.2, 0.2, 1)) + +func refresh() -> void: + clear() + + if !edited_resource: + return + + var rect : Rect2 = edited_resource.rect + edited_resource_current_size = rect.size + rect.position = rect.position * _rect_scale + rect.size = rect.size * _rect_scale + set_custom_minimum_size(rect.size) + + apply_zoom() + + refresh_rects() + +func clear() -> void: + pass + +func refresh_rects() -> void: + clear_rects() + + if !edited_resource: + return + + var cont : Array = edited_resource.get_content() + + for c in cont: + if c: + var s : Node = rect_editor_node_scene.instance() + + add_child(s) + s.set_plugin(_plugin) + s.set_editor_rect_scale(_rect_scale) + s.edited_resource_parent_size = edited_resource_current_size + s.set_edited_resource(c) + +func clear_rects(): + for c in get_children(): + c.queue_free() + remove_child(c) + +func set_edited_resource(res : WorldGenBaseResource): + if edited_resource: + edited_resource.disconnect("changed", self, "on_edited_resource_changed") + + edited_resource = res + + refresh() + + if edited_resource: + edited_resource.connect("changed", self, "on_edited_resource_changed") + +func on_edited_resource_changed() -> void: + call_deferred("refresh") diff --git a/world_generator/ui/RectViewNode.gd b/world_generator/ui/RectViewNode.gd new file mode 100644 index 0000000..2f30e2c --- /dev/null +++ b/world_generator/ui/RectViewNode.gd @@ -0,0 +1,227 @@ +tool +extends MarginContainer + +enum DragType { + DRAG_NONE = 0, + DRAG_MOVE = 1, + DRAG_RESIZE_TOP = 1 << 1, + DRAG_RESIZE_RIGHT = 1 << 2, + DRAG_RESIZE_BOTTOM = 1 << 3, + DRAG_RESIZE_LEFT = 1 << 4 +}; + +var edited_resource : WorldGenBaseResource = null +var edited_resource_parent_size : Vector2 = Vector2() + +var _edited_resource_rect_border_color : Color = Color(1, 1, 1, 1) +var _edited_resource_rect_color : Color = Color(0.8, 0.8, 0.8, 0.9) +var _editor_rect_border_size : int = 2 +var _edited_resource_font_color : Color = Color(0, 0, 0, 1) +var _editor_additional_text : String = "" + +var drag_type : int +var drag_offset : Vector2 +var drag_offset_far : Vector2 + +var _rect_scale : float = 1 + +var _edited_resource_event_ignore : bool = false + +var _plugin : EditorPlugin = null +var _undo_redo : UndoRedo = null + +func set_plugin(plugin : EditorPlugin) -> void: + _plugin = plugin + _undo_redo = _plugin.get_undo_redo() + +func _draw(): + draw_rect(Rect2(Vector2(), get_size()), _edited_resource_rect_color) + draw_rect(Rect2(Vector2(), get_size()), _edited_resource_rect_border_color, false, _editor_rect_border_size) + + var font : Font = get_font("font") + + var res_name : String = "NULL" + + if edited_resource: + res_name = edited_resource.resource_name + + var res_cls : String = "" + + if edited_resource: + res_cls = edited_resource.get_editor_class() + + draw_string(font, Vector2(_editor_rect_border_size, font.get_height()), res_name, _edited_resource_font_color) + draw_string(font, Vector2(_editor_rect_border_size, font.get_height() * 2), _editor_additional_text, _edited_resource_font_color, get_rect().size.x) + + if res_cls != "": + draw_string(font, Vector2(_editor_rect_border_size, font.get_height() * 3), res_cls, _edited_resource_font_color, get_rect().size.x) + +func refresh() -> void: + if !edited_resource: + return + + #anchor is bottom left here + var rect : Rect2 = edited_resource.get_rect() + rect.position *= _rect_scale + rect.size *= _rect_scale + + #anchor needs to be on top left here + var rp : Vector2 = rect.position + rp.y = edited_resource_parent_size.y * _rect_scale - rect.size.y - rect.position.y + rect_position = rp + rect_size = rect.size + + update() + +func set_editor_rect_scale(rect_scale) -> void: + _rect_scale = rect_scale + + refresh() + +func set_edited_resource(res : WorldGenBaseResource): + edited_resource = res + + if edited_resource: + _edited_resource_rect_border_color = edited_resource.get_editor_rect_border_color() + _edited_resource_rect_color = edited_resource.get_editor_rect_color() + _editor_rect_border_size = edited_resource.get_editor_rect_border_size() + _edited_resource_font_color = edited_resource.get_editor_font_color() + _editor_additional_text = edited_resource.get_editor_additional_text() + + edited_resource.connect("changed", self, "on_edited_resource_changed") + + refresh() + +func on_edited_resource_changed() -> void: + if _edited_resource_event_ignore: + return + + refresh() + +#based on / ported from engine/scene/gui/dialogs.h and .cpp +func _notification(p_what : int) -> void: + if (p_what == NOTIFICATION_MOUSE_EXIT): + # Reset the mouse cursor when leaving the resizable window border. + if (edited_resource && !edited_resource.locked && !drag_type): + if (get_default_cursor_shape() != CURSOR_ARROW): + set_default_cursor_shape(CURSOR_ARROW) + +#based on / ported from engine/scene/gui/dialogs.h and .cpp +func _gui_input(p_event : InputEvent) -> void: + if (p_event is InputEventMouseButton) && (p_event.get_button_index() == BUTTON_LEFT): + var mb : InputEventMouseButton = p_event as InputEventMouseButton + + if (mb.is_pressed()): + # Begin a possible dragging operation. + drag_type = _drag_hit_test(Vector2(mb.get_position().x, mb.get_position().y)) + + if (drag_type != DragType.DRAG_NONE): + drag_offset = get_global_mouse_position() - get_position() + + drag_offset_far = get_position() + get_size() - get_global_mouse_position() + + elif (drag_type != DragType.DRAG_NONE && !mb.is_pressed()): + # End a dragging operation. + drag_type = DragType.DRAG_NONE + + var rect : Rect2 = get_rect() + #rect needs to be converted back + rect.position.y = edited_resource_parent_size.y * _rect_scale - rect.size.y - rect.position.y + rect.position /= _rect_scale + rect.size /= _rect_scale + + #edited_resource.set_rect(rect) + _edited_resource_event_ignore = true + _undo_redo.create_action("WE: Drag End") + _undo_redo.add_do_method(edited_resource, "set_rect", rect) + _undo_redo.add_undo_method(edited_resource, "set_rect", edited_resource.get_rect()) + _undo_redo.commit_action() + _edited_resource_event_ignore = false + + if p_event is InputEventMouseMotion: + var mm : InputEventMouseMotion = p_event as InputEventMouseMotion + + if (drag_type == DragType.DRAG_NONE): + # Update the cursor while moving along the borders. + var cursor = CURSOR_ARROW + if (!edited_resource.locked): + var preview_drag_type : int = _drag_hit_test(Vector2(mm.get_position().x, mm.get_position().y)) + + var top_left : int = DragType.DRAG_RESIZE_TOP + DragType.DRAG_RESIZE_LEFT + var bottom_right : int = DragType.DRAG_RESIZE_BOTTOM + DragType.DRAG_RESIZE_RIGHT + var top_right : int = DragType.DRAG_RESIZE_TOP + DragType.DRAG_RESIZE_RIGHT + var bottom_left : int = DragType.DRAG_RESIZE_BOTTOM + DragType.DRAG_RESIZE_LEFT + + match (preview_drag_type): + DragType.DRAG_RESIZE_TOP: + cursor = CURSOR_VSIZE + DragType.DRAG_RESIZE_BOTTOM: + cursor = CURSOR_VSIZE + DragType.DRAG_RESIZE_LEFT: + cursor = CURSOR_HSIZE + DragType.DRAG_RESIZE_RIGHT: + cursor = CURSOR_HSIZE + top_left: + cursor = CURSOR_FDIAGSIZE + bottom_right: + cursor = CURSOR_FDIAGSIZE + top_right: + cursor = CURSOR_BDIAGSIZE + bottom_left: + cursor = CURSOR_BDIAGSIZE + + if (get_cursor_shape() != cursor): + set_default_cursor_shape(cursor); + + else: + # Update while in a dragging operation. + var global_pos : Vector2 = get_global_mouse_position() + + var rect : Rect2 = get_rect() + var min_size : Vector2 = get_combined_minimum_size() + + if (drag_type == DragType.DRAG_MOVE): + rect.position = global_pos - drag_offset + else: + if (drag_type & DragType.DRAG_RESIZE_TOP): + var bottom : int = rect.position.y + rect.size.y + var max_y : int = bottom - min_size.y + rect.position.y = min(global_pos.y - drag_offset.y, max_y) + rect.size.y = bottom - rect.position.y + elif (drag_type & DragType.DRAG_RESIZE_BOTTOM): + rect.size.y = global_pos.y - rect.position.y + drag_offset_far.y + + if (drag_type & DragType.DRAG_RESIZE_LEFT): + var right : int = rect.position.x + rect.size.x + var max_x : int = right - min_size.x + rect.position.x = min(global_pos.x - drag_offset.x, max_x) + rect.size.x = right - rect.position.x + elif (drag_type & DragType.DRAG_RESIZE_RIGHT): + rect.size.x = global_pos.x - rect.position.x + drag_offset_far.x + + set_size(rect.size) + set_position(rect.position) + +#based on / ported from engine/scene/gui/dialogs.h and .cpp +func _drag_hit_test(pos : Vector2) -> int: + var drag_type : int = DragType.DRAG_NONE + + if (!edited_resource.locked): + var scaleborder_size : int = 5 #get_constant("scaleborder_size", "WindowDialog") + + var rect : Rect2 = get_rect() + + if (pos.y < (scaleborder_size)): + drag_type = DragType.DRAG_RESIZE_TOP + elif (pos.y >= (rect.size.y - scaleborder_size)): + drag_type = DragType.DRAG_RESIZE_BOTTOM + + if (pos.x < scaleborder_size): + drag_type |= DragType.DRAG_RESIZE_LEFT + elif (pos.x >= (rect.size.x - scaleborder_size)): + drag_type |= DragType.DRAG_RESIZE_RIGHT + + if (drag_type == DragType.DRAG_NONE): + drag_type = DragType.DRAG_MOVE + + return drag_type diff --git a/world_generator/ui/RectViewNode.tscn b/world_generator/ui/RectViewNode.tscn new file mode 100644 index 0000000..a1f7886 --- /dev/null +++ b/world_generator/ui/RectViewNode.tscn @@ -0,0 +1,11 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://addons/world_generator/ui/RectViewNode.gd" type="Script" id=1] + +[node name="RectViewNode" type="MarginContainer"] +margin_right = 1024.0 +margin_bottom = 600.0 +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} diff --git a/world_generator/ui/ResourcePropertyList.gd b/world_generator/ui/ResourcePropertyList.gd new file mode 100644 index 0000000..8d77e3c --- /dev/null +++ b/world_generator/ui/ResourcePropertyList.gd @@ -0,0 +1,492 @@ +tool +extends ScrollContainer + +var EditorResourceWidget : PackedScene = preload("res://addons/world_generator/widgets/EditorResourceWidget.tscn") + +var _edited_resource : WorldGenBaseResource = null +var properties : Array = Array() + +var _ignore_changed_evend : bool = false +var _refresh_queued : bool = false + +var _plugin : EditorPlugin = null +var _undo_redo : UndoRedo = null + +func set_plugin(plugin : EditorPlugin) -> void: + _plugin = plugin + _undo_redo = _plugin.get_undo_redo() + +func add_h_separator() -> int: + var hsep : HSeparator = HSeparator.new() + + var content_node = $MainContainer/Content + + content_node.add_child(hsep) + var slot_idx : int = content_node.get_child_count() - 1 + + return slot_idx + +func add_slot_color(getter : String, setter : String) -> int: + var cp : ColorPickerButton = ColorPickerButton.new() + + var slot_idx : int = add_slot(getter, setter, cp) + + cp.color = _edited_resource.call(getter) + + cp.connect("color_changed", _edited_resource, setter) + + return slot_idx + +func add_slot_label(getter : String, setter : String, slot_name : String) -> int: + var l : Label = Label.new() + + l.text = slot_name + + return add_slot(getter, setter, l) + +func add_slot_resource(getter : String, setter : String, slot_name : String, resource_type : String = "Resource") -> int: + var bc : HBoxContainer = HBoxContainer.new() + bc.set_h_size_flags(SIZE_EXPAND_FILL) + + var l : Label = Label.new() + l.text = slot_name + bc.add_child(l) + + var r : Control = EditorResourceWidget.instance() + r.set_plugin(_plugin) + r.set_resource_type(resource_type) + r.set_resource(_edited_resource.call(getter)) + r.set_h_size_flags(SIZE_EXPAND_FILL) + + bc.add_child(r) + + var slot_idx : int = add_slot(getter, setter, bc) + + r.connect("on_resource_changed", self, "on_widget_resource_changed", [ slot_idx ]) + + return slot_idx + +func add_slot_line_edit(getter : String, setter : String, slot_name : String, placeholder : String = "") -> int: + var bc : HBoxContainer = HBoxContainer.new() + bc.set_h_size_flags(SIZE_EXPAND_FILL) + + var l : Label = Label.new() + l.text = slot_name + bc.add_child(l) + + var le : LineEdit = LineEdit.new() + le.placeholder_text = placeholder + le.set_h_size_flags(SIZE_EXPAND_FILL) + bc.add_child(le) + + var slot_idx : int = add_slot(getter, setter, bc) + + le.text = _edited_resource.call(getter) + + le.connect("text_entered", self, "on_slot_line_edit_text_entered", [ slot_idx ]) + + return slot_idx + +func add_slot_enum(getter : String, setter : String, slot_name : String, values : Array) -> int: + var bc : VBoxContainer = VBoxContainer.new() + + if slot_name: + var l : Label = Label.new() + l.text = slot_name + bc.add_child(l) + + var mb : OptionButton = OptionButton.new() + + for v in values: + mb.add_item(v) + + bc.add_child(mb) + + var slot_idx : int = add_slot(getter, setter, bc) + + mb.selected = _edited_resource.call(getter) + + mb.connect("item_selected", self, "on_slot_enum_item_selected", [ slot_idx ]) + + return slot_idx + +func add_slot_int(getter : String, setter : String, slot_name : String, prange : Vector2 = Vector2(-1000, 1000)) -> int: + var bc : HBoxContainer = HBoxContainer.new() + + var l : Label = Label.new() + l.text = slot_name + l.size_flags_horizontal = SIZE_EXPAND_FILL + bc.add_child(l) + + var sb : SpinBox = SpinBox.new() + sb.rounded = true + sb.min_value = prange.x + sb.max_value = prange.y + bc.add_child(sb) + + var slot_idx : int = add_slot(getter, setter, bc) + + sb.value = _edited_resource.call(getter) + + sb.connect("value_changed", self, "on_int_spinbox_value_changed", [ slot_idx ]) + + return slot_idx + +func add_slot_bool(getter : String, setter : String, slot_name : String) -> int: + var cb : CheckBox = CheckBox.new() + cb.text = slot_name + + var slot_idx : int = add_slot(getter, setter, cb) + + cb.pressed = _edited_resource.call(getter) + + cb.connect("toggled", self, "on_checkbox_value_changed", [ slot_idx ]) + + return slot_idx + +func add_slot_float(getter : String, setter : String, slot_name : String, step : float = 0.1, prange : Vector2 = Vector2(-1000, 1000)) -> int: + var bc : HBoxContainer = HBoxContainer.new() + + var l : Label = Label.new() + l.text = slot_name + l.size_flags_horizontal = SIZE_EXPAND_FILL + bc.add_child(l) + + var sb : SpinBox = SpinBox.new() + bc.add_child(sb) + + var slot_idx : int = add_slot(getter, setter, bc) + sb.rounded = false + sb.step = step + sb.min_value = prange.x + sb.max_value = prange.y + sb.value = _edited_resource.call(getter) + + sb.connect("value_changed", self, "on_float_spinbox_value_changed", [ slot_idx ]) + + return slot_idx + +func add_slot_vector2(getter : String, setter : String, slot_name : String, step : float = 0.1, prange : Vector2 = Vector2(-1000, 1000)) -> int: + var bc : VBoxContainer = VBoxContainer.new() + + var l : Label = Label.new() + l.text = slot_name + bc.add_child(l) + + var sbx : SpinBox = SpinBox.new() + bc.add_child(sbx) + + var sby : SpinBox = SpinBox.new() + bc.add_child(sby) + + var slot_idx : int = add_slot(getter, setter, bc) + sbx.rounded = false + sby.rounded = false + sbx.step = step + sby.step = step + sbx.min_value = prange.x + sbx.max_value = prange.y + sby.min_value = prange.x + sby.max_value = prange.y + + var val : Vector2 = _edited_resource.call(getter) + + sbx.value = val.x + sby.value = val.y + + sbx.connect("value_changed", self, "on_vector2_spinbox_value_changed", [ slot_idx, sbx, sby ]) + sby.connect("value_changed", self, "on_vector2_spinbox_value_changed", [ slot_idx, sbx, sby ]) + + return slot_idx + +func add_slot_vector3(getter : String, setter : String, slot_name : String, step : float = 0.1, prange : Vector2 = Vector2(-1000, 1000)) -> int: + var bc : VBoxContainer = VBoxContainer.new() + + var l : Label = Label.new() + l.text = slot_name + bc.add_child(l) + + var sbx : SpinBox = SpinBox.new() + bc.add_child(sbx) + + var sby : SpinBox = SpinBox.new() + bc.add_child(sby) + + var sbz : SpinBox = SpinBox.new() + bc.add_child(sbz) + + var slot_idx : int = add_slot(getter, setter, bc) + sbx.rounded = false + sby.rounded = false + sbz.rounded = false + sbx.step = step + sby.step = step + sbz.step = step + sbx.min_value = prange.x + sbx.max_value = prange.y + sby.min_value = prange.x + sby.max_value = prange.y + sbz.min_value = prange.x + sbz.max_value = prange.y + + var val : Vector3 = _edited_resource.call(getter) + + sbx.value = val.x + sby.value = val.y + sbz.value = val.z + + sbx.connect("value_changed", self, "on_vector3_spinbox_value_changed", [ slot_idx, sbx, sby, sbz ]) + sby.connect("value_changed", self, "on_vector3_spinbox_value_changed", [ slot_idx, sbx, sby, sbz ]) + sbz.connect("value_changed", self, "on_vector3_spinbox_value_changed", [ slot_idx, sbx, sby, sbz ]) + + return slot_idx + + +func add_slot_rect2(getter : String, setter : String, slot_name : String, step : float = 0.1, prange : Vector2 = Vector2(-10000, 10000)) -> int: + var bc : VBoxContainer = VBoxContainer.new() + bc.size_flags_horizontal = SIZE_EXPAND_FILL + + var l : Label = Label.new() + l.text = slot_name + bc.add_child(l) + + var hc1 : HBoxContainer = HBoxContainer.new() + hc1.size_flags_horizontal = SIZE_EXPAND_FILL + bc.add_child(hc1) + + var sbx : SpinBox = SpinBox.new() + sbx.size_flags_horizontal = SIZE_EXPAND_FILL + hc1.add_child(sbx) + + var sby : SpinBox = SpinBox.new() + sby.size_flags_horizontal = SIZE_EXPAND_FILL + hc1.add_child(sby) + + var hc2 : HBoxContainer = HBoxContainer.new() + hc2.size_flags_horizontal = SIZE_EXPAND_FILL + bc.add_child(hc2) + + var sbw : SpinBox = SpinBox.new() + sbw.size_flags_horizontal = SIZE_EXPAND_FILL + hc2.add_child(sbw) + + var sbh : SpinBox = SpinBox.new() + sbh.size_flags_horizontal = SIZE_EXPAND_FILL + hc2.add_child(sbh) + + var slot_idx : int = add_slot(getter, setter, bc) + sbx.rounded = false + sby.rounded = false + sbw.rounded = false + sbh.rounded = false + sbx.step = step + sby.step = step + sbw.step = step + sbh.step = step + sbx.min_value = prange.x + sbx.max_value = prange.y + sby.min_value = prange.x + sby.max_value = prange.y + sbw.min_value = prange.x + sbw.max_value = prange.y + sbh.min_value = prange.x + sbh.max_value = prange.y + + var val : Rect2 = _edited_resource.call(getter) + + sbx.value = val.position.x + sby.value = val.position.y + sbw.value = val.size.x + sbh.value = val.size.y + + sbx.connect("value_changed", self, "on_rect2_spinbox_value_changed", [ slot_idx, [ sbx, sby, sbw, sbh ] ]) + sby.connect("value_changed", self, "on_rect2_spinbox_value_changed", [ slot_idx, [ sbx, sby, sbw, sbh ] ]) + sbw.connect("value_changed", self, "on_rect2_spinbox_value_changed", [ slot_idx, [ sbx, sby, sbw, sbh ] ]) + sbh.connect("value_changed", self, "on_rect2_spinbox_value_changed", [ slot_idx, [ sbx, sby, sbw, sbh ] ]) + + return slot_idx + +func add_slot(getter : String, setter : String, control : Control) -> int: + var content_node = $MainContainer/Content + + content_node.add_child(control) + var child_idx : int = content_node.get_child_count() - 1 + + var arr : Array = Array() + + arr.append(child_idx) + arr.append(getter) + arr.append(setter) + arr.append(control) + + properties.append(arr) + + var slot_idx : int = properties.size() - 1 + + return slot_idx + +func get_property_control(slot_idx : int) -> Node: + return properties[slot_idx][3] + +func on_int_spinbox_value_changed(val : float, slot_idx) -> void: + _ignore_changed_evend = true + + #_edited_resource.call(properties[slot_idx][2], int(val)) + + _undo_redo.create_action("WE: Set Value") + _undo_redo.add_do_method(_edited_resource, properties[slot_idx][2], int(val)) + _undo_redo.add_undo_method(_edited_resource, properties[slot_idx][2], _edited_resource.call(properties[slot_idx][1])) + _undo_redo.commit_action() + + _ignore_changed_evend = false + +func on_checkbox_value_changed(val : bool, slot_idx) -> void: + _ignore_changed_evend = true + + #_edited_resource.call(properties[slot_idx][2], val) + + _undo_redo.create_action("WE: Set Value") + _undo_redo.add_do_method(_edited_resource, properties[slot_idx][2], val) + _undo_redo.add_undo_method(_edited_resource, properties[slot_idx][2], _edited_resource.call(properties[slot_idx][1])) + _undo_redo.commit_action() + + _ignore_changed_evend = false + +func on_float_spinbox_value_changed(val : float, slot_idx) -> void: + _ignore_changed_evend = true + + #_edited_resource.call(properties[slot_idx][2], val) + + _undo_redo.create_action("WE: Set Value") + _undo_redo.add_do_method(_edited_resource, properties[slot_idx][2], val) + _undo_redo.add_undo_method(_edited_resource, properties[slot_idx][2], _edited_resource.call(properties[slot_idx][1])) + _undo_redo.commit_action() + + _ignore_changed_evend = false + +func on_vector2_spinbox_value_changed(val : float, slot_idx, spinbox_x, spinbox_y) -> void: + _ignore_changed_evend = true + var vv : Vector2 = Vector2(spinbox_x.value, spinbox_y.value) + + #_edited_resource.call(properties[slot_idx][2], vv) + + _undo_redo.create_action("WE: Set Value") + _undo_redo.add_do_method(_edited_resource, properties[slot_idx][2], vv) + _undo_redo.add_undo_method(_edited_resource, properties[slot_idx][2], _edited_resource.call(properties[slot_idx][1])) + _undo_redo.commit_action() + + _ignore_changed_evend = false + +func on_vector3_spinbox_value_changed(val : float, slot_idx, spinbox_x, spinbox_y, spinbox_z) -> void: + _ignore_changed_evend = true + var vv : Vector3 = Vector3(spinbox_x.value, spinbox_y.value, spinbox_z.value) + + #_edited_resource.call(properties[slot_idx][2], vv) + + _undo_redo.create_action("WE: Set Value") + _undo_redo.add_do_method(_edited_resource, properties[slot_idx][2], vv) + _undo_redo.add_undo_method(_edited_resource, properties[slot_idx][2], _edited_resource.call(properties[slot_idx][1])) + _undo_redo.commit_action() + + _ignore_changed_evend = false + +func on_rect2_spinbox_value_changed(val : float, slot_idx, spinboxes) -> void: + _ignore_changed_evend = true + var vv : Rect2 = Rect2(spinboxes[0].value, spinboxes[1].value, spinboxes[2].value, spinboxes[3].value) + + #_edited_resource.call(properties[slot_idx][2], vv) + + _undo_redo.create_action("WE: Set Value") + _undo_redo.add_do_method(_edited_resource, properties[slot_idx][2], vv) + _undo_redo.add_undo_method(_edited_resource, properties[slot_idx][2], _edited_resource.call(properties[slot_idx][1])) + _undo_redo.commit_action() + + _ignore_changed_evend = false + +func on_slot_enum_item_selected(val : int, slot_idx : int) -> void: + _ignore_changed_evend = true + #_edited_resource.call(properties[slot_idx][2], val) + + _undo_redo.create_action("WE: Set Value") + _undo_redo.add_do_method(_edited_resource, properties[slot_idx][2], val) + _undo_redo.add_undo_method(_edited_resource, properties[slot_idx][2], _edited_resource.call(properties[slot_idx][1])) + _undo_redo.commit_action() + + _ignore_changed_evend = false + +func on_slot_line_edit_text_entered(text : String, slot_idx : int) -> void: + _ignore_changed_evend = true + #_edited_resource.call(properties[slot_idx][2], text) + + _undo_redo.create_action("WE: Set Value") + _undo_redo.add_do_method(_edited_resource, properties[slot_idx][2], text) + _undo_redo.add_undo_method(_edited_resource, properties[slot_idx][2], _edited_resource.call(properties[slot_idx][1])) + _undo_redo.commit_action() + + _ignore_changed_evend = false + +func on_widget_resource_changed(res : Resource, slot_idx : int) -> void: + _ignore_changed_evend = true + #_edited_resource.call(properties[slot_idx][2], res) + + _undo_redo.create_action("WE: Set Value") + _undo_redo.add_do_method(_edited_resource, properties[slot_idx][2], res) + _undo_redo.add_undo_method(_edited_resource, properties[slot_idx][2], _edited_resource.call(properties[slot_idx][1])) + _undo_redo.commit_action() + + _ignore_changed_evend = false + +func clear() -> void: + properties.clear() + + var content_node = $MainContainer/Content + + if !content_node: + return + + for c in content_node.get_children(): + c.queue_free() + content_node.remove_child(c) + +func refresh() -> void: + clear() + + var cls_str : String = "[none]" + var script_str : String = "[none]" + + if _edited_resource: + cls_str = _edited_resource.get_class() + + var scr = _edited_resource.get_script() + + if scr: + script_str = scr.resource_path + + _edited_resource.setup_property_inspector(self) + + $MainContainer/HBoxContainer/ClassLE.text = cls_str + $MainContainer/HBoxContainer2/ScriptLE.text = script_str + + _refresh_queued = false + +func edit_resource(wgw) -> void: + if _edited_resource: + _edited_resource.disconnect("changed", self, "on_edited_resource_changed") + + _edited_resource = wgw + + #if !_edited_resource.is_connected("changed", self, "on_edited_resource_changed"): + if _edited_resource: + _edited_resource.connect("changed", self, "on_edited_resource_changed") + + refresh() + +func on_edited_resource_changed() -> void: + if _ignore_changed_evend: + return + + if _refresh_queued: + return + + _refresh_queued = true + call_deferred("refresh") diff --git a/world_generator/ui/ResourcePropertyList.tscn b/world_generator/ui/ResourcePropertyList.tscn new file mode 100644 index 0000000..b97e3b5 --- /dev/null +++ b/world_generator/ui/ResourcePropertyList.tscn @@ -0,0 +1,81 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://addons/world_generator/ui/ResourcePropertyList.gd" type="Script" id=1] + +[node name="ResourcePropertyList" type="ScrollContainer"] +anchor_right = 1.0 +anchor_bottom = 1.0 +rect_min_size = Vector2( 100, 0 ) +scroll_horizontal_enabled = false +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="MainContainer" type="VBoxContainer" parent="."] +margin_right = 1024.0 +margin_bottom = 90.0 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="MainContainer"] +margin_right = 1024.0 +margin_bottom = 14.0 +text = "Properties" +align = 1 +valign = 1 + +[node name="HSeparator" type="HSeparator" parent="MainContainer"] +margin_top = 18.0 +margin_right = 1024.0 +margin_bottom = 22.0 + +[node name="Content" type="VBoxContainer" parent="MainContainer"] +margin_top = 26.0 +margin_right = 1024.0 +margin_bottom = 26.0 +size_flags_horizontal = 3 + +[node name="HSeparator2" type="HSeparator" parent="MainContainer"] +margin_top = 30.0 +margin_right = 1024.0 +margin_bottom = 34.0 + +[node name="HBoxContainer" type="HBoxContainer" parent="MainContainer"] +margin_top = 38.0 +margin_right = 1024.0 +margin_bottom = 62.0 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="MainContainer/HBoxContainer"] +margin_top = 5.0 +margin_right = 37.0 +margin_bottom = 19.0 +text = "Class " +valign = 1 + +[node name="ClassLE" type="LineEdit" parent="MainContainer/HBoxContainer"] +margin_left = 41.0 +margin_right = 1024.0 +margin_bottom = 24.0 +size_flags_horizontal = 3 +editable = false + +[node name="HBoxContainer2" type="HBoxContainer" parent="MainContainer"] +margin_top = 66.0 +margin_right = 1024.0 +margin_bottom = 90.0 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="MainContainer/HBoxContainer2"] +margin_top = 5.0 +margin_right = 36.0 +margin_bottom = 19.0 +text = "Script" +valign = 1 + +[node name="ScriptLE" type="LineEdit" parent="MainContainer/HBoxContainer2"] +margin_left = 40.0 +margin_right = 1024.0 +margin_bottom = 24.0 +size_flags_horizontal = 3 +editable = false diff --git a/world_generator/ui/WorldTab.gd b/world_generator/ui/WorldTab.gd new file mode 100644 index 0000000..ece2212 --- /dev/null +++ b/world_generator/ui/WorldTab.gd @@ -0,0 +1,19 @@ +tool +extends HBoxContainer + +var edited_world + +func set_plugin(plugin : EditorPlugin) -> void: + $HSplitContainer/ResourcePropertyList.set_plugin(plugin) + $HSplitContainer/RectEditor.set_plugin(plugin) + $VBoxContainer/DataList.set_plugin(plugin) + +func refresh() -> void: + $HSplitContainer/ResourcePropertyList.edit_resource(edited_world) + $VBoxContainer/DataList.set_edited_resource(edited_world) + $HSplitContainer/RectEditor.set_edited_resource(edited_world) + +func set_wgworld(wgw : WorldGenWorld) -> void: + edited_world = wgw + + refresh() diff --git a/world_generator/ui/tabs/Continent.gd b/world_generator/ui/tabs/Continent.gd new file mode 100644 index 0000000..c4ec5b0 --- /dev/null +++ b/world_generator/ui/tabs/Continent.gd @@ -0,0 +1,56 @@ +tool +extends HBoxContainer + +var edited_world : WorldGenWorld = null +var edited_continent : Continent = null + +func _ready(): + var option_button : OptionButton = $HSplitContainer/VBoxContainer/OptionButton + option_button.connect("item_selected", self, "on_item_selected") + +func set_plugin(plugin : EditorPlugin) -> void: + $HSplitContainer/VBoxContainer/HBoxContainer2/ResourcePropertyList.set_plugin(plugin) + $HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList.set_plugin(plugin) + $HSplitContainer/RectEditor.set_plugin(plugin) + +func refresh_continent() -> void: + $HSplitContainer/VBoxContainer/HBoxContainer2/ResourcePropertyList.edit_resource(edited_continent) + $HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList.set_edited_resource(edited_continent) + $HSplitContainer/RectEditor.set_edited_resource(edited_continent) + +# if !edited_continent: +# return + +func refresh() -> void: + var option_button : OptionButton = $HSplitContainer/VBoxContainer/OptionButton + option_button.clear() + + if !edited_world: + return + + var content : Array = edited_world.get_content() + + for c in content: + if c: + option_button.add_item(c.resource_name) + option_button.set_item_metadata(option_button.get_item_count() - 1, c) + + if !edited_continent: + edited_continent = c + + refresh_continent() + +func set_wgworld(wgw : WorldGenWorld) -> void: + edited_world = wgw + + refresh() + +func set_continent(continent : Continent) -> void: + edited_continent = continent + + refresh_continent() + +func on_item_selected(idx : int) -> void: + var option_button : OptionButton = $HSplitContainer/VBoxContainer/OptionButton + + set_continent(option_button.get_item_metadata(idx)) diff --git a/world_generator/ui/tabs/Continent.tscn b/world_generator/ui/tabs/Continent.tscn new file mode 100644 index 0000000..8102c2f --- /dev/null +++ b/world_generator/ui/tabs/Continent.tscn @@ -0,0 +1,100 @@ +[gd_scene load_steps=5 format=2] + +[ext_resource path="res://addons/world_generator/ui/tabs/Continent.gd" type="Script" id=1] +[ext_resource path="res://addons/world_generator/ui/ResourcePropertyList.tscn" type="PackedScene" id=2] +[ext_resource path="res://addons/world_generator/ui/DataList.tscn" type="PackedScene" id=3] +[ext_resource path="res://addons/world_generator/ui/RectEditor.tscn" type="PackedScene" id=4] + +[node name="Continent" type="HBoxContainer"] +anchor_right = 1.0 +anchor_bottom = 1.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="HSplitContainer" type="HSplitContainer" parent="."] +margin_right = 1024.0 +margin_bottom = 600.0 +size_flags_horizontal = 3 + +[node name="RectEditor" parent="HSplitContainer" instance=ExtResource( 4 )] +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_right = 735.0 +margin_bottom = 600.0 +size_flags_horizontal = 3 + +[node name="VBoxContainer" type="VBoxContainer" parent="HSplitContainer"] +margin_left = 747.0 +margin_right = 1024.0 +margin_bottom = 600.0 + +[node name="OptionButton" type="OptionButton" parent="HSplitContainer/VBoxContainer"] +margin_right = 277.0 +margin_bottom = 20.0 + +[node name="HBoxContainer2" type="HBoxContainer" parent="HSplitContainer/VBoxContainer"] +margin_top = 24.0 +margin_right = 277.0 +margin_bottom = 600.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="ResourcePropertyList" parent="HSplitContainer/VBoxContainer/HBoxContainer2" instance=ExtResource( 2 )] +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_right = 100.0 +margin_bottom = 576.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="VBoxContainer" type="VBoxContainer" parent="HSplitContainer/VBoxContainer/HBoxContainer2"] +margin_left = 104.0 +margin_right = 277.0 +margin_bottom = 576.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="Label" type="Label" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer"] +margin_right = 173.0 +margin_bottom = 14.0 +text = "Zones" +align = 1 +valign = 1 + +[node name="HBoxContainer" type="HBoxContainer" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer"] +margin_top = 18.0 +margin_right = 173.0 +margin_bottom = 38.0 + +[node name="AddButton" type="Button" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer"] +margin_right = 37.0 +margin_bottom = 20.0 +text = "Add" + +[node name="DeleteButton" type="Button" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer"] +margin_left = 41.0 +margin_right = 96.0 +margin_bottom = 20.0 +text = "Delete" + +[node name="Duplicate" type="Button" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer"] +margin_left = 100.0 +margin_right = 173.0 +margin_bottom = 20.0 +text = "Duplicate" + +[node name="DataList" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer" instance=ExtResource( 3 )] +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_top = 42.0 +margin_right = 173.0 +margin_bottom = 576.0 +class_types = 1 + +[connection signal="pressed" from="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer/AddButton" to="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList" method="add_button_pressed"] +[connection signal="pressed" from="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer/DeleteButton" to="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList" method="delete_button_pressed"] +[connection signal="pressed" from="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer/Duplicate" to="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList" method="duplicate_button_pressed"] diff --git a/world_generator/ui/tabs/SubZone.gd b/world_generator/ui/tabs/SubZone.gd new file mode 100644 index 0000000..5da25cb --- /dev/null +++ b/world_generator/ui/tabs/SubZone.gd @@ -0,0 +1,122 @@ +tool +extends HBoxContainer + +var edited_world : WorldGenWorld = null +var edited_continent : Continent = null +var edited_zone : Zone = null +var edited_sub_zone : SubZone = null + +func _ready(): + var coption_button : OptionButton = $VBoxContainer/ContinentOptionButton + coption_button.connect("item_selected", self, "on_continent_item_selected") + + var zoption_button : OptionButton = $VBoxContainer/ZoneOptionButton + zoption_button.connect("item_selected", self, "on_zone_item_selected") + + var szoption_button : OptionButton = $VBoxContainer/SubZoneOptionButton + szoption_button.connect("item_selected", self, "on_sub_zone_item_selected") + +func set_plugin(plugin : EditorPlugin) -> void: + $VBoxContainer/HBoxContainer2/ResourcePropertyList.set_plugin(plugin) + +func continent_changed() -> void: + var option_button : OptionButton = $VBoxContainer/ZoneOptionButton + option_button.clear() + edited_zone = null + edited_sub_zone = null + + if !edited_continent: + return + + var content : Array = edited_continent.get_content() + + for c in content: + if c: + option_button.add_item(c.resource_name) + option_button.set_item_metadata(option_button.get_item_count() - 1, c) + + if !edited_zone: + edited_zone = c + + zone_changed() + +func zone_changed() -> void: + var option_button : OptionButton = $VBoxContainer/SubZoneOptionButton + option_button.clear() + edited_sub_zone = null + + if !edited_zone: + return + + var content : Array = edited_zone.get_content() + + for c in content: + if c: + option_button.add_item(c.resource_name) + option_button.set_item_metadata(option_button.get_item_count() - 1, c) + + if !edited_sub_zone: + edited_sub_zone = c + + sub_zone_changed() + + +func sub_zone_changed() -> void: + $VBoxContainer/HBoxContainer2/ResourcePropertyList.edit_resource(edited_sub_zone) + +func refresh() -> void: + var option_button : OptionButton = $VBoxContainer/ContinentOptionButton + option_button.clear() + + if !edited_world: + return + + var content : Array = edited_world.get_content() + + for c in content: + if c: + option_button.add_item(c.resource_name) + option_button.set_item_metadata(option_button.get_item_count() - 1, c) + + if !edited_continent: + edited_continent = c + + continent_changed() + +func set_wgworld(wgw : WorldGenWorld) -> void: + edited_world = wgw + edited_continent = null + edited_zone = null + + refresh() + +func set_continent(continent : Continent) -> void: + edited_continent = continent + edited_zone = null + + continent_changed() + +func set_zone(zone : Zone) -> void: + edited_zone = zone + + zone_changed() + +func set_sub_zone(sub_zone : SubZone) -> void: + edited_sub_zone = sub_zone + + sub_zone_changed() + +func on_continent_item_selected(idx : int) -> void: + var option_button : OptionButton = $VBoxContainer/ContinentOptionButton + + set_continent(option_button.get_item_metadata(idx)) + +func on_zone_item_selected(idx : int) -> void: + var option_button : OptionButton = $VBoxContainer/ZoneOptionButton + + set_zone(option_button.get_item_metadata(idx)) + +func on_sub_zone_item_selected(idx : int) -> void: + var option_button : OptionButton = $VBoxContainer/SubZoneOptionButton + + set_sub_zone(option_button.get_item_metadata(idx)) diff --git a/world_generator/ui/tabs/SubZone.tscn b/world_generator/ui/tabs/SubZone.tscn new file mode 100644 index 0000000..45d5eb6 --- /dev/null +++ b/world_generator/ui/tabs/SubZone.tscn @@ -0,0 +1,49 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://addons/world_generator/ui/tabs/SubZone.gd" type="Script" id=1] +[ext_resource path="res://addons/world_generator/ui/ResourcePropertyList.tscn" type="PackedScene" id=2] + +[node name="SubZone" type="HBoxContainer"] +anchor_right = 1.0 +anchor_bottom = 1.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +margin_right = 1024.0 +margin_bottom = 600.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="ContinentOptionButton" type="OptionButton" parent="VBoxContainer"] +margin_right = 1024.0 +margin_bottom = 20.0 + +[node name="ZoneOptionButton" type="OptionButton" parent="VBoxContainer"] +margin_top = 24.0 +margin_right = 1024.0 +margin_bottom = 44.0 + +[node name="SubZoneOptionButton" type="OptionButton" parent="VBoxContainer"] +margin_top = 48.0 +margin_right = 1024.0 +margin_bottom = 68.0 + +[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer"] +margin_top = 72.0 +margin_right = 1024.0 +margin_bottom = 600.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="ResourcePropertyList" parent="VBoxContainer/HBoxContainer2" instance=ExtResource( 2 )] +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_right = 1024.0 +margin_bottom = 528.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 diff --git a/world_generator/ui/tabs/World.tscn b/world_generator/ui/tabs/World.tscn new file mode 100644 index 0000000..2526008 --- /dev/null +++ b/world_generator/ui/tabs/World.tscn @@ -0,0 +1,82 @@ +[gd_scene load_steps=5 format=2] + +[ext_resource path="res://addons/world_generator/ui/ResourcePropertyList.tscn" type="PackedScene" id=2] +[ext_resource path="res://addons/world_generator/ui/WorldTab.gd" type="Script" id=5] +[ext_resource path="res://addons/world_generator/ui/DataList.tscn" type="PackedScene" id=6] +[ext_resource path="res://addons/world_generator/ui/RectEditor.tscn" type="PackedScene" id=7] + +[node name="World" type="HBoxContainer"] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 4.0 +margin_top = 32.0 +margin_right = -4.0 +margin_bottom = -4.0 +script = ExtResource( 5 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="HSplitContainer" type="HSplitContainer" parent="."] +margin_right = 839.0 +margin_bottom = 564.0 +size_flags_horizontal = 3 + +[node name="RectEditor" parent="HSplitContainer" instance=ExtResource( 7 )] +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_right = 727.0 +margin_bottom = 564.0 +size_flags_horizontal = 3 + +[node name="ResourcePropertyList" parent="HSplitContainer" instance=ExtResource( 2 )] +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 739.0 +margin_right = 839.0 +margin_bottom = 564.0 + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +margin_left = 843.0 +margin_right = 1016.0 +margin_bottom = 564.0 + +[node name="Label" type="Label" parent="VBoxContainer"] +margin_right = 173.0 +margin_bottom = 14.0 +text = "Continents" +align = 1 +valign = 1 + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] +margin_top = 18.0 +margin_right = 173.0 +margin_bottom = 38.0 + +[node name="AddButton" type="Button" parent="VBoxContainer/HBoxContainer"] +margin_right = 37.0 +margin_bottom = 20.0 +text = "Add" + +[node name="DeleteButton" type="Button" parent="VBoxContainer/HBoxContainer"] +margin_left = 41.0 +margin_right = 96.0 +margin_bottom = 20.0 +text = "Delete" + +[node name="Duplicate" type="Button" parent="VBoxContainer/HBoxContainer"] +margin_left = 100.0 +margin_right = 173.0 +margin_bottom = 20.0 +text = "Duplicate" + +[node name="DataList" parent="VBoxContainer" instance=ExtResource( 6 )] +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_top = 42.0 +margin_right = 173.0 +margin_bottom = 564.0 + +[connection signal="pressed" from="VBoxContainer/HBoxContainer/AddButton" to="VBoxContainer/DataList" method="add_button_pressed"] +[connection signal="pressed" from="VBoxContainer/HBoxContainer/DeleteButton" to="VBoxContainer/DataList" method="delete_button_pressed"] +[connection signal="pressed" from="VBoxContainer/HBoxContainer/Duplicate" to="VBoxContainer/DataList" method="duplicate_button_pressed"] diff --git a/world_generator/ui/tabs/Zone.gd b/world_generator/ui/tabs/Zone.gd new file mode 100644 index 0000000..7ea49b7 --- /dev/null +++ b/world_generator/ui/tabs/Zone.gd @@ -0,0 +1,92 @@ +tool +extends HBoxContainer + +var edited_world : WorldGenWorld = null +var edited_continent : Continent = null +var edited_zone : Zone = null + +func _ready(): + var coption_button : OptionButton = $HSplitContainer/VBoxContainer/ContinentOptionButton + coption_button.connect("item_selected", self, "on_continent_item_selected") + + var zoption_button : OptionButton = $HSplitContainer/VBoxContainer/ZoneOptionButton + zoption_button.connect("item_selected", self, "on_zone_item_selected") + +func set_plugin(plugin : EditorPlugin) -> void: + $HSplitContainer/VBoxContainer/HBoxContainer2/ResourcePropertyList.set_plugin(plugin) + $HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList.set_plugin(plugin) + $HSplitContainer/RectEditor.set_plugin(plugin) + +func refresh() -> void: + var option_button : OptionButton = $HSplitContainer/VBoxContainer/ContinentOptionButton + option_button.clear() + edited_continent = null + edited_zone = null + + if !edited_world: + return + + var content : Array = edited_world.get_content() + + for c in content: + if c: + option_button.add_item(c.resource_name) + option_button.set_item_metadata(option_button.get_item_count() - 1, c) + + if !edited_continent: + edited_continent = c + + continent_changed() + +func continent_changed() -> void: + var option_button : OptionButton = $HSplitContainer/VBoxContainer/ZoneOptionButton + option_button.clear() + edited_zone = null + + if !edited_continent: + return + + var content : Array = edited_continent.get_content() + + for c in content: + if c: + option_button.add_item(c.resource_name) + option_button.set_item_metadata(option_button.get_item_count() - 1, c) + + if !edited_zone: + edited_zone = c + + zone_changed() + +func zone_changed() -> void: + $HSplitContainer/VBoxContainer/HBoxContainer2/ResourcePropertyList.edit_resource(edited_zone) + $HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList.set_edited_resource(edited_zone) + $HSplitContainer/RectEditor.set_edited_resource(edited_zone) + +func set_continent(continent : Continent) -> void: + edited_continent = continent + edited_zone = null + + continent_changed() + +func set_zone(zone : Zone) -> void: + edited_zone = zone + + zone_changed() + +func set_wgworld(wgw : WorldGenWorld) -> void: + edited_world = wgw + edited_continent = null + edited_zone = null + + refresh() + +func on_continent_item_selected(idx : int) -> void: + var option_button : OptionButton = $HSplitContainer/VBoxContainer/ContinentOptionButton + + set_continent(option_button.get_item_metadata(idx)) + +func on_zone_item_selected(idx : int) -> void: + var option_button : OptionButton = $HSplitContainer/VBoxContainer/ZoneOptionButton + + set_zone(option_button.get_item_metadata(idx)) diff --git a/world_generator/ui/tabs/Zone.tscn b/world_generator/ui/tabs/Zone.tscn new file mode 100644 index 0000000..a113ff0 --- /dev/null +++ b/world_generator/ui/tabs/Zone.tscn @@ -0,0 +1,105 @@ +[gd_scene load_steps=5 format=2] + +[ext_resource path="res://addons/world_generator/ui/tabs/Zone.gd" type="Script" id=1] +[ext_resource path="res://addons/world_generator/ui/ResourcePropertyList.tscn" type="PackedScene" id=2] +[ext_resource path="res://addons/world_generator/ui/DataList.tscn" type="PackedScene" id=3] +[ext_resource path="res://addons/world_generator/ui/RectEditor.tscn" type="PackedScene" id=4] + +[node name="Zone" type="HBoxContainer"] +anchor_right = 1.0 +anchor_bottom = 1.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="HSplitContainer" type="HSplitContainer" parent="."] +margin_right = 1024.0 +margin_bottom = 600.0 +size_flags_horizontal = 3 + +[node name="RectEditor" parent="HSplitContainer" instance=ExtResource( 4 )] +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_right = 735.0 +margin_bottom = 600.0 +size_flags_horizontal = 3 + +[node name="VBoxContainer" type="VBoxContainer" parent="HSplitContainer"] +margin_left = 747.0 +margin_right = 1024.0 +margin_bottom = 600.0 + +[node name="ContinentOptionButton" type="OptionButton" parent="HSplitContainer/VBoxContainer"] +margin_right = 277.0 +margin_bottom = 20.0 + +[node name="ZoneOptionButton" type="OptionButton" parent="HSplitContainer/VBoxContainer"] +margin_top = 24.0 +margin_right = 277.0 +margin_bottom = 44.0 + +[node name="HBoxContainer2" type="HBoxContainer" parent="HSplitContainer/VBoxContainer"] +margin_top = 48.0 +margin_right = 277.0 +margin_bottom = 600.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="ResourcePropertyList" parent="HSplitContainer/VBoxContainer/HBoxContainer2" instance=ExtResource( 2 )] +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_right = 100.0 +margin_bottom = 552.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="VBoxContainer" type="VBoxContainer" parent="HSplitContainer/VBoxContainer/HBoxContainer2"] +margin_left = 104.0 +margin_right = 277.0 +margin_bottom = 552.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="Label" type="Label" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer"] +margin_right = 173.0 +margin_bottom = 14.0 +text = "Sub Zones" +align = 1 +valign = 1 + +[node name="HBoxContainer" type="HBoxContainer" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer"] +margin_top = 18.0 +margin_right = 173.0 +margin_bottom = 38.0 + +[node name="AddButton" type="Button" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer"] +margin_right = 37.0 +margin_bottom = 20.0 +text = "Add" + +[node name="DeleteButton" type="Button" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer"] +margin_left = 41.0 +margin_right = 96.0 +margin_bottom = 20.0 +text = "Delete" + +[node name="Duplicate" type="Button" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer"] +margin_left = 100.0 +margin_right = 173.0 +margin_bottom = 20.0 +text = "Duplicate" + +[node name="DataList" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer" instance=ExtResource( 3 )] +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_top = 42.0 +margin_right = 173.0 +margin_bottom = 552.0 +class_types = 2 + +[connection signal="pressed" from="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer/AddButton" to="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList" method="add_button_pressed"] +[connection signal="pressed" from="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer/DeleteButton" to="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList" method="delete_button_pressed"] +[connection signal="pressed" from="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer/Duplicate" to="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList" method="duplicate_button_pressed"] diff --git a/world_generator/widgets/EditorResourceWidget.gd b/world_generator/widgets/EditorResourceWidget.gd new file mode 100644 index 0000000..a73924e --- /dev/null +++ b/world_generator/widgets/EditorResourceWidget.gd @@ -0,0 +1,80 @@ +tool +extends HBoxContainer + +var _resource_type : String = "Resource" +var _resource : Resource = null +var _plugin : EditorPlugin = null + +signal on_resource_changed(new_res) + +func _enter_tree(): + $ResourceButton.set_drag_forwarding(self) + +func set_resource_type(type : String) -> void: + _resource_type = type + +func set_resource(res : Resource) -> void: + if res && !res.is_class(_resource_type): + return + + var emit : bool = res != _resource + + _resource = res + + refresh_ui() + + if emit: + emit_signal("on_resource_changed", _resource) + +func refresh_ui() -> void: + if _resource: + var text : String = _resource.resource_name + + if text == "": + text = _resource.get_class() + + $ResourceButton.text = text + else: + $ResourceButton.text = "[null]" + +func on_clear_button_pressed() -> void: + if _resource: + set_resource(null) + +func on_resource_button_pressed() -> void: + if _resource && _plugin: + _plugin.get_editor_interface().inspect_object(_resource) + +#examples +#{files:[res://modules/planets/test_planet/test_world.tres], from:@@4176:[Tree:9070], type:files} +#{from:Button:[Button:917001], resource:[Resource:26180], type:resource} + +func can_drop_data_fw(position, data, from_control): + return true + +func drop_data_fw(position, data, from_control): + if data["type"] == "resource": + var res : Resource = data["resource"] + set_resource(res) + elif data["type"] == "files": + var files : Array = data["files"] + + for f in files: + var res : Resource = load(f) + set_resource(res) + return + +func get_drag_data_fw(position, from_control): + if !_resource: + return + + var d : Dictionary = Dictionary() + + d["from"] = self + d["resource"] = _resource + d["type"] = "resource" + + return d + +func set_plugin(plugin : EditorPlugin) -> void: + _plugin = plugin diff --git a/world_generator/widgets/EditorResourceWidget.tscn b/world_generator/widgets/EditorResourceWidget.tscn new file mode 100644 index 0000000..f5f3bfe --- /dev/null +++ b/world_generator/widgets/EditorResourceWidget.tscn @@ -0,0 +1,23 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://addons/world_generator/widgets/EditorResourceWidget.gd" type="Script" id=1] + +[node name="EditorResourceWidget" type="HBoxContainer"] +margin_right = 376.0 +margin_bottom = 40.0 +script = ExtResource( 1 ) + +[node name="ResourceButton" type="Button" parent="."] +margin_right = 342.0 +margin_bottom = 40.0 +size_flags_horizontal = 3 + +[node name="Clear" type="Button" parent="."] +margin_left = 346.0 +margin_right = 376.0 +margin_bottom = 40.0 +rect_min_size = Vector2( 30, 0 ) +text = "X" + +[connection signal="pressed" from="ResourceButton" to="." method="on_resource_button_pressed"] +[connection signal="pressed" from="Clear" to="." method="on_clear_button_pressed"] diff --git a/world_generator/widgets/EditorZoomWidget.gd b/world_generator/widgets/EditorZoomWidget.gd new file mode 100644 index 0000000..c0579b6 --- /dev/null +++ b/world_generator/widgets/EditorZoomWidget.gd @@ -0,0 +1,218 @@ +tool +extends HBoxContainer + +#This is a port of godot 4.0's EditorZoomWidget + +#/*************************************************************************/ +#/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +#/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +#/* */ +#/* Permission is hereby granted, free of charge, to any person obtaining */ +#/* a copy of this software and associated documentation files (the */ +#/* "Software"), to deal in the Software without restriction, including */ +#/* without limitation the rights to use, copy, modify, merge, publish, */ +#/* distribute, sublicense, and/or sell copies of the Software, and to */ +#/* permit persons to whom the Software is furnished to do so, subject to */ +#/* the following conditions: */ +#/* */ +#/* The above copyright notice and this permission notice shall be */ +#/* included in all copies or substantial portions of the Software. */ +#/* */ +#/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +#/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +#/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +#/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +#/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +#/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +#/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#/*************************************************************************/ + +var zoom_minus : Button +var zoom_reset : Button +var zoom_plus : Button + +var EDSCALE : float = 1 + +export(float) var zoom : float = 1.0 setget set_zoom, get_zoom + +signal zoom_changed(zoom) + +func _init() -> void: + # Zoom buttons + zoom_minus = Button.new() + zoom_minus.set_flat(true) + add_child(zoom_minus) + zoom_minus.connect("pressed", self, "_button_zoom_minus") + zoom_minus.set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_minus", tr("Zoom Out"), KEY_MASK_CMD | KEY_MINUS)) + zoom_minus.set_focus_mode(FOCUS_NONE) + + zoom_reset = Button.new() + zoom_reset.set_flat(true) + add_child(zoom_reset) + zoom_reset.add_constant_override("outline_size", 1) + zoom_reset.add_color_override("font_outline_color", Color(0, 0, 0)) + zoom_reset.add_color_override("font_color", Color(1, 1, 1)) + zoom_reset.connect("pressed", self, "_button_zoom_reset") + zoom_reset.set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_reset", tr("Zoom Reset"), KEY_MASK_CMD | KEY_0)) + zoom_reset.set_focus_mode(FOCUS_NONE) + #Prevent the button's size from changing when the text size changes + zoom_reset.set_custom_minimum_size(Vector2(75, 0)) + + zoom_plus = Button.new() + zoom_plus.set_flat(true) + add_child(zoom_plus) + zoom_plus.connect("pressed", self, "_button_zoom_plus") + zoom_plus.set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_plus", tr("Zoom In"), KEY_MASK_CMD | KEY_EQUAL)) # Usually direct access key for PLUS + zoom_plus.set_focus_mode(FOCUS_NONE) + + _update_zoom_label() + + add_constant_override("separation", round(-8)) + +func get_zoom() -> float: + return zoom + +func set_zoom(p_zoom : float) -> void: + if (p_zoom > 0 && p_zoom != zoom): + zoom = p_zoom; + _update_zoom_label(); + +func set_zoom_by_increments(p_increment_count : int, p_integer_only : bool) -> void: + # Remove editor scale from the index computation. + var zoom_noscale : float = zoom / max(1, EDSCALE) + var CMP_EPSILON : float = 0.00001 + + if (p_integer_only): + # Only visit integer scaling factors above 100%, and fractions with an integer denominator below 100% + # (1/2 = 50%, 1/3 = 33.33%, 1/4 = 25%, …). + # This is useful when working on pixel art projects to avoid distortion. + # This algorithm is designed to handle fractional start zoom values correctly + # (e.g. 190% will zoom up to 200% and down to 100%). + if (zoom_noscale + p_increment_count * 0.001 >= 1.0 - CMP_EPSILON): + # New zoom is certain to be above 100%. + if (p_increment_count >= 1): + # Zooming. + set_zoom(floor(zoom_noscale + p_increment_count) * max(1, EDSCALE)) + else: + # Dezooming. + set_zoom(ceil(zoom_noscale + p_increment_count) * max(1, EDSCALE)) + else: + if (p_increment_count >= 1): + # Zooming. Convert the current zoom into a denominator. + var new_zoom : float = 1.0 / ceil(1.0 / zoom_noscale - p_increment_count) + if (is_equal_approx(zoom_noscale, new_zoom)): + # New zoom is identical to the old zoom, so try again. + # This can happen due to floating-point precision issues. + new_zoom = 1.0 / ceil(1.0 / zoom_noscale - p_increment_count - 1) + + set_zoom(new_zoom * max(1, EDSCALE)); + else: + # Dezooming. Convert the current zoom into a denominator. + var new_zoom : float = 1.0 / floor(1.0 / zoom_noscale - p_increment_count) + if (is_equal_approx(zoom_noscale, new_zoom)): + # New zoom is identical to the old zoom, so try again. + # This can happen due to floating-point precision issues. + new_zoom = 1.0 / floor(1.0 / zoom_noscale - p_increment_count + 1) + + set_zoom(new_zoom * max(1, EDSCALE)) + else: + # Base increment factor defined as the twelveth root of two. + # This allow a smooth geometric evolution of the zoom, with the advantage of + # visiting all integer power of two scale factors. + # note: this is analogous to the 'semitones' interval in the music world + # In order to avoid numerical imprecisions, we compute and edit a zoom index + # with the following relation: zoom = 2 ^ (index / 12) + + if (zoom < CMP_EPSILON || p_increment_count == 0): + return + + # zoom = 2**(index/12) => log2(zoom) = index/12 + var closest_zoom_index : float = round(log(zoom_noscale) * 12.0 / log(2.0)) + + var new_zoom_index : float = closest_zoom_index + p_increment_count + var new_zoom : float = pow(2.0, new_zoom_index / 12.0) + + # Restore Editor scale transformation + new_zoom *= max(1, EDSCALE) + + set_zoom(new_zoom) + + +func _update_zoom_label() -> void: + var zoom_text : String = "" + + # The zoom level displayed is relative to the editor scale + # (like in most image editors). Its lower bound is clamped to 1 as some people + # lower the editor scale to increase the available real estate, + # even if their display doesn't have a particularly low DPI. + + if (zoom >= 10): + # Don't show a decimal when the zoom level is higher than 1000 %. + #zoom_text = (rtos(round((zoom / max(1, EDSCALE)) * 100))) + " %" + zoom_text = (String(round((zoom / max(1, EDSCALE)) * 100))) + " %" + else: + var v : float = (zoom / max(1, EDSCALE)) * 100 + var val : float = floor(v / 0.1 + 0.5) * 0.1 + +# zoom_text = (rtos(val)) + " %" + zoom_text = (String(val)) + " %" + + zoom_reset.set_text(zoom_text) + +func _button_zoom_minus() -> void: + set_zoom_by_increments(-6, Input.is_key_pressed(KEY_ALT)); + emit_signal("zoom_changed", zoom); + +func _button_zoom_reset() -> void: + set_zoom(1.0 * max(1, EDSCALE)); + emit_signal("zoom_changed", zoom); + +func _button_zoom_plus() -> void: + set_zoom_by_increments(6, Input.is_key_pressed(KEY_ALT)); + emit_signal("zoom_changed", zoom); + +func _notification(p_what : int) -> void: + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED): + zoom_minus.icon = get_icon("ZoomLess", "EditorIcons") + zoom_plus.icon = get_icon("ZoomMore", "EditorIcons") + +#from godot editor/editor_Settings.cpp +func ED_SHORTCUT(p_path : String, p_name : String, p_keycode : int, editor_settings : EditorSettings = null) -> ShortCut: + if OS.get_name() == "OSX": + # Use Cmd+Backspace as a general replacement for Delete shortcuts on macOS + if (p_keycode == KEY_DELETE): + p_keycode = KEY_MASK_CMD | KEY_BACKSPACE + + var ie : InputEventKey = null + if (p_keycode): + ie = InputEventKey.new() + + ie.set_unicode(p_keycode & KEY_CODE_MASK) + ie.set_scancode(p_keycode & KEY_CODE_MASK) + ie.set_shift(bool(p_keycode & KEY_MASK_SHIFT)) + ie.set_alt(bool(p_keycode & KEY_MASK_ALT)) + ie.set_control(bool(p_keycode & KEY_MASK_CTRL)) + ie.set_metakey(bool(p_keycode & KEY_MASK_META)) + + if (!editor_settings): + var sc : ShortCut + sc = ShortCut.new() + sc.set_name(p_name) + sc.set_shortcut(ie) + sc.set_meta("original", ie) + return sc + + var sc : ShortCut = editor_settings.get_shortcut(p_path) + if (sc.is_valid()): + sc.set_name(p_name); #keep name (the ones that come from disk have no name) + sc.set_meta("original", ie); #to compare against changes + return sc; + + sc = ShortCut.new() + sc.set_name(p_name) + sc.set_shortcut(ie) + sc.set_meta("original", ie) #to compare against changes + editor_settings.add_shortcut(p_path, sc) + + return sc + diff --git a/world_generator/widgets/EditorZoomWidget.tscn b/world_generator/widgets/EditorZoomWidget.tscn new file mode 100644 index 0000000..5de87a9 --- /dev/null +++ b/world_generator/widgets/EditorZoomWidget.tscn @@ -0,0 +1,8 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://addons/world_generator/widgets/EditorZoomWidget.gd" type="Script" id=1] + +[node name="EditorZoomWidget" type="HBoxContainer"] +anchor_right = 1.0 +anchor_bottom = 1.0 +script = ExtResource( 1 )