From 670cfa1779a3c7bd72e5c4d766e221513181b067 Mon Sep 17 00:00:00 2001 From: Sara Date: Mon, 8 Dec 2025 13:41:15 +0100 Subject: [PATCH] feat: added layer tree icons --- assets/icons/plus.svg | 23 ++++---- .../terrain_editor/primitive_layer_list.cpp | 59 +++++++++++++++---- modules/terrain_editor/primitive_layer_list.h | 10 ++++ project/assets/icons/plus.svg | 53 +++++++++++++---- project/scenes/editor.tscn | 6 ++ 5 files changed, 120 insertions(+), 31 deletions(-) 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