feat: selection tracking

This commit is contained in:
Sara Gerretsen 2025-12-12 22:28:04 +01:00
parent 4aa1075fb6
commit cb43179770
15 changed files with 217 additions and 20 deletions

View file

@ -0,0 +1,51 @@
#include "layer_editor.h"
#include "scene/resources/packed_scene.h"
void LayerEditor::_bind_methods() {
String hint_string{ vformat("StringName;%s/%s:PackedScene", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE) };
BIND_HPROPERTY(Variant::DICTIONARY, inspectors, PROPERTY_HINT_DICTIONARY_TYPE, hint_string);
BIND_HPROPERTY(Variant::OBJECT, terrain, PROPERTY_HINT_NODE_TYPE, "TerrainMeshEditor");
}
void LayerEditor::deselect_current() {
if (this->current_inspector) {
this->current_inspector->queue_free();
}
this->current_inspector = nullptr;
}
void LayerEditor::select(Ref<TerrainPrimitive> primitive) {
deselect_current();
if (primitive.is_valid() && this->inspectors.has(primitive->get_class())) {
this->current_inspector = this->inspectors.get(primitive->get_class())->instantiate();
add_child(this->current_inspector);
}
}
void LayerEditor::set_inspectors(Dictionary dict) {
this->inspectors.clear();
for (KeyValue<Variant, Variant> kvp : dict) {
StringName name{ kvp.key };
Ref<PackedScene> value{ kvp.value };
this->inspectors.insert(name, value);
}
}
Dictionary LayerEditor::get_inspectors() const {
Dictionary r;
for (KeyValue<StringName, Ref<PackedScene>> const &kvp : this->inspectors) {
r[kvp.key] = kvp.value;
}
return r;
}
void LayerEditor::set_terrain(TerrainMeshEditor *editor) {
this->terrain = editor;
if (editor && !Engine::get_singleton()->is_editor_hint()) {
editor->connect(TerrainMeshEditor::sig_selection_changed, callable_mp(this, &self_type::select));
}
}
TerrainMeshEditor *LayerEditor::get_terrain() const {
return this->terrain;
}

View file

@ -0,0 +1,24 @@
#pragma once
#include "scene/gui/tab_container.h"
#include "terrain_editor/terrain_mesh_editor.h"
#include "terrain_primitive.h"
class LayerEditor : public TabContainer {
GDCLASS(LayerEditor, TabContainer);
static void _bind_methods();
protected:
public:
void deselect_current();
void select(Ref<TerrainPrimitive> primitive);
void set_inspectors(Dictionary dict);
Dictionary get_inspectors() const;
void set_terrain(TerrainMeshEditor *terrain);
TerrainMeshEditor *get_terrain() const;
private:
HashMap<StringName, Ref<PackedScene>> inspectors{};
Node *current_inspector{ nullptr };
TerrainMeshEditor *terrain{ nullptr };
};

View file

