diff --git a/assets/icons/plus.svg b/assets/icons/plus.svg
index b21e8ed2..7d280c41 100644
--- a/assets/icons/plus.svg
+++ b/assets/icons/plus.svg
@@ -29,7 +29,8 @@
inkscape:zoom="11.046421"
inkscape:cx="33.766593"
inkscape:cy="34.852918"
- inkscape:current-layer="layer1" />
+ inkscape:current-layer="layer1"
+ showgrid="false" />
+ width="1.8242012"
+ height="6.5867867"
+ x="7.5545654"
+ y="5.1732726"
+ ry="0.26216069" />
diff --git a/modules/terrain_editor/primitive_layer_list.cpp b/modules/terrain_editor/primitive_layer_list.cpp
index f2445865..15dccc81 100644
--- a/modules/terrain_editor/primitive_layer_list.cpp
+++ b/modules/terrain_editor/primitive_layer_list.cpp
@@ -1,21 +1,32 @@
#include "primitive_layer_list.h"
#include "core/object/object.h"
+#include "core/variant/callable.h"
#include "scene/gui/tree.h"
+#include "scene/resources/texture.h"
+#include "terrain_editor/edit_history.h"
#include "terrain_editor/macros.h"
#include "terrain_editor/terrain_primitive.h"
+#include
void PrimitiveLayerList::_bind_methods() {
BIND_HPROPERTY(Variant::OBJECT, terrain, PROPERTY_HINT_NODE_TYPE, "TerrainMeshGenerator");
+ BIND_HPROPERTY(Variant::DICTIONARY, icons, PROPERTY_HINT_DICTIONARY_TYPE, "StringName;Texture2D");
}
void PrimitiveLayerList::generate_subtree(size_t idx, Ref prim, TreeItem *parent) {
TreeItem *base{ create_item(get_root()) };
- base->set_text(0, vformat("%d", idx));
- base->set_expand_right(0, false);
- base->set_editable(0, true);
- base->set_text(1, prim->get_name().is_empty() ? prim->get_class() : prim->get_name());
- base->set_editable(1, true);
- base->set_expand_right(1, true);
+ base->set_icon(ICON_COLUMN, this->icons.has(prim->get_class()) ? this->icons.get(prim->get_class()) : Ref());
+ base->set_icon_max_width(ICON_COLUMN, 24);
+ base->set_selectable(ICON_COLUMN, true);
+ base->set_expand_right(ICON_COLUMN, false);
+
+ base->set_text(IDX_COLUMN, vformat("%d", idx));
+ base->set_expand_right(IDX_COLUMN, false);
+ base->set_editable(IDX_COLUMN, true);
+
+ 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);
}
@@ -48,18 +59,27 @@ void PrimitiveLayerList::switch_index(size_t from, size_t to) {
void PrimitiveLayerList::layer_renamed(TreeItem *item) {
Array primitives = this->terrain->get_primitives();
Ref primitive{ primitives.get(item->get_index()) };
- primitive->set_name(item->get_text(1));
+ String old{ primitive->get_name() };
+ Callable set_name_c{ callable_mp(cast_to(primitive.ptr()), &Resource::set_name) };
+ EditHistory::get_singleton()->push_action(set_name_c.bind(item->get_text(1)), set_name_c.bind(old));
}
void PrimitiveLayerList::item_edited() {
TreeItem *edited{ get_edited() };
+ if (!edited) {
+ return;
+ }
switch (get_edited_column()) {
default:
return;
- case 0: // index
- switch_index(edited->get_index(), edited->get_text(0).to_int());
+ case IDX_COLUMN: { // index
+ Callable switch_index_c{ callable_mp(this, &self_type::switch_index) };
+ int64_t from{ edited->get_index() },
+ to{ edited->get_text(0).to_int() };
+ EditHistory::get_singleton()->push_action(switch_index_c.bind(from, to), switch_index_c.bind(to, from));
return;
- case 1: // name
+ }
+ case NAME_COLUMN: // name
layer_renamed(edited);
return;
}
@@ -75,7 +95,9 @@ void PrimitiveLayerList::_notification(int what) {
case NOTIFICATION_READY:
connect("item_edited", callable_mp(this, &self_type::item_edited));
create_item();
+ set_columns(COLUMN_MAX);
set_hide_root(true);
+ set_select_mode(SelectMode::SELECT_ROW);
if (this->terrain) {
this->terrain->connect(TerrainMeshGenerator::sig_primitive_list_changed, callable_mp(this, &self_type::regenerate_tree));
regenerate_tree(this->terrain->get_primitives());
@@ -84,6 +106,23 @@ void PrimitiveLayerList::_notification(int what) {
}
}
+void PrimitiveLayerList::set_icons(Dictionary dict) {
+ this->icons.clear();
+ for (KeyValue elem : dict) {
+ StringName key{ elem.key };
+ Ref value{ elem.value };
+ this->icons.insert(key, value);
+ }
+}
+
+Dictionary PrimitiveLayerList::get_icons() const {
+ Dictionary dict;
+ for (KeyValue> icon : this->icons) {
+ dict[icon.key] = icon.value;
+ }
+ return dict;
+}
+
void PrimitiveLayerList::set_terrain(TerrainMeshGenerator *terrain) {
this->terrain = terrain;
}
diff --git a/modules/terrain_editor/primitive_layer_list.h b/modules/terrain_editor/primitive_layer_list.h
index d2a2742a..159c079e 100644
--- a/modules/terrain_editor/primitive_layer_list.h
+++ b/modules/terrain_editor/primitive_layer_list.h
@@ -8,6 +8,12 @@
class PrimitiveLayerList : public Tree {
GDCLASS(PrimitiveLayerList, Tree);
static void _bind_methods();
+ enum ColumnTags {
+ ICON_COLUMN = 0,
+ IDX_COLUMN = 1,
+ NAME_COLUMN = 2,
+ COLUMN_MAX
+ };
void generate_subtree(size_t idx, Ref prim, TreeItem *parent);
void regenerate_tree(Array array);
void switch_index(size_t from, size_t to);
@@ -18,10 +24,14 @@ protected:
void _notification(int what);
public:
+ void set_icons(Dictionary dict);
+ Dictionary get_icons() const;
void set_terrain(TerrainMeshGenerator *generator);
TerrainMeshGenerator *get_terrain() const;
private:
+ HashMap> icons{};
TerrainMeshGenerator *terrain{};
+
HashMap[, TreeItem *> subtrees{};
};
diff --git a/project/assets/icons/plus.svg b/project/assets/icons/plus.svg
index ab78d77e..6db0f942 100644
--- a/project/assets/icons/plus.svg
+++ b/project/assets/icons/plus.svg
@@ -7,28 +7,61 @@
viewBox="0 0 16.933332 16.933332"
version="1.1"
id="svg1"
+ inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
+ sodipodi:docname="plus.svg"
+ inkscape:export-filename="../../project/assets/icons/plus.svg"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
+
+
+
+ width="1.8242012"
+ height="6.5867867"
+ x="7.5545654"
+ y="5.1732726"
+ ry="0.26216069" />
diff --git a/project/scenes/editor.tscn b/project/scenes/editor.tscn
index 2d390b5d..0950e885 100644
--- a/project/scenes/editor.tscn
+++ b/project/scenes/editor.tscn
@@ -3,6 +3,7 @@
[ext_resource type="PackedScene" uid="uid://cnux2fqne284i" path="res://objects/primitive_nodes/point_primitive_node.tscn" id="1_b1cmn"]
[ext_resource type="PackedScene" uid="uid://wkqhvjnxs2mx" path="res://objects/terrain_chunk.tscn" id="1_pxqd5"]
[ext_resource type="Theme" uid="uid://dh5hqcu3vyhrh" path="res://editor_theme.tres" id="3_ba0ut"]
+[ext_resource type="Texture2D" uid="uid://b8hetdn3d3ysr" path="res://assets/icons/point.svg" id="4_5lcyj"]
[ext_resource type="Texture2D" uid="uid://bb0mnjwx58nt3" path="res://assets/icons/plus.svg" id="4_q68jb"]
[ext_resource type="Texture2D" uid="uid://bl3gn6qruuy8w" path="res://assets/icons/plane.svg" id="4_xg7d5"]
[ext_resource type="Texture2D" uid="uid://d1te42w7wpkrx" path="res://assets/icons/noise.svg" id="5_eqbpn"]
@@ -176,6 +177,11 @@ layout_mode = 2
size_flags_vertical = 3
columns = 4
terrain = NodePath("../../../../TerrainMeshEditor")
+icons = {
+&"NoisePrimitive": ExtResource("5_eqbpn"),
+&"PlanePrimitive": ExtResource("4_xg7d5"),
+&"PointPrimitive": ExtResource("4_5lcyj")
+}
[node name="HBoxContainer" type="HBoxContainer" parent="LeftPanel/TabContainer/Layers" unique_id=702489990]
layout_mode = 2
]