Split ElementType editor from LayoutEditor

This commit is contained in:
2024-10-05 08:42:32 +03:00
parent 57f34b93bf
commit 6986a4a334
3 changed files with 311 additions and 185 deletions

View File

@@ -87,8 +87,8 @@ scroll_horizontal_enabled = false
[node name="layout_mesh_buttons" type="VBoxContainer" parent="VBoxContainer/ScrollContainer"]
unique_name_in_owner = true
margin_right = 302.0
margin_bottom = 168.0
margin_right = 314.0
margin_bottom = 100.0
rect_min_size = Vector2( 100, 0 )
size_flags_horizontal = 3
size_flags_vertical = 3

View File

@@ -1,5 +1,6 @@
#undef NDEBUG
#include <cassert>
#include <vector>
#include <main/main.h>
#include <core/engine.h>
#include <scene/resources/packed_scene.h>
@@ -13,17 +14,6 @@
#include <editor/editor_node.h>
#include "building_layout_editor.h"
/* Taken from Godot code editor/editor_plugin.cpp */
BuildingLayoutEditor::BuildingLayoutEditor()
: meshes_ready(false)
, current_mode(-1)
, current_element_type("")
, current_element("")
, current_socket(-1)
{
}
template <class T> T *get_as_node(const String &path)
{
Node *scene;
@@ -43,6 +33,289 @@ template <class T> T *get_as_node(const String &path)
return ret;
}
class ElementData {
public:
static ElementData *singleton;
static ElementData *get_singleton()
{
if (!singleton)
singleton = memnew(ElementData);
return singleton;
}
static void cleanup()
{
if (singleton)
memdelete(singleton);
}
struct grid_element_type {
String name;
Transform sockets[ELEMENT_SOCKETS];
};
protected:
HashMap<String, struct grid_element_type> element_type;
public:
void get_key_list(List<String> *keys)
{
element_type.get_key_list(keys);
}
void create_element_type(const String &key)
{
assert(!element_type.has(key));
struct grid_element_type g;
g.name = key;
element_type[key] = g;
}
void set_element_type_socket(const String &key, int socket,
const Transform &xform)
{
assert(element_type.has(key));
assert(socket >= 0 && socket < ELEMENT_SOCKETS);
element_type[key].sockets[socket] = xform;
}
void set_element_type_name(const String &key, const String &name)
{
assert(element_type.has(key));
element_type[key].name = name;
}
bool has(const String &key)
{
return element_type.has(key);
}
Transform get_element_type_socket(const String &key, int socket)
{
assert(element_type.has(key));
assert(socket >= 0 && socket < ELEMENT_SOCKETS);
return element_type[key].sockets[socket];
}
int get_element_type_size()
{
return element_type.size();
}
};
ElementData *ElementData::singleton = nullptr;
class ElementTypeEditor : public Object {
GDCLASS(ElementTypeEditor, Object)
BuildingLayoutEditor *editor;
String current_element_type;
int current_socket;
public:
ElementTypeEditor(BuildingLayoutEditor *editor)
: Object()
, editor(editor)
, current_element_type("")
, current_socket(-1)
{
get_as_node<ItemList>("%element_type_list")
->connect("item_selected", this, "select_element_type");
get_as_node<ItemList>("%socket_list")
->connect("item_selected", this, "select_socket");
get_as_node<Button>("%socket_new_element")
->connect("pressed", this, "enter_name", varray(""));
get_as_node<LineEdit>("%socket_new_element_name")
->connect("text_entered", this, "enter_name");
get_as_node<Button>("%socket_editor_offset_base/set")
->connect("pressed", this, "set_socket_offset");
get_as_node<Button>("%socket_editor_rotation_base/set")
->connect("pressed", this, "set_socket_rotation");
}
virtual ~ElementTypeEditor()
{
}
void select_element_type(int element)
{
String item = get_as_node<ItemList>("%element_type_list")
->get_item_text(element);
print_line("item: " + item);
current_element_type = item;
get_as_node<ItemList>("%socket_list")->show();
get_as_node<ItemList>("%socket_list")->select(0);
// just in case
select_socket(0);
}
void select_socket(int socket)
{
current_socket = socket;
String item = get_as_node<ItemList>("%socket_list")
->get_item_text(socket);
get_as_node<Control>("%socket_transform_editor")->show();
print_line("socket: " + item);
Vector3 f = ElementData::get_singleton()
->get_element_type_socket(
current_element_type, socket)
.origin;
f = Vector3(Math::stepify(f.x, 0.01f),
Math::stepify(f.y, 0.01f),
Math::stepify(f.z, 0.01f));
get_as_node<LineEdit>("%socket_editor_offset_base/x_edit")
->set_text(String::num(f.x));
get_as_node<LineEdit>("%socket_editor_offset_base/y_edit")
->set_text(String::num(f.y));
get_as_node<LineEdit>("%socket_editor_offset_base/z_edit")
->set_text(String::num(f.z));
Vector3 r = ElementData::get_singleton()
->get_element_type_socket(
current_element_type, socket)
.basis.get_rotation_euler() *
180.0f / Math_PI;
r = Vector3(Math::stepify(r.x, 0.01f),
Math::stepify(r.y, 0.01f),
Math::stepify(r.z, 0.01f));
get_as_node<LineEdit>("%socket_editor_rotation_base/x_edit")
->set_text(String::num(r.x));
get_as_node<LineEdit>("%socket_editor_rotation_base/y_edit")
->set_text(String::num(r.y));
get_as_node<LineEdit>("%socket_editor_rotation_base/z_edit")
->set_text(String::num(r.z));
}
void deactivate()
{
get_as_node<Control>("%socket_editor")->hide();
}
void activate()
{
List<String> element_keys;
List<String>::Element *e;
get_as_node<ItemList>("%element_type_list")->clear();
print_line("Restoring UI");
element_keys.clear();
ElementData::get_singleton()->get_key_list(&element_keys);
e = element_keys.front();
while (e) {
get_as_node<ItemList>("%element_type_list")
->add_item(e->get());
print_line("Added item: " + e->get());
e = e->next();
}
get_as_node<ItemList>("%socket_list")->hide();
get_as_node<Control>("%socket_editor")->show();
get_as_node<LineEdit>("%socket_new_element_name")->hide();
get_as_node<ItemList>("%socket_list")->hide();
get_as_node<Control>("%socket_transform_editor")->hide();
}
void enter_name(const String &text)
{
bool added = false;
if (text == "") {
get_as_node<LineEdit>("%socket_new_element_name")
->show();
get_as_node<LineEdit>("%socket_new_element_name")
->grab_click_focus();
get_as_node<LineEdit>("%socket_new_element_name")
->grab_focus();
} else {
String key = text.strip_edges();
assert(!ElementData::get_singleton()->has(key));
if (!ElementData::get_singleton()->has(key)) {
ElementData::get_singleton()
->create_element_type(key);
get_as_node<ItemList>("%element_type_list")
->add_item(key);
assert(ElementData::get_singleton()->has(key));
added = true;
}
assert(added);
get_as_node<LineEdit>("%socket_new_element_name")
->set_text("");
get_as_node<LineEdit>("%socket_new_element_name")
->release_focus();
get_as_node<LineEdit>("%socket_new_element_name")
->hide();
if (added) {
get_as_node<ItemList>("%element_type_list")
->grab_click_focus();
get_as_node<ItemList>("%element_type_list")
->grab_focus();
}
}
}
void set_socket_offset()
{
float x = get_as_node<LineEdit>(
"%socket_editor_offset_base/x_edit")
->get_text()
.to_float();
x = Math::stepify(x, 0.01f);
float y = get_as_node<LineEdit>(
"%socket_editor_offset_base/y_edit")
->get_text()
.to_float();
y = Math::stepify(y, 0.01f);
float z = get_as_node<LineEdit>(
"%socket_editor_offset_base/z_edit")
->get_text()
.to_float();
z = Math::stepify(z, 0.01f);
Transform xm =
ElementData::get_singleton()->get_element_type_socket(
current_element_type, current_socket);
xm.origin = Vector3(x, y, z);
ElementData::get_singleton()->set_element_type_socket(
current_element_type, current_socket, xm);
}
void set_socket_rotation()
{
float x = Math::stepify(
get_as_node<LineEdit>(
"%socket_editor_rotation_base/x_edit")
->get_text()
.to_float(),
0.01f) *
Math_PI / 180.0f;
float y = Math::stepify(
get_as_node<LineEdit>(
"%socket_editor_rotation_base/y_edit")
->get_text()
.to_float(),
0.01f) *
Math_PI / 180.0f;
float z = Math::stepify(
get_as_node<LineEdit>(
"%socket_editor_rotation_base/z_edit")
->get_text()
.to_float(),
0.01f) *
Math_PI / 180.0f;
Basis basis(Vector3(x, y, z));
Transform xm =
ElementData::get_singleton()->get_element_type_socket(
current_element_type, current_socket);
xm.basis = basis;
ElementData::get_singleton()->set_element_type_socket(
current_element_type, current_socket, xm);
}
protected:
static void _bind_methods()
{
ClassDB::bind_method(D_METHOD("select_element_type", "element"),
&ElementTypeEditor::select_element_type);
ClassDB::bind_method(D_METHOD("select_socket", "socket"),
&ElementTypeEditor::select_socket);
ClassDB::bind_method(D_METHOD("enter_name", "text"),
&ElementTypeEditor::enter_name);
ClassDB::bind_method(D_METHOD("set_socket_offset"),
&ElementTypeEditor::set_socket_offset);
ClassDB::bind_method(D_METHOD("set_socket_rotation"),
&ElementTypeEditor::set_socket_rotation);
}
};
/* Taken from Godot code editor/editor_plugin.cpp */
static std::vector<Object *> editors;
BuildingLayoutEditor::BuildingLayoutEditor()
: meshes_ready(false)
, current_mode(-1)
, current_element("")
{
}
Vector<Ref<Texture> >
BuildingLayoutEditor::make_mesh_previews(const Vector<Ref<Mesh> > &p_meshes,
Vector<Transform> *p_transforms,
@@ -165,17 +438,27 @@ Ref<PackedScene> BuildingLayoutEditor::get_source() const
return source;
}
static ElementTypeEditor *etype_editor;
void BuildingLayoutEditor::_notification(int which)
{
int i;
switch (which) {
case NOTIFICATION_READY:
case NOTIFICATION_READY: {
if (Engine::get_singleton()->is_editor_hint())
return;
etype_editor = memnew(ElementTypeEditor(this));
editors.push_back(etype_editor);
connect_signals();
if (!meshes_ready) {
prepare_meshes();
update_mesh_buttons();
}
select_mode(0);
break;
} break;
case NOTIFICATION_EXIT_TREE:
for (i = 0; i < (int)editors.size(); i++)
memdelete(editors[i]);
}
}
@@ -253,20 +536,10 @@ void BuildingLayoutEditor::_bind_methods()
&BuildingLayoutEditor::get_source);
ClassDB::bind_method(D_METHOD("select_mode", "mode"),
&BuildingLayoutEditor::select_mode);
ClassDB::bind_method(D_METHOD("enter_name", "text"),
&BuildingLayoutEditor::enter_name);
ClassDB::bind_method(D_METHOD("enter_element_name", "text"),
&BuildingLayoutEditor::enter_element_name);
ClassDB::bind_method(D_METHOD("select_element_type", "element"),
&BuildingLayoutEditor::select_element_type);
ClassDB::bind_method(D_METHOD("select_element", "element"),
&BuildingLayoutEditor::select_element);
ClassDB::bind_method(D_METHOD("select_socket", "socket"),
&BuildingLayoutEditor::select_socket);
ClassDB::bind_method(D_METHOD("set_socket_offset"),
&BuildingLayoutEditor::set_socket_offset);
ClassDB::bind_method(D_METHOD("set_socket_rotation"),
&BuildingLayoutEditor::set_socket_rotation);
ClassDB::bind_method(D_METHOD("menu_control"),
&BuildingLayoutEditor::menu_control);
ClassDB::bind_method(D_METHOD("mesh_selected", "mesh_idx", "socket"),
@@ -281,18 +554,6 @@ void BuildingLayoutEditor::connect_signals()
int i;
if (Engine::get_singleton()->is_editor_hint())
return;
get_as_node<Button>("%socket_new_element")
->connect("pressed", this, "enter_name", varray(""));
get_as_node<LineEdit>("%socket_new_element_name")
->connect("text_entered", this, "enter_name");
get_as_node<ItemList>("%element_type_list")
->connect("item_selected", this, "select_element_type");
get_as_node<ItemList>("%socket_list")
->connect("item_selected", this, "select_socket");
get_as_node<Button>("%socket_editor_offset_base/set")
->connect("pressed", this, "set_socket_offset");
get_as_node<Button>("%socket_editor_rotation_base/set")
->connect("pressed", this, "set_socket_rotation");
get_as_node<ItemList>("%element_list")
->connect("item_selected", this, "select_element");
@@ -311,6 +572,8 @@ void BuildingLayoutEditor::connect_signals()
void BuildingLayoutEditor::select_mode(int mode)
{
int i;
if (Engine::get_singleton()->is_editor_hint())
return;
List<String> element_keys;
List<String>::Element *e;
print_line("set mode: " + itos(mode));
@@ -326,34 +589,20 @@ void BuildingLayoutEditor::select_mode(int mode)
current_mode = mode;
switch (mode) {
case 0:
get_as_node<Control>("%socket_editor")->hide();
etype_editor->deactivate();
get_as_node<Control>("%element_editor")->hide();
if (elements.size() == 0)
print_error("No elements");
break;
case 1:
etype_editor->activate();
get_as_node<Control>("%element_editor")->hide();
get_as_node<ItemList>("%element_type_list")->clear();
print_line("Restoring UI");
element_keys.clear();
element_type.get_key_list(&element_keys);
e = element_keys.front();
while (e) {
get_as_node<ItemList>("%element_type_list")
->add_item(e->get());
print_line("Added item: " + e->get());
e = e->next();
}
get_as_node<ItemList>("%socket_list")->hide();
get_as_node<Control>("%socket_editor")->show();
get_as_node<LineEdit>("%socket_new_element_name")
->hide();
get_as_node<ItemList>("%socket_list")->hide();
get_as_node<Control>("%socket_transform_editor")->hide();
element_keys.clear();
break;
case 2:
if (element_type.size() == 0)
etype_editor->deactivate();
if (ElementData::get_singleton()
->get_element_type_size() == 0)
print_error("No element types");
get_as_node<Control>("%socket_editor")->hide();
get_as_node<Control>("%element_editor")->show();
@@ -371,7 +620,8 @@ void BuildingLayoutEditor::select_mode(int mode)
e = e->next();
}
element_keys.clear();
element_type.get_key_list(&element_keys);
ElementData::get_singleton()->get_key_list(
&element_keys);
e = element_keys.front();
while (e) {
get_as_node<OptionButton>(
@@ -384,6 +634,7 @@ void BuildingLayoutEditor::select_mode(int mode)
ItemList *sl = get_as_node<ItemList>("%socket_list");
Control *mb =
get_as_node<Control>("%element_mesh_select");
mb->hide();
used_socket_count = sl->get_item_count();
if (mb->get_child_count() == 0) {
for (i = 0; i < used_socket_count; i++) {
@@ -424,45 +675,12 @@ void BuildingLayoutEditor::select_mode(int mode)
"mesh_selected", varray(i));
}
}
select_element(0);
// select_element(0);
break;
}
}
}
void BuildingLayoutEditor::enter_name(const String &text)
{
bool added = false;
if (text == "") {
get_as_node<LineEdit>("%socket_new_element_name")->show();
get_as_node<LineEdit>("%socket_new_element_name")
->grab_click_focus();
get_as_node<LineEdit>("%socket_new_element_name")->grab_focus();
} else {
String key = text.strip_edges();
assert(!element_type.has(key));
if (!element_type.has(key)) {
struct grid_element_type g;
g.name = key;
element_type[key] = g;
get_as_node<ItemList>("%element_type_list")
->add_item(key);
added = true;
}
assert(added);
get_as_node<LineEdit>("%socket_new_element_name")->set_text("");
get_as_node<LineEdit>("%socket_new_element_name")
->release_focus();
get_as_node<LineEdit>("%socket_new_element_name")->hide();
if (added) {
get_as_node<ItemList>("%element_type_list")
->grab_click_focus();
get_as_node<ItemList>("%element_type_list")
->grab_focus();
}
}
}
void BuildingLayoutEditor::enter_element_name(const String &text)
{
bool added = false;
@@ -494,91 +712,6 @@ void BuildingLayoutEditor::enter_element_name(const String &text)
}
}
void BuildingLayoutEditor::select_element_type(int element)
{
String item = get_as_node<ItemList>("%element_type_list")
->get_item_text(element);
print_line("item: " + item);
current_element_type = item;
get_as_node<ItemList>("%socket_list")->show();
get_as_node<ItemList>("%socket_list")->select(0);
// just in case
select_socket(0);
}
void BuildingLayoutEditor::select_socket(int socket)
{
current_socket = socket;
String item =
get_as_node<ItemList>("%socket_list")->get_item_text(socket);
get_as_node<Control>("%socket_transform_editor")->show();
print_line("socket: " + item);
Vector3 f = element_type[current_element_type].sockets[socket].origin;
f = Vector3(Math::stepify(f.x, 0.01f), Math::stepify(f.y, 0.01f),
Math::stepify(f.z, 0.01f));
get_as_node<LineEdit>("%socket_editor_offset_base/x_edit")
->set_text(String::num(f.x));
get_as_node<LineEdit>("%socket_editor_offset_base/y_edit")
->set_text(String::num(f.y));
get_as_node<LineEdit>("%socket_editor_offset_base/z_edit")
->set_text(String::num(f.z));
Vector3 r = element_type[current_element_type]
.sockets[socket]
.basis.get_rotation_euler() *
180.0f / Math_PI;
r = Vector3(Math::stepify(r.x, 0.01f), Math::stepify(r.y, 0.01f),
Math::stepify(r.z, 0.01f));
get_as_node<LineEdit>("%socket_editor_rotation_base/x_edit")
->set_text(String::num(r.x));
get_as_node<LineEdit>("%socket_editor_rotation_base/y_edit")
->set_text(String::num(r.y));
get_as_node<LineEdit>("%socket_editor_rotation_base/z_edit")
->set_text(String::num(r.z));
}
void BuildingLayoutEditor::set_socket_offset()
{
float x = get_as_node<LineEdit>("%socket_editor_offset_base/x_edit")
->get_text()
.to_float();
x = Math::stepify(x, 0.01f);
float y = get_as_node<LineEdit>("%socket_editor_offset_base/y_edit")
->get_text()
.to_float();
y = Math::stepify(y, 0.01f);
float z = get_as_node<LineEdit>("%socket_editor_offset_base/z_edit")
->get_text()
.to_float();
z = Math::stepify(z, 0.01f);
element_type[current_element_type].sockets[current_socket].origin =
Vector3(x, y, z);
}
void BuildingLayoutEditor::set_socket_rotation()
{
float x = Math::stepify(get_as_node<LineEdit>(
"%socket_editor_rotation_base/x_edit")
->get_text()
.to_float(),
0.01f) *
Math_PI / 180.0f;
float y = Math::stepify(get_as_node<LineEdit>(
"%socket_editor_rotation_base/y_edit")
->get_text()
.to_float(),
0.01f) *
Math_PI / 180.0f;
float z = Math::stepify(get_as_node<LineEdit>(
"%socket_editor_rotation_base/z_edit")
->get_text()
.to_float(),
0.01f) *
Math_PI / 180.0f;
Basis basis(Vector3(x, y, z));
element_type[current_element_type].sockets[current_socket].basis =
basis;
}
void BuildingLayoutEditor::menu_control(int id)
{
print_line("menu_control: " + itos(id));
@@ -610,6 +743,8 @@ void BuildingLayoutEditor::select_element(int element)
print_line("selected element: " + item);
current_element = item;
String type = elements[current_element].type;
Control *mb = get_as_node<Control>("%element_mesh_select");
mb->show();
if (type.length() > 0) {
OptionButton *b =
get_as_node<OptionButton>("%element_type_select");

View File

@@ -16,22 +16,15 @@ class BuildingLayoutEditor : public Node {
HashMap<int, OptionButton *> mesh_select_buttons;
int used_socket_count;
#define ELEMENT_SOCKETS 16
struct grid_element_type {
String name;
Transform sockets[ELEMENT_SOCKETS];
};
struct grid_element {
String name;
String type;
String mesh_names[ELEMENT_SOCKETS];
};
HashMap<String, struct grid_element_type> element_type;
HashMap<String, struct grid_element> elements;
bool meshes_ready;
int current_mode;
String current_element_type;
String current_element;
int current_socket;
public:
BuildingLayoutEditor();
@@ -48,9 +41,7 @@ protected:
static void _bind_methods();
void connect_signals();
void select_mode(int mode);
void enter_name(const String &text);
void enter_element_name(const String &text);
void select_element_type(int element);
void select_socket(int socket);
void set_socket_offset();
void set_socket_rotation();