@ -9,7 +9,7 @@
#include <cstdint>
void PrimitiveLayerList::_bind_methods() {
BIND_HPROPERTY(Variant::OBJECT, terrain, PROPERTY_HINT_NODE_TYPE, "TerrainMeshGenerator");
BIND_HPROPERTY(Variant::OBJECT, terrain, PROPERTY_HINT_NODE_TYPE, "TerrainMeshEditor");
BIND_HPROPERTY(Variant::DICTIONARY, icons, PROPERTY_HINT_DICTIONARY_TYPE, "StringName;Texture2D");
}
@ -27,15 +27,15 @@ void PrimitiveLayerList::generate_subtree(size_t idx, Ref<TerrainPrimitive> prim
base->set_text(NAME_COLUMN, prim->get_name().is_empty() ? prim->get_class() : prim->get_name());
base->set_editable(NAME_COLUMN, true);
base->set_expand_right(NAME_COLUMN, true);
this->subtrees.insert(prim, base);
}
void PrimitiveLayerList::regenerate_tree(Array array) {
get_root()->clear_children();
this->subtrees.clear();
this->primitives.clear();
size_t i{ 0 };
for (Variant var : array) {
Ref<TerrainPrimitive> prim{ var };
this->primitives.push_back(prim);
if (prim.is_valid()) {
generate_subtree(i, prim, get_root());
++i;
@ -88,6 +88,16 @@ void PrimitiveLayerList::item_edited() {
}
}
void PrimitiveLayerList::item_selected() {
TreeItem *item{ get_selected() };
int64_t const idx{ item->get_text(IDX_COLUMN).to_int() };
if (idx < this->primitives.size() && idx >= 0) {
this->terrain->set_current_selected(this->primitives[idx]);
} else {
this->terrain->set_current_selected(nullptr);
}
}
void PrimitiveLayerList::_notification(int what) {
if (Engine::get_singleton()->is_editor_hint()) {
return;
@ -97,6 +107,7 @@ void PrimitiveLayerList::_notification(int what) {
return;
case NOTIFICATION_READY:
connect("item_edited", callable_mp(this, &self_type::item_edited));
connect("item_selected", callable_mp(this, &self_type::item_selected));
create_item();
set_columns(COLUMN_MAX);
set_hide_root(true);
@ -126,10 +137,10 @@ Dictionary PrimitiveLayerList::get_icons() const {
return dict;
}
void PrimitiveLayerList::set_terrain(TerrainMeshGenerator *terrain) {
void PrimitiveLayerList::set_terrain(TerrainMeshEditor *terrain) {
this->terrain = terrain;
}
TerrainMeshGenerator *PrimitiveLayerList::get_terrain() const {
TerrainMeshEditor *PrimitiveLayerList::get_terrain() const {
return this->terrain;
}

View file

@ -2,7 +2,7 @@
#include "core/templates/hash_map.h"
#include "scene/gui/tree.h"
#include "terrain_editor/terrain_mesh_generator.h"
#include "terrain_editor/terrain_mesh_editor.h"
#include "terrain_editor/terrain_primitive.h"
class PrimitiveLayerList : public Tree {
@ -19,6 +19,7 @@ class PrimitiveLayerList : public Tree {
void switch_index(size_t from, size_t to);
void layer_renamed(TreeItem *item);
void item_edited();
void item_selected();
protected:
void _notification(int what);
@ -26,12 +27,12 @@ protected:
public:
void set_icons(Dictionary dict);
Dictionary get_icons() const;
void set_terrain(TerrainMeshGenerator *generator);
TerrainMeshGenerator *get_terrain() const;
void set_terrain(TerrainMeshEditor *generator);
TerrainMeshEditor *get_terrain() const;
private:
HashMap<StringName, Ref<Texture2D>> icons{};
TerrainMeshGenerator *terrain{};
TerrainMeshEditor *terrain{};
HashMap<Ref<TerrainPrimitive>, TreeItem *> subtrees{};
Vector<Ref<TerrainPrimitive>> primitives{};
};

View file

@ -4,6 +4,7 @@
#include "core/object/class_db.h"
#include "terrain_editor/add_primitive_button.h"
#include "terrain_editor/edit_history.h"
#include "terrain_editor/layer_editor.h"
#include "terrain_editor/point_primitive_node.h"
#include "terrain_editor/primitive_layer_list.h"
#include "terrain_editor/terrain_chunk.h"
@ -29,6 +30,7 @@ void initialize_terrain_editor_module(ModuleInitializationLevel p_level) {
Engine::get_singleton()->add_singleton(Engine::Singleton("EditHistory", (EditHistory::singleton_instance = memnew(EditHistory)), "EditHistory"));
ClassDB::register_class<PrimitiveLayerList>();
ClassDB::register_class<AddPrimitiveButton>();
ClassDB::register_class<LayerEditor>();
}
void uninitialize_terrain_editor_module(ModuleInitializationLevel p_level) {

View file

@ -1,6 +1,5 @@
#include "terrain_mesh_editor.h"
#include "core/input/input_event.h"
#include "core/io/file_access.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/os/keyboard.h"
@ -36,9 +35,13 @@ Array SaveData::get_primitives() const {
return this->primitives;
}
String const TerrainMeshEditor::sig_selection_changed{ "selection_changed" };
void TerrainMeshEditor::_bind_methods() {
BIND_HPROPERTY(Variant::OBJECT, point_primitive_object, PROPERTY_HINT_RESOURCE_TYPE, "PackedScene");
ClassDB::bind_method(D_METHOD("save_data"), &self_type::save_data);
BIND_HPROPERTY(Variant::OBJECT, current_selected, PROPERTY_HINT_RESOURCE_TYPE, "TerrainPrimitive");
ADD_SIGNAL(MethodInfo(sig_selection_changed, PropertyInfo(Variant::OBJECT, "new_selection", PROPERTY_HINT_RESOURCE_TYPE, "TerrainPrimitive")));
}
void TerrainMeshEditor::ready() {
@ -54,7 +57,6 @@ void TerrainMeshEditor::ready() {
}
void TerrainMeshEditor::on_primitive_list_changed(Array primitives) {
this->out_of_date = true;
for (Node3D *existing : this->primitive_nodes) {
existing->queue_free();
}
@ -162,6 +164,15 @@ void TerrainMeshEditor::save_data() {
}
}
void TerrainMeshEditor::set_current_selected(Ref<TerrainPrimitive> primitive) {
this->current_selected = primitive;
emit_signal(sig_selection_changed, primitive);
}
Ref<TerrainPrimitive> TerrainMeshEditor::get_current_selected() const {
return this->current_selected;
}
void TerrainMeshEditor::set_point_primitive_object(Ref<PackedScene> scene) {
this->point_primitive_object = scene;
}

View file

@ -3,6 +3,7 @@
#include "core/io/resource.h"
#include "scene/gui/file_dialog.h"
#include "terrain_editor/terrain_mesh_generator.h"
#include "terrain_editor/terrain_primitive.h"
class SaveData : public Resource {
GDCLASS(SaveData, Resource);
@ -34,13 +35,18 @@ protected:
public:
void save_data();
void set_current_selected(Ref<TerrainPrimitive>);
Ref<TerrainPrimitive> get_current_selected() const;
void set_point_primitive_object(Ref<PackedScene> scene);
Ref<PackedScene> get_point_primitive_object() const;
private:
Ref<SaveData> data{ memnew(SaveData) };
Ref<TerrainPrimitive> current_selected{};
FileDialog *file_dialog{};
bool out_of_date{ false };
Vector<Node3D *> primitive_nodes{};
Ref<PackedScene> point_primitive_object{};
public:
static String const sig_selection_changed;
};