Editor UI refactoring

This commit is contained in:
2024-10-24 04:48:36 +03:00
parent 7bac24d34e
commit aa324903fd
17 changed files with 1249 additions and 669 deletions

View File

@@ -63,264 +63,24 @@ margin_bottom = 48.0
rect_min_size = Vector2( 48, 48 )
focus_mode = 2
[node name="ColorRect" type="ColorRect" parent="VBoxContainer"]
[node name="MainTabs" type="MainTabs" parent="VBoxContainer"]
unique_name_in_owner = true
margin_top = 52.0
margin_right = 248.0
margin_bottom = 82.0
rect_min_size = Vector2( 160, 30 )
size_flags_horizontal = 3
size_flags_vertical = 5
color = Color( 0.25098, 0.25098, 0.25098, 1 )
[node name="Label" type="Label" parent="VBoxContainer/ColorRect"]
margin_left = 39.0
margin_top = 8.0
margin_right = 118.0
margin_bottom = 22.0
size_flags_horizontal = 3
size_flags_vertical = 7
text = "Mode select"
align = 1
valign = 1
[node name="select_buildings" type="Button" parent="VBoxContainer"]
unique_name_in_owner = true
margin_top = 86.0
margin_right = 248.0
margin_bottom = 106.0
text = "Buildings Mode"
[node name="select_navigation" type="Button" parent="VBoxContainer"]
unique_name_in_owner = true
margin_top = 110.0
margin_right = 248.0
margin_bottom = 130.0
text = "Navigation Mode"
[node name="select_poi" type="Button" parent="VBoxContainer"]
unique_name_in_owner = true
margin_top = 134.0
margin_right = 248.0
margin_bottom = 154.0
text = "POI Mode"
[node name="select_road_lines" type="Button" parent="VBoxContainer"]
unique_name_in_owner = true
margin_top = 158.0
margin_right = 248.0
margin_bottom = 178.0
text = "Road Lines Mode"
[node name="select_npc" type="Button" parent="VBoxContainer"]
unique_name_in_owner = true
margin_top = 182.0
margin_right = 248.0
margin_bottom = 202.0
text = "NPC Mode"
margin_bottom = 500.0
[node name="v_buildings" type="VBoxContainer" parent="VBoxContainer"]
unique_name_in_owner = true
margin_top = 206.0
margin_top = 504.0
margin_right = 248.0
margin_bottom = 650.0
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_buildings"]
margin_right = 248.0
margin_bottom = 4.0
[node name="base" type="PanelContainer" parent="VBoxContainer/v_buildings"]
margin_top = 8.0
margin_right = 248.0
margin_bottom = 444.0
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/v_buildings/base"]
margin_left = 7.0
margin_top = 7.0
margin_right = 241.0
margin_bottom = 429.0
[node name="Label" type="Label" parent="VBoxContainer/v_buildings/base/VBoxContainer"]
margin_right = 234.0
margin_bottom = 14.0
text = "Buildings mode"
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_buildings/base/VBoxContainer"]
margin_top = 18.0
margin_right = 234.0
margin_bottom = 22.0
[node name="Label3" type="Label" parent="VBoxContainer/v_buildings/base/VBoxContainer"]
margin_top = 26.0
margin_right = 234.0
margin_bottom = 40.0
text = "Cursor position"
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/v_buildings/base/VBoxContainer"]
margin_top = 44.0
margin_right = 234.0
margin_bottom = 68.0
[node name="building_cursor_x" type="LineEdit" parent="VBoxContainer/v_buildings/base/VBoxContainer/HBoxContainer"]
unique_name_in_owner = true
margin_right = 63.0
margin_bottom = 24.0
size_flags_horizontal = 3
[node name="building_cursor_y" type="LineEdit" parent="VBoxContainer/v_buildings/base/VBoxContainer/HBoxContainer"]
unique_name_in_owner = true
margin_left = 67.0
margin_right = 130.0
margin_bottom = 24.0
size_flags_horizontal = 3
[node name="building_cursor_z" type="LineEdit" parent="VBoxContainer/v_buildings/base/VBoxContainer/HBoxContainer"]
unique_name_in_owner = true
margin_left = 134.0
margin_right = 197.0
margin_bottom = 24.0
size_flags_horizontal = 3
[node name="buildings_set_cursor_position" type="Button" parent="VBoxContainer/v_buildings/base/VBoxContainer/HBoxContainer"]
unique_name_in_owner = true
margin_left = 201.0
margin_right = 233.0
margin_bottom = 24.0
text = "Set"
[node name="Label5" type="Label" parent="VBoxContainer/v_buildings/base/VBoxContainer"]
margin_top = 72.0
margin_right = 234.0
margin_bottom = 86.0
text = "Selected building position"
[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer/v_buildings/base/VBoxContainer"]
margin_top = 90.0
margin_right = 234.0
margin_bottom = 114.0
[node name="building_position_x" type="LineEdit" parent="VBoxContainer/v_buildings/base/VBoxContainer/HBoxContainer2"]
unique_name_in_owner = true
margin_right = 75.0
margin_bottom = 24.0
size_flags_horizontal = 3
[node name="building_position_y" type="LineEdit" parent="VBoxContainer/v_buildings/base/VBoxContainer/HBoxContainer2"]
unique_name_in_owner = true
margin_left = 79.0
margin_right = 154.0
margin_bottom = 24.0
size_flags_horizontal = 3
[node name="building_position_z" type="LineEdit" parent="VBoxContainer/v_buildings/base/VBoxContainer/HBoxContainer2"]
unique_name_in_owner = true
margin_left = 158.0
margin_right = 234.0
margin_bottom = 24.0
size_flags_horizontal = 3
[node name="HBoxContainer3" type="HBoxContainer" parent="VBoxContainer/v_buildings/base/VBoxContainer"]
margin_top = 118.0
margin_right = 234.0
margin_bottom = 142.0
[node name="Label" type="Label" parent="VBoxContainer/v_buildings/base/VBoxContainer/HBoxContainer3"]
margin_top = 5.0
margin_right = 18.0
margin_bottom = 19.0
text = "rot"
[node name="building_rotation_y" type="LineEdit" parent="VBoxContainer/v_buildings/base/VBoxContainer/HBoxContainer3"]
unique_name_in_owner = true
margin_left = 22.0
margin_right = 80.0
margin_bottom = 24.0
[node name="buildings_set_building_position" type="Button" parent="VBoxContainer/v_buildings/base/VBoxContainer/HBoxContainer3"]
unique_name_in_owner = true
margin_left = 84.0
margin_right = 116.0
margin_bottom = 24.0
text = "Set"
[node name="HSeparator3" type="HSeparator" parent="VBoxContainer/v_buildings/base/VBoxContainer"]
margin_top = 146.0
margin_right = 234.0
margin_bottom = 150.0
[node name="Label4" type="Label" parent="VBoxContainer/v_buildings/base/VBoxContainer"]
margin_top = 154.0
margin_right = 234.0
margin_bottom = 168.0
text = "Mode"
[node name="buildings_edit_mode" type="OptionButton" parent="VBoxContainer/v_buildings/base/VBoxContainer"]
unique_name_in_owner = true
margin_top = 172.0
margin_right = 234.0
margin_bottom = 192.0
text = "Select"
items = [ "Select", null, false, 0, null, "Move", null, false, 1, null, "Rotate", null, false, 2, null, "Create", null, false, 3, null ]
selected = 0
[node name="Label2" type="Label" parent="VBoxContainer/v_buildings/base/VBoxContainer"]
margin_top = 196.0
margin_right = 234.0
margin_bottom = 210.0
text = "Building type"
[node name="building_type" type="OptionButton" parent="VBoxContainer/v_buildings/base/VBoxContainer"]
unique_name_in_owner = true
margin_top = 214.0
margin_right = 234.0
margin_bottom = 234.0
text = "Building Type"
[node name="HSeparator2" type="HSeparator" parent="VBoxContainer/v_buildings/base/VBoxContainer"]
margin_top = 238.0
margin_right = 234.0
margin_bottom = 242.0
[node name="buildings_delete_building" type="Button" parent="VBoxContainer/v_buildings/base/VBoxContainer"]
unique_name_in_owner = true
margin_top = 246.0
margin_right = 234.0
margin_bottom = 266.0
text = "Delete building"
[node name="buildings_create_building" type="Button" parent="VBoxContainer/v_buildings/base/VBoxContainer"]
unique_name_in_owner = true
margin_top = 270.0
margin_right = 234.0
margin_bottom = 290.0
text = "Create building"
[node name="buildings_save" type="Button" parent="VBoxContainer/v_buildings/base/VBoxContainer"]
unique_name_in_owner = true
margin_top = 294.0
margin_right = 234.0
margin_bottom = 314.0
text = "Save Buildings"
[node name="lines_list_building" type="ItemList" parent="VBoxContainer/v_buildings/base/VBoxContainer"]
unique_name_in_owner = true
margin_top = 318.0
margin_right = 234.0
margin_bottom = 398.0
rect_min_size = Vector2( 0, 80 )
size_flags_horizontal = 3
[node name="buildings_assign_to_line" type="Button" parent="VBoxContainer/v_buildings/base/VBoxContainer"]
unique_name_in_owner = true
margin_top = 402.0
margin_right = 234.0
margin_bottom = 422.0
text = "Assign To Line"
margin_bottom = 504.0
[node name="v_navigation" type="VBoxContainer" parent="VBoxContainer"]
unique_name_in_owner = true
margin_top = 654.0
visible = false
margin_top = 246.0
margin_right = 248.0
margin_bottom = 676.0
margin_bottom = 268.0
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_navigation"]
margin_right = 248.0
@@ -334,9 +94,10 @@ text = "Navigation mode"
[node name="v_poi" type="VBoxContainer" parent="VBoxContainer"]
unique_name_in_owner = true
margin_top = 680.0
visible = false
margin_top = 246.0
margin_right = 248.0
margin_bottom = 702.0
margin_bottom = 268.0
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_poi"]
margin_right = 248.0
@@ -350,9 +111,10 @@ text = "POI mode"
[node name="v_road_lines" type="VBoxContainer" parent="VBoxContainer"]
unique_name_in_owner = true
margin_top = 706.0
visible = false
margin_top = 246.0
margin_right = 248.0
margin_bottom = 1665.0
margin_bottom = 1205.0
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_road_lines"]
margin_right = 248.0
@@ -604,8 +366,8 @@ size_flags_vertical = 3
scroll_horizontal_enabled = false
[node name="v" type="VBoxContainer" parent="VBoxContainer/v_road_lines/road_lines_edit_metadata_dlg/scroll"]
margin_right = 222.0
margin_bottom = 418.0
margin_right = 234.0
margin_bottom = 250.0
size_flags_horizontal = 3
size_flags_vertical = 3
@@ -730,9 +492,10 @@ text = "Close"
[node name="v_npc" type="VBoxContainer" parent="VBoxContainer"]
unique_name_in_owner = true
margin_top = 1669.0
visible = false
margin_top = 1749.0
margin_right = 248.0
margin_bottom = 1691.0
margin_bottom = 1771.0
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/v_npc"]
margin_right = 248.0

View File

@@ -3,14 +3,14 @@
Import("env")
Import("env_modules")
env_stream = env_modules.Clone()
# Godot source files
module_obj = []
SConscript("buildings/SCsub")
SConscript("ui/SCsub")
env_stream = env_modules.Clone()
env_stream.Prepend(CPPPATH=["../../meshoptimizer/src"])
env_stream.add_source_files(module_obj, "*.cpp")

View File

@@ -205,6 +205,7 @@ void ElementData::grow_cell(int type, const String &key, bool exterior, int fl,
}
void ElementData::create_new_layout(const String &key)
{
flecs::world ecs = BaseData::get_singleton()->get();
flecs::entity top = ecs.lookup("grid_layouts");
assert(top.is_valid());
flecs::entity layout = ecs.entity(key.ascii().ptr()).child_of(top);
@@ -220,6 +221,7 @@ void ElementData::create_new_layout(const String &key)
void ElementData::create_new_exterior_floor(const String &key)
{
int i;
flecs::world ecs = BaseData::get_singleton()->get();
flecs::entity ext = get_base(key, true);
assert(ext.is_valid());
struct grid_layout_base *l = ext.get_mut<grid_layout_base>();
@@ -243,6 +245,7 @@ void ElementData::create_new_interior_floor(const String &key)
assert(intr.is_valid());
struct grid_layout_base *l = intr.get_mut<grid_layout_base>();
int floor = l->floor_count;
flecs::world ecs = BaseData::get_singleton()->get();
flecs::entity fl = ecs.entity(("floor_" + itos(floor)).ascii().ptr())
.child_of(intr);
assert(fl.is_valid());
@@ -257,6 +260,7 @@ void ElementData::create_new_interior_floor(const String &key)
}
void ElementData::serialize_layouts(Dictionary &store)
{
flecs::world ecs = BaseData::get_singleton()->get();
flecs::entity top = ecs.lookup("grid_layouts");
assert(top.is_valid());
top.children([this, &store](flecs::entity l) {
@@ -324,6 +328,7 @@ void ElementData::serialize_layouts(Dictionary &store)
void ElementData::unserialize_layouts(const Dictionary &store)
{
int i;
flecs::world ecs = BaseData::get_singleton()->get();
flecs::entity top = ecs.lookup("grid_layouts");
assert(top.is_valid());
// delete all layouts
@@ -417,6 +422,7 @@ void ElementData::ensure_floor(const String &key, bool exterior, int fl)
int i;
if (has_floor(key, exterior, fl))
return;
flecs::world ecs = BaseData::get_singleton()->get();
flecs::entity base = get_base(key, exterior);
flecs::entity floor_e =
ecs.entity(("floor_" + itos(fl)).ascii().ptr()).child_of(base);

View File

@@ -8,6 +8,7 @@
#include <core/engine.h>
#include <editor/editor_node.h>
#include <flecs/flecs.h>
#include "base_data.h"
#include "editor_event.h"
template <class T> T *get_as_node(const String &path)
{
@@ -60,7 +61,6 @@ template <class T> void select_control_item(T *ctl, const String &item)
}
#define ELEMENT_SOCKETS 16
class ElementData {
flecs::world ecs;
static ElementData *singleton;
public:
@@ -124,6 +124,7 @@ public:
protected:
ElementData()
{
flecs::world ecs = BaseData::get_singleton()->get();
ecs.component<struct grid_layouts>();
ecs.component<struct grid_layout>();
ecs.component<struct grid_layout_exterior>();
@@ -185,6 +186,7 @@ public:
}
inline const flecs::entity get_layout(const String &key) const
{
flecs::world ecs = BaseData::get_singleton()->get();
flecs::entity top = ecs.lookup("grid_layouts");
assert(top.is_valid());
flecs::entity layout = top.lookup(key.ascii().ptr());
@@ -301,6 +303,7 @@ public:
}
void get_grid_layouts_key_list(List<String> *keys)
{
flecs::world ecs = BaseData::get_singleton()->get();
flecs::entity top = ecs.lookup("grid_layouts");
assert(top.is_valid());
flecs::query_builder<const struct grid_layout> qb =
@@ -438,4 +441,4 @@ public:
void load_data();
};
#endif
#endif

View File

@@ -1,6 +1,7 @@
#undef NDEBUG
#include <cassert>
#include <core/variant.h>
#include <core/engine.h>
#include <core/os/time.h>
#include <scene/gui/option_button.h>
#include <scene/gui/line_edit.h>
@@ -12,342 +13,10 @@
#include "editor_event.h"
#include "world_editor.h"
#include "buildings_data.h"
#include "base_data.h"
#include "ui/main_tabs.h"
#include "buildings_editor.h"
class HandlePositionSetting : public Object {
GDCLASS(HandlePositionSetting, Object)
BuildingsEditor *editor;
int old_mode;
public:
HandlePositionSetting(BuildingsEditor *editor)
: Object()
, editor(editor)
, old_mode(-1)
{
SceneTree::get_singleton()->connect("idle_frame", this,
"handle_update");
Button *set_cursor_position = editor->get_as_node<Button>(
"%buildings_set_cursor_position");
set_cursor_position->connect("pressed", this,
"handle_set_cursor");
Button *set_building_position = editor->get_as_node<Button>(
"%buildings_set_building_position");
set_building_position->connect("pressed", this,
"handle_set_building");
EditorEvent::get_singleton()->event.add_listener(
this, &HandlePositionSetting::handle_event);
#if 0
String building = editor->get_selected_building();
if (building.length() > 0) {
Vector3 building_pos =
editor->get_selected_building_xform().origin;
}
#endif
}
virtual ~HandlePositionSetting()
{
EditorEvent::get_singleton()->event.remove_listener(
this, &HandlePositionSetting::handle_event);
Button *set_building_position = editor->get_as_node<Button>(
"%buildings_set_building_position");
set_building_position->disconnect("pressed", this,
"handle_set_building");
Button *set_cursor_position = editor->get_as_node<Button>(
"%buildings_set_cursor_position");
set_cursor_position->disconnect("pressed", this,
"handle_set_cursor");
SceneTree::get_singleton()->disconnect("idle_frame", this,
"handle_update");
}
protected:
static void _bind_methods()
{
ClassDB::bind_method(D_METHOD("handle_update"),
&HandlePositionSetting::handle_update);
ClassDB::bind_method(D_METHOD("handle_set_cursor"),
&HandlePositionSetting::handle_set_cursor);
ClassDB::bind_method(
D_METHOD("handle_set_building"),
&HandlePositionSetting::handle_set_building);
}
private:
void handle_event(const String &event, const Vector<Variant> &args)
{
if (event == "buildings_building_cursor_moved") {
Vector3 position = args[0];
LineEdit *cursor_x = editor->get_as_node<LineEdit>(
"%building_cursor_x");
LineEdit *cursor_y = editor->get_as_node<LineEdit>(
"%building_cursor_y");
LineEdit *cursor_z = editor->get_as_node<LineEdit>(
"%building_cursor_z");
cursor_x->set_text(String::num(position.x));
cursor_y->set_text(String::num(position.y));
cursor_z->set_text(String::num(position.z));
} else if (event == "buildings_building_selected" ||
event == "buildings_building_moved" ||
event == "buildings_building_rotated") {
LineEdit *position_x = editor->get_as_node<LineEdit>(
"%building_position_x");
LineEdit *position_y = editor->get_as_node<LineEdit>(
"%building_position_y");
LineEdit *position_z = editor->get_as_node<LineEdit>(
"%building_position_z");
LineEdit *position_rot = editor->get_as_node<LineEdit>(
"%building_rotation_y");
Transform xform = editor->get_selected_building_xform();
position_x->set_text(String::num(xform.origin.x));
position_y->set_text(String::num(xform.origin.y));
position_z->set_text(String::num(xform.origin.z));
Vector3 reference(0, 0, -1);
Vector3 rotated =
xform.basis.xform(reference).normalized();
float angle = reference.signed_angle_to(
rotated, Vector3(0, 1, 0));
position_rot->set_text(
String::num(angle * 180.0f / Math_PI));
}
}
void handle_set_cursor()
{
LineEdit *cursor_x =
editor->get_as_node<LineEdit>("%building_cursor_x");
LineEdit *cursor_y =
editor->get_as_node<LineEdit>("%building_cursor_y");
LineEdit *cursor_z =
editor->get_as_node<LineEdit>("%building_cursor_z");
Vector3 position;
position.x = cursor_x->get_text().to_float();
position.y = cursor_y->get_text().to_float();
position.z = cursor_z->get_text().to_float();
editor->set_cursor_position(position);
}
void handle_set_building()
{
LineEdit *position_x =
editor->get_as_node<LineEdit>("%building_position_x");
LineEdit *position_y =
editor->get_as_node<LineEdit>("%building_position_y");
LineEdit *position_z =
editor->get_as_node<LineEdit>("%building_position_z");
LineEdit *position_rot =
editor->get_as_node<LineEdit>("%building_rotation_y");
Transform xform = editor->get_selected_building_xform();
xform.basis = Basis().rotated(
Vector3(0, 1, 0),
position_rot->get_text().to_float() * Math_PI / 180.0f);
xform.origin.x = position_x->get_text().to_float();
xform.origin.y = position_y->get_text().to_float();
xform.origin.z = position_z->get_text().to_float();
String key = editor->get_selected_building();
int mode = editor->get_buildings_editor_mode();
if (mode == 1 || mode == 2)
editor->set_cursor_position(xform.origin);
editor->emit("run_update_building_transform",
varray(key, xform));
}
void handle_update()
{
// TODO: handle selection
int i;
int mode = editor->get_buildings_editor_mode();
LineEdit *cursor_x =
editor->get_as_node<LineEdit>("%building_cursor_x");
LineEdit *cursor_y =
editor->get_as_node<LineEdit>("%building_cursor_y");
LineEdit *cursor_z =
editor->get_as_node<LineEdit>("%building_cursor_z");
LineEdit *cursor_le[] = { cursor_x, cursor_y, cursor_z };
Button *set_cursor_position = editor->get_as_node<Button>(
"%buildings_set_cursor_position");
LineEdit *position_x =
editor->get_as_node<LineEdit>("%building_position_x");
LineEdit *position_y =
editor->get_as_node<LineEdit>("%building_position_y");
LineEdit *position_z =
editor->get_as_node<LineEdit>("%building_position_z");
LineEdit *position_rot =
editor->get_as_node<LineEdit>("%building_rotation_y");
LineEdit *position_le[] = { position_x, position_y, position_z,
position_rot };
Button *set_building_position = editor->get_as_node<Button>(
"%buildings_set_building_position");
int sz_cursor = (int)(sizeof(cursor_le) / sizeof(cursor_le[0]));
int sz_position =
(int)(sizeof(position_le) / sizeof(position_le[0]));
if (mode != old_mode) {
switch (mode) {
case 0: // select
for (i = 0; i < sz_cursor; i++)
cursor_le[i]->set_editable(false);
set_cursor_position->set_disabled(true);
for (i = 0; i < sz_position; i++)
position_le[i]->set_editable(false);
set_building_position->set_disabled(true);
break;
case 1: // move
for (i = 0; i < sz_cursor; i++)
cursor_le[i]->set_editable(false);
set_cursor_position->set_disabled(true);
for (i = 0; i < sz_position; i++)
position_le[i]->set_editable(true);
set_building_position->set_disabled(false);
break;
case 2: // rotate
for (i = 0; i < sz_cursor; i++)
cursor_le[i]->set_editable(false);
set_cursor_position->set_disabled(true);
for (i = 0; i < sz_position; i++)
position_le[i]->set_editable(true);
set_building_position->set_disabled(false);
break;
case 3: // create
for (i = 0; i < sz_cursor; i++)
cursor_le[i]->set_editable(true);
set_cursor_position->set_disabled(false);
for (i = 0; i < sz_position; i++)
position_le[i]->set_editable(true);
set_building_position->set_disabled(false);
break;
}
old_mode = mode;
}
}
};
class HandleChangeBuildingType : public Object {
GDCLASS(HandleChangeBuildingType, Object)
BuildingsEditor *editor;
void change_building_type(int index)
{
OptionButton *building_type =
editor->get_as_node<OptionButton>("%building_type");
const String &item = building_type->get_item_text(index);
int bmode = editor->get_buildings_editor_mode();
if (bmode == 0 || bmode == 1 ||
bmode == 2) /* select, move, rotate */
editor->change_building_type(item);
/* do not change building types in create mode (3) */
}
public:
HandleChangeBuildingType(BuildingsEditor *editor)
: Object()
, editor(editor)
{
OptionButton *building_type =
editor->get_as_node<OptionButton>("%building_type");
building_type->connect("item_selected", this,
"change_building_type");
}
virtual ~HandleChangeBuildingType()
{
OptionButton *building_type =
editor->get_as_node<OptionButton>("%building_type");
if (building_type->is_connected("item_selected", this,
"change_building_type"))
building_type->disconnect("item_selected", this,
"change_building_type");
}
protected:
static void _bind_methods()
{
ClassDB::bind_method(
D_METHOD("change_building_type", "index"),
&HandleChangeBuildingType::change_building_type);
}
};
class HandleButton : public Object {
GDCLASS(HandleButton, Object)
BuildingsEditor *editor;
String button_path;
String event_string;
Vector<Variant> event_args;
Button *get_button()
{
Button *button = editor->get_as_node<Button>(button_path);
assert(button);
return button;
}
void button_handler()
{
editor->emit("button:" + event_string, event_args);
}
public:
HandleButton(BuildingsEditor *editor, const String &button_path,
const String &event_string,
const Vector<Variant> &event_args = varray())
: Object()
, editor(editor)
, button_path(button_path)
, event_string(event_string)
, event_args(event_args)
{
if (!get_button()->is_connected("pressed", this,
"button_handler"))
get_button()->connect("pressed", this,
"button_handler");
}
virtual ~HandleButton()
{
if (get_button()->is_connected("pressed", this,
"button_handler"))
get_button()->disconnect("pressed", this,
"button_handler");
}
static void _bind_methods()
{
ClassDB::bind_method(D_METHOD("button_handler"),
&HandleButton::button_handler);
}
};
class HandleDeleteButton : public Object {
GDCLASS(HandleDeleteButton, Object)
BuildingsEditor *editor;
public:
HandleDeleteButton(BuildingsEditor *editor)
: Object()
, editor(editor)
{
Button *delete_button = editor->get_as_node<Button>(
"%buildings_delete_building");
assert(delete_button);
/* FIXME */
if (!delete_button->is_connected("pressed", this,
"delete_building_handler"))
delete_button->connect("pressed", this,
"delete_building_handler");
}
~HandleDeleteButton()
{
Button *delete_button = editor->get_as_node<Button>(
"%buildings_delete_building");
if (delete_button->is_connected("pressed", this,
"delete_building_handler"))
delete_button->disconnect("pressed", this,
"delete_building_handler");
}
void delete_building_handler()
{
editor->delete_building_handler();
}
static void _bind_methods()
{
ClassDB::bind_method(
D_METHOD("delete_building_handler"),
&HandleDeleteButton::delete_building_handler);
}
};
static std::vector<Object *> ui_handlers;
BuildingsEditor::BuildingsEditor(WorldEditor *editor)
: editor(editor)
, selected_building("")
@@ -363,37 +32,16 @@ void BuildingsEditor::exit()
void BuildingsEditor::activate()
{
assert(scene());
assert(!active);
ConfigFile config;
Error result = config.load("res://config/stream.conf");
ERR_FAIL_COND_MSG(result != OK, "Failed to load config");
print_line("BuildingsEditor ACTIVE");
ui_handlers.push_back(
memnew(HandleButton(this, "%buildings_create_building",
"create_building", varray())));
ui_handlers.push_back(memnew(HandleChangeBuildingType(this)));
ui_handlers.push_back(memnew(HandleDeleteButton(this)));
ui_handlers.push_back(memnew(HandlePositionSetting(this)));
int i;
for (i = 0; i < (int)ui_handlers.size(); i++)
assert(ui_handlers[i]);
/* TODO: make separate function for this */
EditorEvent::get_singleton()->event.add_listener(
this, &BuildingsEditor::event_handler);
Dictionary buildings_data =
config.get_value("buildings", "building_data");
OptionButton *building_type =
get_as_node<OptionButton>("%building_type");
building_type->clear();
List<Variant> keys;
buildings_data.get_key_list(&keys);
List<Variant>::Element *e = keys.front();
while (e) {
const String &key = e->get();
print_line("EE::" + key);
building_type->add_item(key);
e = e->next();
}
active = true;
}
@@ -403,16 +51,13 @@ void BuildingsEditor::deactivate()
EditorEvent::get_singleton()->event.remove_listener(
this, &BuildingsEditor::event_handler);
print_line("BuildingsEditor DEACTIVE");
int i;
for (i = 0; i < (int)ui_handlers.size(); i++)
memdelete(ui_handlers[i]);
ui_handlers.clear();
active = false;
}
void BuildingsEditor::event_handler(const String &event,
const Vector<Variant> &args)
{
assert(scene());
assert(active);
print_line("E::" + event);
if (event == "mouse_drag")
@@ -421,6 +66,8 @@ void BuildingsEditor::event_handler(const String &event,
mouse_press(args[0]);
else if (event == "button:create_building")
handle_create_building();
else if (event == "button:delete_building")
delete_building_handler();
else if (event == "result:get_closest_building") {
select_building(args[0], args[3], args[4]);
if (get_buildings_editor_mode() == 2 /* rotate */) {
@@ -444,34 +91,35 @@ void BuildingsEditor::event_handler(const String &event,
void BuildingsEditor::handle_create_building()
{
assert(scene());
print_line("create_building");
int bmode = get_buildings_editor_mode();
assert(bmode == 3);
OptionButton *building_type =
get_as_node<OptionButton>("%building_type");
int index = building_type->get_selected();
if (index >= 0) {
const String &item = building_type->get_item_text(index);
Transform xform;
xform.origin = get_cursor_position();
Dictionary building_data;
/* FIXME: calculate AABBs as in previous editor */
String building_xform = to_string<Transform>(xform);
building_data["id"] = item;
building_data["key"] = String::num_uint64(
String(item + building_xform +
itos(Time::get_singleton()->get_ticks_usec()))
.hash64(),
16);
building_data["xform"] = building_xform;
editor->editor_command("create_building",
varray(building_data));
}
flecs::world ecs = BaseData::get_singleton()->get();
flecs::entity e = ecs.lookup("world_editor");
assert(e.is_valid());
const String &item =
e.get<WorldEditor::components::buildings_editor_mode>()
->current_type;
Transform xform;
xform.origin = get_cursor_position();
Dictionary building_data;
/* FIXME: calculate AABBs as in previous editor */
String building_xform = to_string<Transform>(xform);
building_data["id"] = item;
building_data["key"] = String::num_uint64(
String(item + building_xform +
itos(Time::get_singleton()->get_ticks_usec()))
.hash64(),
16);
building_data["xform"] = building_xform;
editor->editor_command("create_building", varray(building_data));
}
template <class T>
inline void BuildingsEditor::mode_visibility(int mode, const String &path)
{
assert(scene());
T *obj = get_as_node<T>(path);
if (get_buildings_editor_mode() == mode) {
if (!obj->is_visible())
@@ -484,6 +132,7 @@ inline void BuildingsEditor::mode_visibility(int mode, const String &path)
void BuildingsEditor::update(float delta)
{
assert(scene());
#ifdef _VERBOSE_DEBUG
if (active)
print_line("update: " + String::num(delta) + " " +
@@ -500,13 +149,11 @@ void BuildingsEditor::update(float delta)
rot_cursor->set_global_transform(
selected_building_xform);
}
mode_visibility<Button>(0, "%buildings_delete_building");
mode_visibility<Spatial>(2, "%building_rot_cursor");
mode_visibility<Button>(3, "%buildings_create_building");
}
void BuildingsEditor::mouse_drag(const Vector2 &position)
{
assert(scene());
if (editor->get_current_mode() != WorldEditor::MODE_BUILDINGS) {
print_verbose("bad editor mode: " +
itos(editor->get_current_mode()));
@@ -579,6 +226,7 @@ void BuildingsEditor::mouse_drag(const Vector2 &position)
void BuildingsEditor::mouse_press(const Vector2 &position)
{
assert(scene());
if (editor->get_current_mode() != WorldEditor::MODE_BUILDINGS) {
print_verbose("bad editor mode: " +
itos(editor->get_current_mode()));
@@ -644,6 +292,7 @@ void BuildingsEditor::mouse_press(const Vector2 &position)
void BuildingsEditor::set_cursor_position(const Vector3 &position)
{
assert(scene());
Spatial *cursor = get_as_node<Spatial>("%building_cursor");
if (!cursor->is_visible())
cursor->show();
@@ -657,6 +306,7 @@ void BuildingsEditor::set_cursor_position(const Vector3 &position)
Vector3 BuildingsEditor::get_cursor_position() const
{
assert(scene());
const Spatial *cursor = get_as_node<Spatial>("%building_cursor");
Transform xform = cursor->get_global_transform();
return xform.origin;
@@ -664,10 +314,12 @@ Vector3 BuildingsEditor::get_cursor_position() const
int BuildingsEditor::get_buildings_editor_mode() const
{
const OptionButton *buildings_edit_mode =
get_as_node<OptionButton>("%buildings_edit_mode");
int selected = buildings_edit_mode->get_selected();
return selected;
flecs::world ecs = BaseData::get_singleton()->get();
flecs::entity e = ecs.lookup("world_editor");
assert(e.is_valid());
int mode =
e.get<WorldEditor::components::buildings_editor_mode>()->mode;
return mode;
}
BuildingsEditor::~BuildingsEditor()
@@ -717,27 +369,11 @@ void BuildingsEditor::select_building(const Transform &xform, const String &key,
const String &mid)
{
int i;
assert(scene());
selected_building_xform = xform;
selected_building = key;
print_line("selected key: " + key);
OptionButton *building_type = Object::cast_to<OptionButton>(
editor->get_node(NodePath("%building_type")));
assert(building_type);
bool ok = false;
for (i = 0; i < building_type->get_item_count(); i++) {
const String &item = building_type->get_item_text(i);
if (item == mid) {
building_type->select(i);
ok = true;
break;
}
}
if (ok) {
Button *delete_button =
get_as_node<Button>("%buildings_delete_building");
delete_button->show();
emit("buildings_building_selected", varray());
}
emit("set_selected_building_type", varray(mid));
set_cursor_position(xform.origin);
}
@@ -761,6 +397,7 @@ template <class T> T *BuildingsEditor::get_as_node(const String &path)
template <class T>
const T *BuildingsEditor::get_as_node(const String &path) const
{
assert(scene());
const Node *node = scene()->get_node(NodePath(path));
assert(node);
const T *ret = Object::cast_to<T>(node);
@@ -770,11 +407,15 @@ const T *BuildingsEditor::get_as_node(const String &path) const
Node *BuildingsEditor::scene()
{
assert(editor);
assert(editor->get_tree());
return editor->get_tree()->get_current_scene();
}
const Node *BuildingsEditor::scene() const
{
assert(editor);
assert(editor->get_tree());
const Node *ret = editor->get_tree()->get_current_scene();
return ret;
}

View File

@@ -0,0 +1,11 @@
Import("env")
Import("env_modules")
env.stream_building_sources = []
env.add_source_files(env.stream_building_sources, "*.cpp")
lib = env.add_library("npc", env.stream_building_sources)
env.Prepend(LIBS=[lib])
env.Prepend(CPPPATH=[".."])
env.Prepend(CPPPATH=["../../../meshoptimizer/src"])

View File

@@ -0,0 +1,147 @@
#include <core/os/memory.h>
#include <core/vector.h>
#include <core/ustring.h>
#include <core/math/transform.h>
#include <core/object.h>
#include <scene/main/scene_tree.h>
#include "flecs/flecs.h"
#include "base_data.h"
#include "npc.h"
NPC *NPC::singleton = nullptr;
namespace NPCModule
{
struct NPCBase {
int id;
String name;
};
struct NPCLocation {
Transform global_location, local_position;
};
struct NPCTarget {
Transform target;
};
struct NPCTargetKey {
String location_key;
};
struct NPCBackgroundMotion {
float speed;
};
struct NPCBody {
/* TODO: implement */
void *nothing;
};
struct NPCAnimation {
/* TODO: implement */
void *nothing;
};
struct NPCResidence {
String residence_key;
};
struct NPCOccupation {
/* building key */
String occupation_key;
// index in building's job list
int job_type;
int start_hour;
int end_hour;
// bit field from mon to sun
int week_days;
};
/* Assign leisure on the go depending on
character mood and stats */
struct NPCLeisure {
String leisure_key;
};
struct module {
module(flecs::world &ecs)
{
ecs.module<struct module>();
ecs.component<struct NPCBase>();
ecs.component<struct NPCLocation>();
ecs.component<struct NPCTarget>();
ecs.component<struct NPCTargetKey>();
ecs.component<struct NPCBody>();
ecs.component<struct NPCAnimation>();
ecs.component<struct NPCResidence>();
ecs.component<struct NPCOccupation>();
ecs.component<struct NPCLeisure>();
/* moving NPC despawned NPC */
ecs.system<NPCBase>("Update").each(
[](flecs::entity e, NPCBase &b) {
// TODO: implement;
});
}
};
}
class Updater : public Object {
GDCLASS(Updater, Object)
NPC *base;
public:
Updater(NPC *base)
: Object()
, base(base)
{
SceneTree::get_singleton()->connect("physics_frame", this,
"update");
}
virtual ~Updater()
{
}
void update()
{
float delta =
SceneTree::get_singleton()->get_physics_process_time();
base->update(delta);
print_line("Update running");
}
protected:
static void _bind_methods()
{
ClassDB::bind_method(D_METHOD("update"), &Updater::update);
}
};
static Updater *updater = nullptr;
NPC::NPC()
{
flecs::world ecs = BaseData::get_singleton()->get();
ecs.import <NPCModule::module>();
flecs::entity npcs_e = ecs.entity("npc");
if (!updater)
updater = memnew(Updater(this));
}
NPC *NPC::get_singleton()
{
if (!singleton)
singleton = memnew(NPC);
return singleton;
}
void NPC::cleanup()
{
memdelete(singleton);
}
NPC::~NPC()
{
}
void NPC::update(float delta)
{
BaseData::get_singleton()->get().progress(delta);
}

View File

@@ -0,0 +1,13 @@
#ifndef NPC_H_
#define NPC_H_
class NPC {
static NPC *singleton;
NPC();
public:
static NPC *get_singleton();
static void cleanup();
virtual ~NPC();
void update(float delta);
};
#endif

View File

@@ -5,6 +5,7 @@
#include "nav_panel.h"
#include "line_metadata_editor.h"
#include "buildings/building_layout_editor.h"
#include "ui/main_tabs.h"
void register_stream_types()
{
@@ -14,6 +15,7 @@ void register_stream_types()
ClassDB::register_class<NavPanel>();
ClassDB::register_class<LineMetadataEditor>();
ClassDB::register_class<BuildingLayoutEditor>();
ClassDB::register_class<MainTabs>();
}
void unregister_stream_types()

View File

@@ -0,0 +1,18 @@
Import("env")
Import("env_modules")
#env_modules.stream_building_sources = []
#
#env_modules.add_source_files(env_modules.stream_building_sources, "*.cpp")
#
#lib = env_modules.add_library("buildings", env_modules.stream_building_sources)
#env_modules.Prepend(LIBS=[lib])
env.stream_building_sources = []
env.add_source_files(env.stream_building_sources, "*.cpp")
lib = env.add_library("ui", env.stream_building_sources)
env.Prepend(LIBS=[lib])
env.Prepend(CPPPATH=[".."])
env.Prepend(CPPPATH=["../../../meshoptimizer/src"])

View File

@@ -0,0 +1,910 @@
#include <unordered_map>
#include <cstdio>
#include <core/engine.h>
#include <scene/gui/box_container.h>
#include <scene/gui/label.h>
#include <scene/gui/separator.h>
#include <scene/gui/panel_container.h>
#include <scene/gui/button.h>
#include <scene/gui/option_button.h>
#include <scene/gui/line_edit.h>
#include <scene/gui/item_list.h>
#include "world_editor.h"
#include "buildings_editor.h"
#include "base_data.h"
#include "editor_event.h"
#include "main_tabs.h"
class HandleBuildingsEditorMode : public Object {
GDCLASS(HandleBuildingsEditorMode, Object)
OptionButton *ob;
BuildingsEditor *editor;
void update_editor_mode(int index)
{
flecs::world ecs = BaseData::get_singleton()->get();
flecs::entity e = ecs.lookup("world_editor");
assert(e.is_valid());
e.set<WorldEditor::components::buildings_editor_mode>(
{ index });
}
public:
HandleBuildingsEditorMode(OptionButton *ob, BuildingsEditor *editor)
: Object()
, ob(ob)
, editor(editor)
{
ob->connect("item_selected", this, "update_editor_mode");
}
~HandleBuildingsEditorMode()
{
ob->disconnect("item_selected", this, "update_editor_mode");
}
protected:
static void _bind_methods()
{
ClassDB::bind_method(
D_METHOD("update_editor_mode", "index"),
&HandleBuildingsEditorMode::update_editor_mode);
}
};
class HandleBuildingType : public Object {
GDCLASS(HandleBuildingType, Object)
OptionButton *ob;
BuildingsEditor *editor;
void change_building_type(int index)
{
assert(editor->scene());
const String &item = ob->get_item_text(index);
int bmode = editor->get_buildings_editor_mode();
if (bmode == 0 || bmode == 1 ||
bmode == 2) /* select, move, rotate */
editor->change_building_type(item);
/* do not change building types in create mode (3) */
flecs::world ecs = BaseData::get_singleton()->get();
flecs::entity e = ecs.lookup("world_editor");
assert(e.is_valid());
e.get_mut<WorldEditor::components::buildings_editor_mode>()
->current_type = item;
}
public:
HandleBuildingType(OptionButton *ob, BuildingsEditor *editor)
: Object()
, ob(ob)
, editor(editor)
{
ConfigFile config;
Error result = config.load("res://config/stream.conf");
ERR_FAIL_COND_MSG(result != OK, "Failed to load config");
Dictionary buildings_data =
config.get_value("buildings", "building_data");
ob->clear();
List<Variant> keys;
buildings_data.get_key_list(&keys);
List<Variant>::Element *e = keys.front();
while (e) {
const String &key = e->get();
print_line("EE::" + key);
ob->add_item(key);
e = e->next();
}
ob->connect("item_selected", this, "change_building_type");
}
virtual ~HandleBuildingType()
{
if (ob->is_connected("item_selected", this,
"change_building_type"))
ob->disconnect("item_selected", this,
"change_building_type");
}
static void _bind_methods()
{
ClassDB::bind_method(D_METHOD("change_building_type", "index"),
&HandleBuildingType::change_building_type);
}
};
class HandleFullPositionSetting : public Object {
GDCLASS(HandleFullPositionSetting, Object)
BuildingsEditor *editor;
MainTabs *gui;
int old_mode;
public:
HandleFullPositionSetting(BuildingsEditor *editor, MainTabs *gui)
: Object()
, editor(editor)
, gui(gui)
, old_mode(-1)
{
SceneTree::get_singleton()->connect("idle_frame", this,
"handle_update");
Button *set_cursor_position = gui->get_as_node<Button>(
"%buildings_set_cursor_position");
set_cursor_position->connect("pressed", this,
"handle_set_cursor");
Button *set_building_position = gui->get_as_node<Button>(
"%buildings_set_building_position");
set_building_position->connect("pressed", this,
"handle_set_building");
EditorEvent::get_singleton()->event.add_listener(
this, &HandleFullPositionSetting::handle_event);
#if 0
String building = editor->get_selected_building();
if (building.length() > 0) {
Vector3 building_pos =
editor->get_selected_building_xform().origin;
}
#endif
assert(set_cursor_position);
assert(set_building_position);
}
virtual ~HandleFullPositionSetting()
{
EditorEvent::get_singleton()->event.remove_listener(
this, &HandleFullPositionSetting::handle_event);
Button *set_building_position = gui->get_as_node<Button>(
"%buildings_set_building_position");
set_building_position->disconnect("pressed", this,
"handle_set_building");
Button *set_cursor_position = gui->get_as_node<Button>(
"%buildings_set_cursor_position");
set_cursor_position->disconnect("pressed", this,
"handle_set_cursor");
SceneTree::get_singleton()->disconnect("idle_frame", this,
"handle_update");
}
protected:
static void _bind_methods()
{
ClassDB::bind_method(D_METHOD("handle_update"),
&HandleFullPositionSetting::handle_update);
ClassDB::bind_method(
D_METHOD("handle_set_cursor"),
&HandleFullPositionSetting::handle_set_cursor);
ClassDB::bind_method(
D_METHOD("handle_set_building"),
&HandleFullPositionSetting::handle_set_building);
}
private:
void handle_event(const String &event, const Vector<Variant> &args)
{
if (event == "buildings_building_cursor_moved") {
Vector3 position = args[0];
LineEdit *cursor_x = gui->get_as_node<LineEdit>(
"%building_cursor_x");
LineEdit *cursor_y = gui->get_as_node<LineEdit>(
"%building_cursor_y");
LineEdit *cursor_z = gui->get_as_node<LineEdit>(
"%building_cursor_z");
cursor_x->set_text(String::num(position.x));
cursor_y->set_text(String::num(position.y));
cursor_z->set_text(String::num(position.z));
} else if (event == "buildings_building_selected" ||
event == "buildings_building_moved" ||
event == "buildings_building_rotated") {
LineEdit *position_x = gui->get_as_node<LineEdit>(
"%building_position_x");
LineEdit *position_y = gui->get_as_node<LineEdit>(
"%building_position_y");
LineEdit *position_z = gui->get_as_node<LineEdit>(
"%building_position_z");
LineEdit *position_rot = gui->get_as_node<LineEdit>(
"%building_rotation_y");
Transform xform = editor->get_selected_building_xform();
position_x->set_text(String::num(xform.origin.x));
position_y->set_text(String::num(xform.origin.y));
position_z->set_text(String::num(xform.origin.z));
Vector3 reference(0, 0, -1);
Vector3 rotated =
xform.basis.xform(reference).normalized();
float angle = reference.signed_angle_to(
rotated, Vector3(0, 1, 0));
position_rot->set_text(
String::num(angle * 180.0f / Math_PI));
}
}
void handle_set_cursor()
{
LineEdit *cursor_x =
gui->get_as_node<LineEdit>("%building_cursor_x");
LineEdit *cursor_y =
gui->get_as_node<LineEdit>("%building_cursor_y");
LineEdit *cursor_z =
gui->get_as_node<LineEdit>("%building_cursor_z");
Vector3 position;
position.x = cursor_x->get_text().to_float();
position.y = cursor_y->get_text().to_float();
position.z = cursor_z->get_text().to_float();
editor->set_cursor_position(position);
}
void handle_set_building()
{
LineEdit *position_x =
gui->get_as_node<LineEdit>("%building_position_x");
LineEdit *position_y =
gui->get_as_node<LineEdit>("%building_position_y");
LineEdit *position_z =
gui->get_as_node<LineEdit>("%building_position_z");
LineEdit *position_rot =
gui->get_as_node<LineEdit>("%building_rotation_y");
Transform xform = editor->get_selected_building_xform();
xform.basis = Basis().rotated(
Vector3(0, 1, 0),
position_rot->get_text().to_float() * Math_PI / 180.0f);
xform.origin.x = position_x->get_text().to_float();
xform.origin.y = position_y->get_text().to_float();
xform.origin.z = position_z->get_text().to_float();
String key = editor->get_selected_building();
int mode = editor->get_buildings_editor_mode();
if (mode == 1 || mode == 2)
editor->set_cursor_position(xform.origin);
editor->emit("run_update_building_transform",
varray(key, xform));
}
void handle_update()
{
if (Engine::get_singleton()->is_editor_hint())
return;
// TODO: handle selection
int i;
int mode = editor->get_buildings_editor_mode();
LineEdit *cursor_x =
gui->get_as_node<LineEdit>("%building_cursor_x");
LineEdit *cursor_y =
gui->get_as_node<LineEdit>("%building_cursor_y");
LineEdit *cursor_z =
gui->get_as_node<LineEdit>("%building_cursor_z");
LineEdit *cursor_le[] = { cursor_x, cursor_y, cursor_z };
Button *set_cursor_position = gui->get_as_node<Button>(
"%buildings_set_cursor_position");
LineEdit *position_x =
gui->get_as_node<LineEdit>("%building_position_x");
LineEdit *position_y =
gui->get_as_node<LineEdit>("%building_position_y");
LineEdit *position_z =
gui->get_as_node<LineEdit>("%building_position_z");
LineEdit *position_rot =
gui->get_as_node<LineEdit>("%building_rotation_y");
LineEdit *position_le[] = { position_x, position_y, position_z,
position_rot };
Button *set_building_position = gui->get_as_node<Button>(
"%buildings_set_building_position");
int sz_cursor = (int)(sizeof(cursor_le) / sizeof(cursor_le[0]));
int sz_position =
(int)(sizeof(position_le) / sizeof(position_le[0]));
if (mode != old_mode) {
switch (mode) {
case 0: // select
for (i = 0; i < sz_cursor; i++)
cursor_le[i]->set_editable(false);
set_cursor_position->set_disabled(true);
for (i = 0; i < sz_position; i++)
position_le[i]->set_editable(false);
set_building_position->set_disabled(true);
break;
case 1: // move
for (i = 0; i < sz_cursor; i++)
cursor_le[i]->set_editable(false);
set_cursor_position->set_disabled(true);
for (i = 0; i < sz_position; i++)
position_le[i]->set_editable(true);
set_building_position->set_disabled(false);
break;
case 2: // rotate
for (i = 0; i < sz_cursor; i++)
cursor_le[i]->set_editable(false);
set_cursor_position->set_disabled(true);
for (i = 0; i < sz_position; i++)
position_le[i]->set_editable(true);
set_building_position->set_disabled(false);
break;
case 3: // create
for (i = 0; i < sz_cursor; i++)
cursor_le[i]->set_editable(true);
set_cursor_position->set_disabled(false);
for (i = 0; i < sz_position; i++)
position_le[i]->set_editable(true);
set_building_position->set_disabled(false);
break;
}
old_mode = mode;
}
}
};
class HandleCmdButton : public Object {
GDCLASS(HandleCmdButton, Object)
Button *button;
WorldEditor *editor;
String command;
Vector<Variant> args;
void button_handler()
{
assert(command.length() > 0);
editor->editor_command(command, args);
}
public:
HandleCmdButton(Button *button, WorldEditor *editor,
const String &command,
const Vector<Variant> &args = varray())
: Object()
, button(button)
, editor(editor)
, command(command)
, args(args)
{
assert(button);
assert(this->command.length() > 0);
if (!button->is_connected("pressed", this, "button_handler")) {
button->connect("pressed", this, "button_handler");
assert(button->is_connected("pressed", this,
"button_handler"));
}
}
virtual ~HandleCmdButton()
{
assert(button);
assert(button->is_connected("pressed", this, "button_handler"));
if (button->is_connected("pressed", this, "button_handler"))
button->disconnect("pressed", this, "button_handler");
}
protected:
static void _bind_methods()
{
ClassDB::bind_method(D_METHOD("button_handler"),
&HandleCmdButton::button_handler);
}
};
class HandleEventButton : public Object {
GDCLASS(HandleEventButton, Object)
Button *button;
BuildingsEditor *editor;
String event_string;
Vector<Variant> event_args;
void button_handler()
{
assert(event_string.length() > 0);
editor->emit("button:" + event_string, event_args);
}
public:
HandleEventButton(Button *button, BuildingsEditor *editor,
const String &event_string,
const Vector<Variant> &event_args = varray())
: Object()
, button(button)
, editor(editor)
, event_string(event_string)
, event_args(event_args)
{
assert(button);
assert(this->event_string.length() > 0);
if (!button->is_connected("pressed", this, "button_handler")) {
button->connect("pressed", this, "button_handler");
assert(button->is_connected("pressed", this,
"button_handler"));
}
}
virtual ~HandleEventButton()
{
assert(button);
assert(button->is_connected("pressed", this, "button_handler"));
if (button->is_connected("pressed", this, "button_handler"))
button->disconnect("pressed", this, "button_handler");
}
protected:
static void _bind_methods()
{
ClassDB::bind_method(D_METHOD("button_handler"),
&HandleEventButton::button_handler);
}
};
static Vector<Object *> c_handlers;
static void ui_field_builder(Node *owner, Node *parent, const String format,
const Vector<Variant> args)
{
int argp = 0, i;
List<Node *> stack;
int fmt_size = (int)format.length();
int args_size = (int)args.size();
Control *last_created = nullptr;
flecs::world ecs = BaseData::get_singleton()->get();
flecs::entity world_editor_e = ecs.lookup("world_editor");
WorldEditor *we =
world_editor_e
.get<WorldEditor::components::world_editor_node>()
->node;
BuildingsEditor *be =
world_editor_e
.get<WorldEditor::components::buildings_editor_node>()
->node;
for (i = 0; i < format.length(); i++) {
const char *fmt = format.ascii().ptr();
int c = fmt[i];
printf("character: %c : argp: %d\n", (char)c, argp);
switch (c) {
case '{':
stack.push_front(parent);
parent = last_created;
break;
case '}':
parent = stack.front()->get();
stack.pop_front();
break;
case '#': {
assert(argp < args_size);
String name = args[argp++];
assert(name.length() > 0);
last_created->set_name(name);
printf("set name: %s\n", name.ascii().ptr());
} break;
case '.':
assert(argp < args_size);
last_created->set_custom_minimum_size(args[argp++]);
break;
case '!':
last_created->set_unique_name_in_owner(true);
break;
case '+':
assert(argp < args_size);
last_created->set_h_size_flags(args[argp++]);
break;
case 'v':
case 'V':
case 'h':
case 'H':
if (c == 'v' || c == 'V') {
VBoxContainer *vb = memnew(VBoxContainer);
parent->add_child(vb);
vb->set_owner(owner);
last_created = vb;
} else {
HBoxContainer *hb = memnew(HBoxContainer);
parent->add_child(hb);
hb->set_owner(owner);
last_created = hb;
}
break;
case 'l':
case 'L':
assert(i < fmt_size - 1);
assert(argp < args_size);
{
Label *l = memnew(Label);
l->set_text(args[argp++]);
parent->add_child(l);
l->set_owner(owner);
last_created = l;
}
break;
case 'e':
case 'E':
assert(i < fmt_size);
assert(argp < args_size);
{
LineEdit *l = memnew(LineEdit);
assert(argp < args_size);
l->set_text(args[argp++]);
parent->add_child(l);
l->set_owner(owner);
last_created = l;
}
break;
case 'b':
case 'B':
assert(argp < args_size);
{
Button *b = memnew(Button);
assert(argp < args_size);
b->set_text(args[argp++]);
parent->add_child(b);
b->set_owner(owner);
last_created = b;
}
break;
case 'o':
assert(argp < args_size);
{
int j, count;
OptionButton *b = memnew(OptionButton);
assert(argp < args_size);
b->set_text(args[argp++]);
parent->add_child(b);
b->set_owner(owner);
assert(argp < args_size);
count = args[argp++];
for (j = 0; j < count; j++) {
assert(argp < args_size);
int id = args[argp++];
assert(argp < args_size);
String text = args[argp++];
b->add_item(text, id);
}
last_created = b;
}
break;
case 'i':
assert(argp < args_size);
{
int j, count;
ItemList *l = memnew(ItemList);
assert(argp < args_size);
parent->add_child(l);
l->set_owner(owner);
assert(argp < args_size);
count = args[argp++];
for (j = 0; j < count; j++) {
assert(argp < args_size);
String text = args[argp++];
l->add_item(text);
}
last_created = l;
}
break;
case '_': {
HSeparator *hs = memnew(HSeparator);
parent->add_child(hs);
hs->set_owner(owner);
last_created = hs;
} break;
case '|': {
VSeparator *vs = memnew(VSeparator);
parent->add_child(vs);
vs->set_owner(owner);
last_created = vs;
} break;
case 'q': {
assert(argp + 1 < args_size);
Button *b = Object::cast_to<Button>(last_created);
assert(b);
HandleCmdButton *cmd = memnew(HandleCmdButton(
b, we, args[argp++], args[argp++]));
c_handlers.push_back(cmd);
} break;
case 'Q': {
assert(argp + 1 < args_size);
Button *b = Object::cast_to<Button>(last_created);
assert(b);
HandleEventButton *cmd = memnew(HandleEventButton(
b, be, args[argp++], args[argp++]));
c_handlers.push_back(cmd);
} break;
case 'T': {
assert(argp < args_size);
OptionButton *b =
Object::cast_to<OptionButton>(last_created);
assert(b);
HandleBuildingType *cmd =
memnew(HandleBuildingType(b, be));
c_handlers.push_back(cmd);
} break;
case 'M': {
assert(argp < args_size);
OptionButton *b =
Object::cast_to<OptionButton>(last_created);
assert(b);
HandleBuildingsEditorMode *cmd =
memnew(HandleBuildingsEditorMode(b, be));
c_handlers.push_back(cmd);
} break;
default:
printf("bad character %c\n", (char)c);
assert(false);
}
}
}
template <class T>
inline void MainTabs::mode_visibility(int mode, const String &path)
{
T *obj = get_as_node<T>(path);
flecs::world ecs = BaseData::get_singleton()->get();
flecs::entity e = ecs.lookup("world_editor");
assert(e.is_valid());
int bmode =
e.get<WorldEditor::components::buildings_editor_mode>()->mode;
if (bmode == mode) {
if (!obj->is_visible())
obj->show();
} else {
if (obj->is_visible())
obj->hide();
}
}
void MainTabs::handle_event(const String &event, const Vector<Variant> &args)
{
int i;
if (event == "buildings_building_selected")
get_as_node<Button>("%buildings_delete_building")->show();
else if (event == "set_selected_building_type") {
String mid = args[0];
OptionButton *building_type = Object::cast_to<OptionButton>(
get_node(NodePath("%building_type")));
assert(building_type);
bool ok = false;
for (i = 0; i < building_type->get_item_count(); i++) {
const String &item = building_type->get_item_text(i);
if (item == mid) {
building_type->select(i);
ok = true;
break;
}
}
if (ok)
EditorEvent::get_singleton()->event.emit(
"buildings_building_selected", varray());
}
}
void MainTabs::_notification(int which)
{
struct StringHasher {
std::size_t operator()(const String &s) const
{
return (std::size_t)s.hash64();
}
};
int j;
switch (which) {
case NOTIFICATION_ENTER_TREE:
connect("tab_changed", this, "tab_changed");
EditorEvent::get_singleton()->event.add_listener(
this, &MainTabs::handle_event);
break;
case NOTIFICATION_READY: {
struct menu_data {
String title, command, header;
};
struct menu_data items[] = {
{ "Buildings", "select_buildings", "Buildings mode" },
{ "Navigation", "select_navigation",
"Navigation mode" },
{ "POI", "select_poi", "POI mode" },
{ "Lines", "select_road_lines", "Lines mode" },
{ "NPC", "select_npc", "NPC mode" },
};
flecs::world ecs = BaseData::get_singleton()->get();
flecs::entity world_editor_e = ecs.lookup("world_editor");
assert(world_editor_e.is_valid());
assert(world_editor_e.has<
WorldEditor::components::buildings_editor_node>());
WorldEditor *we =
world_editor_e
.get<WorldEditor::components::world_editor_node>()
->node;
BuildingsEditor *editor =
world_editor_e
.get<WorldEditor::components::
buildings_editor_node>()
->node;
int i;
for (i = 0; i < (int)(sizeof(items) / sizeof(items[0])); i++) {
VBoxContainer *tab = memnew(VBoxContainer);
tab->set_name(items[i].title);
tab->set_meta("command", items[i].command);
tab->set_owner(this);
add_child(tab);
Label *header = memnew(Label);
header->set_text(items[i].header);
tab->add_child(header);
header->set_owner(this);
HSeparator *sep = memnew(HSeparator);
tab->add_child(sep);
sep->set_owner(this);
PanelContainer *panel = memnew(PanelContainer);
tab->add_child(panel);
panel->set_owner(this);
switch (i) {
case 0: {
// VBoxContainer *v = memnew(VBoxContainer);
//panel->add_child(v);
//v->set_owner(this);
//Label *l1 = memnew(Label);
//v->add_child(l1);
//l1->set_owner(this);
//l1->set_text("Cursor position");
// create_position_setting(
// this, v, "building_cursor",
// "buildings_set_cursor_position");
{
String cursor_prefix =
"building_cursor";
String building_prefix =
"building_position";
/* clang-format off */
std::vector<Variant> args_data = {
/* 0 */
"Cursor position",
/* 1 */
"", cursor_prefix + "_x", Control::SIZE_EXPAND_FILL,
"", cursor_prefix + "_y", Control::SIZE_EXPAND_FILL,
"", cursor_prefix + "_z", Control::SIZE_EXPAND_FILL,
"Set", "buildings_set_cursor_position",
/* 12 */
"Selected building position",
"", building_prefix + "_x", Control::SIZE_EXPAND_FILL,
"", building_prefix + "_y", Control::SIZE_EXPAND_FILL,
"", building_prefix + "_z", Control::SIZE_EXPAND_FILL,
"rot",
"", "building_rotation_y",
/* 25 */
"Set", "buildings_set_building_position",
"Mode",
/* 28 */
"Select", 4, 0, "Select", 1, "Move", 2, "Rotate", 3, "Create", "buildings_edit_mode",
/* 39 */
"Building type",
/* 40 */
"Building Type", 0, "building_type",
/* 43 */
"Delete Building", "buildings_delete_building", "delete_building", varray(),
/* 47 */
"Create Building", "buildings_create_building", "create_building", varray(),
/* 51 */
"Save Buildings", "buildings_save", "buildings_save", varray(),
/* 55 */
0, Vector2(0, 80), "lines_list_building",
/* 58 */
"Assign To Line", "buildings_assign_to_line"
/* 60 */
};
/* clang-format on */
Vector<Variant> args;
args.resize(args_data.size());
{
Variant *pw = args.ptrw();
for (j = 0; j < args.size();
j++)
pw[j] = args_data.data()
[j];
}
#if 0
/* clang-format off */
/* 0 */
args.push_back("Cursor position");
/* 1 */
args.push_back(""); args.push_back(cursor_prefix + "_x"); args.push_back(Control::SIZE_EXPAND_FILL);
/* 4 */
args.push_back(""); args.push_back(cursor_prefix + "_y"); args.push_back(Control::SIZE_EXPAND_FILL);
/* 7 */
args.push_back(""); args.push_back(cursor_prefix + "_z"); args.push_back(Control::SIZE_EXPAND_FILL);
/* 10 */
args.push_back("Set"); args.push_back("building_set_cursor_position");
/* 12 */
args.push_back("Selected building position");
/* 13 */
args.push_back(""); args.push_back(building_prefix + "_x"); args.push_back(Control::SIZE_EXPAND_FILL);
/* 16 */
args.push_back(""); args.push_back(building_prefix + "_y"); args.push_back(Control::SIZE_EXPAND_FILL);
/* 19 */
args.push_back(""); args.push_back(building_prefix + "_z"); args.push_back(Control::SIZE_EXPAND_FILL);
/* 22 */
args.push_back("rot");
/* 23 */
args.push_back(""); args.push_back("building_rotation_y");
/* 25 */
args.push_back("Set"); args.push_back("buildings_set_building_position");
args.push_back("Mode");
/* 28 */
args.push_back("Select");
args.push_back(4);
args.push_back(0); args.push_back("Select");
args.push_back(1); args.push_back("Move");
args.push_back(2); args.push_back("Rotate");
args.push_back(3); args.push_back("Create");
args.push_back("buildings_edit_mode");
/* 39 */
args.push_back("Building type");
/* 40 */
args.push_back("Building Type"); args.push_back(0); args.push_back("building_type");
/* 43 */
args.push_back("Delete Building");
args.push_back("buildings_delete_building");
args.push_back("delete_building");
args.push_back(varray());
/* 47 */
args.push_back("Create Building");
args.push_back("buildings_create_building");
args.push_back("create_building");
args.push_back(varray());
/* 51 */
args.push_back("Save Buildings");
args.push_back("buildings_save");
args.push_back("buildings_save");
args.push_back(varray());
/* 55 */
args.push_back(0); args.push_back(Vector2(0, 80)); args.push_back("lines_list_building");
/* 58 */
args.push_back("Assign To Line"); args.push_back("buildings_assign_to_line");
/* 60 */
/* clang-format on */
print_line(itos(args_data.size()) +
" " + itos(args.size()));
assert((int)args_data.size() ==
(int)args.size());
#endif
ui_field_builder(
this, panel,
"v{lh{e#!+e#!+e#!+b#!}lh{e#!+e#!+e#!+}h{le#!b#!}_lo#!Mlo#!T_b#!Qb#!QB#!qi.#!b#!}",
args);
}
} break;
}
}
handlers.push_back(
memnew(HandleFullPositionSetting(editor, this)));
set_process(true);
} break;
case NOTIFICATION_PROCESS: {
mode_visibility<Button>(0, "%buildings_delete_building");
mode_visibility<Spatial>(2, "%building_rot_cursor");
mode_visibility<Button>(3, "%buildings_create_building");
} break;
case NOTIFICATION_EXIT_TREE:
set_process(false);
EditorEvent::get_singleton()->event.remove_listener(
this, &MainTabs::handle_event);
break;
}
}
void MainTabs::_bind_methods()
{
ClassDB::bind_method(D_METHOD("tab_changed", "tab"),
&MainTabs::tab_changed);
}
void MainTabs::tab_changed(int tab)
{
print_line(get_tab_control(tab)->get_name());
assert(get_tab_control(tab)->has_meta("command"));
if (Engine::get_singleton()->is_editor_hint())
return;
String command = get_tab_control(tab)->get_meta("command");
EditorEvent::get_singleton()->event.emit(command, varray());
}
void MainTabs::hide_control(const String &path)
{
get_as_node<Control>(path)->hide();
}
void MainTabs::show_control(const String &path)
{
get_as_node<Control>(path)->show();
}
template <class T> T *MainTabs::get_as_node(const String &path)
{
Node *node = get_node(NodePath(path));
assert(node);
T *ret = Object::cast_to<T>(node);
assert(ret);
return ret;
}
template <class T> const T *MainTabs::get_as_node(const String &path) const
{
const Node *node = get_node(NodePath(path));
assert(node);
const T *ret = Object::cast_to<T>(node);
assert(ret);
return ret;
}

View File

@@ -0,0 +1,22 @@
#include <scene/gui/tab_container.h>
class MainTabs : public TabContainer {
GDCLASS(MainTabs, TabContainer)
Vector<Object *> handlers;
template <class T>
inline void mode_visibility(int mode, const String &path);
void handle_event(const String &event, const Vector<Variant> &args);
public:
void _notification(int which);
protected:
static void _bind_methods();
void tab_changed(int tab);
public:
template <class T> T *get_as_node(const String &path);
template <class T> const T *get_as_node(const String &path) const;
void hide_control(const String &path);
void show_control(const String &path);
};

View File

@@ -14,6 +14,7 @@
#include "road_lines_editor.h"
#include "world_editor.h"
#include "editor_event.h"
#include "base_data.h"
#include "buildings_editor.h"
class HandleCommandButton : public Object {
@@ -76,6 +77,14 @@ WorldEditor::WorldEditor()
, road_lines_editor(memnew(RoadLinesEditor(this)))
, buildings_editor(memnew(BuildingsEditor(this)))
{
flecs::entity e;
flecs::world ecs = BaseData::get_singleton()->get();
ecs.component<WorldEditor::components::world_editor_node>();
ecs.component<WorldEditor::components::buildings_editor_node>();
ecs.component<WorldEditor::components::road_lines_editor_node>();
ecs.component<WorldEditor::components::buildings_editor_mode>();
e = ecs.lookup("world_editor");
assert(!e.is_valid());
if (!InputMap::get_singleton()->has_action("left"))
InputMap::get_singleton()->add_action("left");
if (!InputMap::get_singleton()->has_action("right"))
@@ -98,11 +107,23 @@ WorldEditor::WorldEditor()
InputMap::get_singleton()->add_action("mouse1");
EditorEvent::get_singleton()->event.add_listener(
this, &WorldEditor::event_signal_handler);
e = ecs.entity("world_editor");
assert(e.is_valid());
e.set<WorldEditor::components::world_editor_node>({ this });
e.set<WorldEditor::components::buildings_editor_node>(
{ buildings_editor });
e.set<WorldEditor::components::road_lines_editor_node>(
{ road_lines_editor });
e.set<WorldEditor::components::buildings_editor_mode>({ 0, "" });
print_line("constructed");
}
WorldEditor::~WorldEditor()
{
flecs::world ecs = BaseData::get_singleton()->get();
flecs::entity e = ecs.lookup("world_editor");
assert(e.is_valid());
e.destruct();
EditorEvent::get_singleton()->event.remove_listener(
this, &WorldEditor::event_signal_handler);
if (road_lines_editor) {
@@ -218,6 +239,8 @@ static std::unordered_map<int, String> vmode = { { 2, "%v_buildings" },
void WorldEditor::tools_button(const String &button)
{
print_line("tools_button: " + button);
if (Engine::get_singleton()->is_editor_hint())
return;
if (modes.find(button) == modes.end())
goto end;
assert(modes[button] >= 0);
@@ -330,6 +353,10 @@ int WorldEditor::get_current_mode() const
void WorldEditor::event_signal_handler(const String &event,
const Vector<Variant> &args)
{
if (event.begins_with("select_")) {
editor_command(event, args);
return;
}
if (event == "mode_change_pre") {
int prev_mode = args[0];
if (prev_mode == -1) {
@@ -404,12 +431,14 @@ void WorldEditor::_notification(int which)
Node *base = get_parent();
int count = base->get_child_count();
int i;
#if 0
for (i = 0; i < (int)tool_buttons.size(); i++) {
String bname =
get_node(NodePath(tool_buttons[i]))->get_name();
tool_handlers.push_back(memnew(HandleCommandButton(
this, tool_buttons[i], bname)));
}
#endif
for (i = 0; i < count; i++) {
Node *node = base->get_child(i);
StreamWorld *sw = Object::cast_to<StreamWorld>(node);

View File

@@ -53,6 +53,21 @@ public:
int get_current_mode() const;
void event_signal_handler(const String &event,
const Vector<Variant> &args);
struct components {
struct world_editor_node {
WorldEditor *node;
};
struct buildings_editor_node {
BuildingsEditor *node;
};
struct road_lines_editor_node {
RoadLinesEditor *node;
};
struct buildings_editor_mode {
int mode;
String current_type;
};
};
};
#endif