Refactoring; Started GUI for interior layout graph

This commit is contained in:
2024-10-25 22:16:35 +03:00
parent 2cc591706f
commit 3b4006e02d
19 changed files with 1713 additions and 1148 deletions

View File

@@ -1,3 +1,5 @@
#ifndef BASE_DATA_H
#define BASE_DATA_H
#include "flecs/flecs.h"
class BaseData {
flecs::world ecs;
@@ -11,3 +13,4 @@ public:
static BaseData *get_singleton();
void cleanup();
};
#endif

View File

@@ -234,6 +234,7 @@ static LinesAccessor lines;
ImmediateGeometry *RoadLinesData::debug_im = nullptr;
static Ref<Material> debug_material;
RoadLinesData::RoadLinesData()
: initialized(false)
{
load_data();
}
@@ -286,6 +287,7 @@ RoadLinesData *RoadLinesData::get_singleton()
{
if (!singleton)
singleton = memnew(RoadLinesData);
assert(singleton->initialized);
return singleton;
}
RoadLinesData::~RoadLinesData()
@@ -321,7 +323,9 @@ void RoadLinesData::get_road_lines_key_list(List<String> *keys)
}
void RoadLinesData::get_lines_key_list(List<String> *keys)
{
assert(initialized);
::lines.get_key_list(keys);
assert(!keys->empty());
}
const String &RoadLinesData::get_next_line(const String &key)
{
@@ -337,6 +341,7 @@ void RoadLinesData::load_data()
ConfigFile config;
Error result = config.load("res://config/stream.conf");
ERR_FAIL_COND_MSG(result != OK, "Failed to load config");
assert(result == OK);
road_lines_path = config.get_value("lines", "road_lines_path");
String road_lines_path = config.get_value("lines", "road_lines_path");
String road_lines_json =
@@ -345,7 +350,8 @@ void RoadLinesData::load_data()
String es;
int eline;
Error status = JSON::parse(road_lines_json, json_v, es, eline);
ERR_FAIL_COND_MSG(status != OK, "Can't parse json: " + es +
ERR_FAIL_COND_MSG(status != OK, "Can't parse json: " + road_lines_path +
": " + es +
" at line: " + itos(eline));
Dictionary json = json_v;
@@ -384,6 +390,12 @@ void RoadLinesData::load_data()
set_line(key, rline);
e = e->next();
}
{
List<String> tkeys;
::lines.get_key_list(&tkeys);
assert(!tkeys.empty());
}
initialized = true;
}
void RoadLinesData::save_data()
{

View File

@@ -7,6 +7,7 @@ class RoadLinesData {
String road_lines_path;
uint32_t road_lines_hash(const Vector3 &v);
static ImmediateGeometry *debug_im;
bool initialized;
protected:
RoadLinesData();

View File

@@ -219,19 +219,6 @@ public:
, editor(editor)
{
int i;
Node *menu_block =
editor->get_as_node<Node>("%road_lines_menu_block");
for (i = 0; i < menu_block->get_child_count(); i++) {
Node *menu_button_node = menu_block->get_child(i);
MenuButton *menu_button =
Object::cast_to<MenuButton>(menu_button_node);
if (!menu_button)
continue;
PopupMenu *popup = menu_button->get_popup();
popup->connect("id_pressed", this, "main_handler");
// popup->connect("mouse_exited", popup, "hide");
popup->connect("focus_exited", popup, "hide");
}
Button *cancel_button = editor->get_as_node<Button>(
"%road_lines_create_new_cancel");
LineEdit *line_name = editor->get_as_node<LineEdit>(
@@ -282,17 +269,6 @@ public:
line_name->disconnect("text_changed", this, "changed_handler");
line_name->disconnect("text_entered", this, "entered_handler");
cancel_button->disconnect("pressed", this, "cancel_handler");
Node *menu_block =
editor->get_as_node<Node>("%road_lines_menu_block");
for (i = 0; i < menu_block->get_child_count(); i++) {
Node *menu_button_node = menu_block->get_child(i);
MenuButton *menu_button =
Object::cast_to<MenuButton>(menu_button_node);
if (!menu_button)
continue;
PopupMenu *popup = menu_button->get_popup();
popup->disconnect("id_pressed", this, "main_handler");
}
}
protected:
@@ -324,129 +300,6 @@ protected:
items->add_item(key);
}
}
void main_handler(int id)
{
switch (id) {
case 11:
editor->line_create_point();
break;
case 12:
editor->line_delete_point();
break;
case 21:
/* Create line */
editor->get_as_node<Control>("%road_lines_base")->hide();
editor->get_as_node<Control>(
"%road_lines_create_new_line_dlg")
->show();
break;
case 22:
/* delete line */
editor->delete_current_line();
break;
case 23:
/* edit line metadata */
if (current_line == "") {
print_error("No current line set");
return;
}
editor->get_as_node<Control>("%road_lines_base")->hide();
editor->get_as_node<Control>(
"%road_lines_edit_metadata_dlg")
->show();
update_metadata_editor();
break;
case 30:
editor->remove_generated_stuff();
break;
case 31:
editor->place_generated_objects();
break;
case 32:
editor->rebuild_roads();
break;
case 33:
editor->remove_road_meshes();
break;
case 34: {
RoadLinesData::get_singleton()->assign_close_buildings(
current_line);
editor->update_line_geometry();
} break;
case 36:
editor->get_as_node<Control>("%road_lines_base")->hide();
editor->get_as_node<Control>("%road_lines_buildings")
->show();
update_line_buildings_editor();
break;
case 51:
editor->set_point_to_cursor();
break;
case 52:
editor->move_cursor_to_point();
break;
case 53:
editor->move_cursor_to_closest_building();
case 101:
editor->save_data();
break;
case 201:
case 210:
case 211:
case 212: {
print_line("selected item 201");
int i, j;
Node *menu_block = editor->get_as_node<Node>(
"%road_lines_menu_block");
for (i = 0; i < menu_block->get_child_count(); i++) {
Node *menu_button_node =
menu_block->get_child(i);
MenuButton *menu_button =
Object::cast_to<MenuButton>(
menu_button_node);
if (!menu_button)
continue;
PopupMenu *popup = menu_button->get_popup();
for (j = 0; j < popup->get_item_count(); j++) {
int nid = popup->get_item_id(j);
if (nid == id) {
bool checked =
popup->is_item_checked(
j);
if (checked)
print_line("checked");
else
print_line("unchecked");
checked = !checked;
popup->set_item_checked(
j, checked);
switch (id) {
case 201:
editor->set_update_roads(
checked);
break;
case 210:
editor->set_debug_road_nodes(
checked);
break;
case 211:
editor->set_debug_road_edges(
checked);
break;
case 212:
editor->set_debug_road_wedges(
checked);
break;
}
}
}
}
} break;
default:
print_line("menu option pressed: " + itos(id));
assert(false);
}
}
void cancel_handler()
{
LineEdit *line_name = editor->get_as_node<LineEdit>(
@@ -553,8 +406,6 @@ protected:
}
static void _bind_methods()
{
ClassDB::bind_method(D_METHOD("main_handler", "id"),
&HandleCreateNewLine::main_handler);
ClassDB::bind_method(D_METHOD("cancel_handler"),
&HandleCreateNewLine::cancel_handler);
ClassDB::bind_method(D_METHOD("entered_handler", "new_text"),
@@ -1127,6 +978,38 @@ void RoadLinesEditor::set_debug_road_wedges(bool checked)
{
debug_road_wedges = checked;
}
const String &RoadLinesEditor::get_current_line() const
{
return current_line;
}
const String &RoadLinesEditor::get_filter_text() const
{
return filter_text;
}
void RoadLinesEditor::get_matching_lines(List<String> *lines)
{
if (!re.is_valid())
re.instance();
re->compile(filter_text);
if (filter_text.length() > 0 && !re->is_valid())
return;
List<String> line_keys;
RoadLinesData *rld = RoadLinesData::get_singleton();
rld->get_lines_key_list(&line_keys);
assert(!line_keys.empty());
lines->clear();
List<String>::Element *e = line_keys.front();
while (e) {
Array matches = re->search_all(e->get());
if (filter_text.length() > 0 && matches.size() == 0) {
e = e->next();
continue;
}
lines->push_back(e->get());
e = e->next();
}
assert(!lines->empty());
}
void RoadLinesEditor::place_zebras()
{
editor->editor_command("remove_buildings_by_prefix", varray("zebra"));

View File

@@ -59,6 +59,9 @@ public:
void set_debug_road_nodes(bool checked);
void set_debug_road_edges(bool checked);
void set_debug_road_wedges(bool checked);
const String &get_current_line() const;
const String &get_filter_text() const;
void get_matching_lines(List<String> *lines);
protected:
void activate();

View File

@@ -0,0 +1,107 @@
#ifndef BUILDING_LAYOUT_GRAPH_UI_H
#define BUILDING_LAYOUT_GRAPH_UI_H
#include <cassert>
#include <vector>
#include <core/object.h>
#include <core/variant.h>
#include <core/engine.h>
#include <scene/gui/dialogs.h>
#include <scene/gui/menu_button.h>
#include <scene/gui/color_rect.h>
#include "ui_field_builder.h"
class BuildingLayoutGraphUI : public Object {
GDCLASS(BuildingLayoutGraphUI, Object)
WindowDialog *dlg;
Control *canvas_item;
public:
BuildingLayoutGraphUI(WindowDialog *dlg)
: Object()
, dlg(dlg)
{
dlg->connect("tree_entered", this, "tree_entered");
}
void tree_entered()
{
if (!Engine::get_singleton()->is_editor_hint()) {
/* move this elsewhere */
std::vector<Variant> args_data2 = {
/* clang-format off */
MARGIN_RIGHT, 1.0f, MARGIN_BOTTOM, 1.0f,
// Control::SIZE_EXPAND_FILL, Control::SIZE_EXPAND_FILL,
// MARGIN_RIGHT, 1.0f, MARGIN_BOTTOM, 1.0f,
// Control::SIZE_EXPAND_FILL, Control::SIZE_EXPAND_FILL,
"Layout Graph",
MARGIN_RIGHT, 1.0f, MARGIN_BOTTOM, 1.0f,
"buildings_layout_graph",
MARGIN_RIGHT, 1.0f, MARGIN_BOTTOM, 1.0f,
"Interior",
"Exterior",
/* clang-format on */
};
ui_field::ui_field_builder(
dlg, dlg,
// "p+={t+={v#{s#!+={}}v#{}v#{}}}",
"t**{v#{s**{p#!**}}v#{}v#{}}",
args_data2.data(), args_data2.size());
dlg->update();
update_graph();
}
}
void update_graph()
{
int i;
assert(dlg->get_node(NodePath("%buildings_layout_graph")));
Control *base = Object::cast_to<Control>(
dlg->get_node(NodePath("%buildings_layout_graph")));
ScrollContainer *p =
Object::cast_to<ScrollContainer>(base->get_parent());
p->set_v_size_flags(Control::SIZE_EXPAND_FILL);
p->set_h_size_flags(Control::SIZE_EXPAND_FILL);
p->set_anchor(MARGIN_RIGHT, 1.0f);
p->set_anchor(MARGIN_BOTTOM, 1.0f);
base->set_custom_minimum_size(Vector2(2048, 1600));
LocalVector<Node *> data;
for (i = 0; i < base->get_child_count(); i++)
data.push_back(base->get_child(i));
for (i = 0; i < (int)data.size(); i++) {
base->remove_child(data[i]);
data[i]->queue_delete();
}
data.clear();
ColorRect *canvas = memnew(ColorRect);
base->add_child(canvas);
canvas->set_frame_color(Color(0.2, 0.2, 0.25, 1.0));
canvas_item = canvas;
canvas->connect("draw", this, "draw_graph");
MenuButton *button = memnew(MenuButton);
button->set_text("Entry");
canvas->add_child(button);
button->set_size(Vector2(80, 40));
button->set_position(Vector2(40, 45));
button->get_popup()->add_item("Create block unit", 100);
button->get_popup()->add_item("Create private zone", 101);
button->get_popup()->add_item("Create public zone", 102);
button->get_popup()->add_item("Create hallway", 103);
}
void draw_graph()
{
canvas_item->draw_rect(Rect2(Vector2(),
canvas_item->get_size()),
Color(0.2, 0.2, 0.25, 1.0));
canvas_item->draw_circle(Vector2(40, 45) + Vector2(40, 20),
40.0f, Color(0.4, 0.4, 0.55, 1.0));
}
static void _bind_methods()
{
ClassDB::bind_method(D_METHOD("tree_entered"),
&BuildingLayoutGraphUI::tree_entered);
ClassDB::bind_method(D_METHOD("draw_graph"),
&BuildingLayoutGraphUI::draw_graph);
}
};
#endif

View File

@@ -0,0 +1,66 @@
#ifndef HANDLE_BUILDING_TYPE_H
#define HANDLE_BUILDING_TYPE_H
#include <core/object.h>
#include <scene/gui/option_button.h>
#include "buildings_editor.h"
#include "base_data.h"
#include "world_editor.h"
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);
}
};
#endif

View File

@@ -0,0 +1,42 @@
#ifndef HANDLE_BUILDINGS_EDITOR_MODE
#define HANDLE_BUILDINGS_EDITOR_MODE
#include <core/object.h>
#include <scene/gui/option_button.h>
#include "buildings_editor.h"
#include "base_data.h"
#include "world_editor.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);
}
};
#endif

View File

@@ -0,0 +1,62 @@
#ifndef HANDLE_CMD_BUTTON_H
#define HANDLE_CMD_BUTTON_H
#include <core/object.h>
#include <core/engine.h>
#include <scene/gui/option_button.h>
#include <scene/gui/item_list.h>
#include <scene/gui/line_edit.h>
#include "buildings_editor.h"
#include "base_data.h"
#include "world_editor.h"
#include "main_tabs.h"
#include "road_lines_data.h"
#include "road_lines_editor.h"
#include "editor_event.h"
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);
}
};
#endif

View File

@@ -0,0 +1,62 @@
#ifndef HANDLE_EVENT_BUTTON_H
#define HANDLE_EVENT_BUTTON_H
#include <core/object.h>
#include <core/engine.h>
#include <scene/gui/option_button.h>
#include <scene/gui/item_list.h>
#include <scene/gui/line_edit.h>
#include "buildings_editor.h"
#include "base_data.h"
#include "world_editor.h"
#include "main_tabs.h"
#include "road_lines_data.h"
#include "road_lines_editor.h"
#include "editor_event.h"
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);
}
};
#endif

View File

@@ -0,0 +1,226 @@
#ifndef HANDLE_FULL_POSITION_SETTING_H
#define HANDLE_FULL_POSITION_SETTING_H
#include <core/object.h>
#include <core/engine.h>
#include <scene/gui/option_button.h>
#include <scene/gui/item_list.h>
#include <scene/gui/line_edit.h>
#include "buildings_editor.h"
#include "base_data.h"
#include "world_editor.h"
#include "main_tabs.h"
#include "road_lines_data.h"
#include "road_lines_editor.h"
#include "editor_event.h"
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;
}
}
};
#endif

View File

@@ -0,0 +1,85 @@
#ifndef HANDLE_LINES_LIST_H
#define HANDLE_LINES_LIST_H
#include <core/object.h>
#include <scene/gui/option_button.h>
#include <scene/gui/item_list.h>
#include "buildings_editor.h"
#include "base_data.h"
#include "world_editor.h"
#include "main_tabs.h"
#include "road_lines_data.h"
#include "road_lines_editor.h"
#include "editor_event.h"
class HandleLinesList : public Object {
GDCLASS(HandleLinesList, Object)
public:
RoadLinesEditor *editor;
MainTabs *gui;
void handler(int index)
{
if (index < 0)
return;
ItemList *lines_list =
gui->get_as_node<ItemList>("%lines_list");
editor->select_line(lines_list->get_item_text(index));
}
void update_ui()
{
RoadLinesData *rld = RoadLinesData::get_singleton();
ItemList *lines_list =
gui->get_as_node<ItemList>("%lines_list");
assert(lines_list);
List<String> line_keys;
editor->get_matching_lines(&line_keys);
assert(!line_keys.empty());
List<String>::Element *e = line_keys.front();
lines_list->clear();
int selected_index = -1;
int index = 0;
while (e) {
String key = e->get();
if (key == editor->get_current_line())
selected_index = index;
lines_list->add_item(key);
e = e->next();
index++;
}
if (selected_index >= 0)
lines_list->set_current(selected_index);
else
lines_list->set_current(0);
}
HandleLinesList(RoadLinesEditor *editor, MainTabs *gui)
: Object()
, editor(editor)
, gui(gui)
{
ItemList *lines_list =
gui->get_as_node<ItemList>("%lines_list");
update_ui();
EditorEvent::get_singleton()->event.add_listener(
this, &HandleLinesList::event_handler);
lines_list->connect("item_selected", this, "handler");
}
virtual ~HandleLinesList()
{
ItemList *lines_list =
gui->get_as_node<ItemList>("%lines_list");
lines_list->disconnect("item_selected", this, "handler");
assert(lines_list);
}
void event_handler(const String &event, const Vector<Variant> &args)
{
if (event == "lines_select_line")
update_ui();
}
protected:
static void _bind_methods()
{
ClassDB::bind_method(D_METHOD("handler", "index"),
&HandleLinesList::handler);
}
};
#endif

View File

@@ -7,607 +7,30 @@
#include <scene/gui/panel_container.h>
#include <scene/gui/button.h>
#include <scene/gui/option_button.h>
#include <scene/gui/menu_button.h>
#include <scene/gui/line_edit.h>
#include <scene/gui/item_list.h>
#include <scene/gui/spin_box.h>
#include <scene/gui/text_edit.h>
#include <scene/gui/dialogs.h>
#include <scene/gui/color_rect.h>
#include "world_editor.h"
#include "buildings_editor.h"
#include "base_data.h"
#include "editor_event.h"
#include "road_lines_editor.h"
#include "road_lines_data.h"
#include "handle_buildings_editor_mode.h"
#include "handle_building_type.h"
#include "handle_lines_list.h"
#include "handle_cmd_button.h"
#include "handle_event_button.h"
#include "handle_full_position_setting.h"
#include "menu_handler.h"
#include "ui_field_builder.h"
#include "building_layout_graph_ui.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)
{
@@ -677,12 +100,18 @@ void MainTabs::_notification(int which)
{ "POI", "select_poi", "POI mode" },
{ "Lines", "select_road_lines", "Lines mode" },
{ "NPC", "select_npc", "NPC mode" },
{ "Building layouts", "select_building_layouts",
"Building layouts" },
};
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::world_editor_node>());
assert(world_editor_e.has<
WorldEditor::components::buildings_editor_node>());
assert(world_editor_e.has<
WorldEditor::components::road_lines_editor_node>());
WorldEditor *we =
world_editor_e
.get<WorldEditor::components::world_editor_node>()
@@ -692,23 +121,52 @@ void MainTabs::_notification(int which)
.get<WorldEditor::components::
buildings_editor_node>()
->node;
RoadLinesEditor *rleditor =
world_editor_e
.get<WorldEditor::components::
road_lines_editor_node>()
->node;
int i;
if (!Engine::get_singleton()->is_editor_hint()) {
npc_editor = memnew(WindowDialog);
SceneTree::get_singleton()
->get_current_scene()
->call_deferred("add_child", npc_editor);
npc_editor->set_anchor(MARGIN_TOP, 0.0316667f);
npc_editor->set_anchor(MARGIN_RIGHT, 0.746094f);
npc_editor->set_anchor(MARGIN_BOTTOM, 1.0f);
npc_editor->set_name("npc_editor");
npc_editor->set_unique_name_in_owner(true);
npc_editor->set_exclusive(false);
npc_editor->call_deferred(
"set_owner",
SceneTree::get_singleton()->get_current_scene());
building_layouts_editor = memnew(WindowDialog);
SceneTree::get_singleton()
->get_current_scene()
->call_deferred("add_child",
building_layouts_editor);
building_layouts_editor->set_anchor(MARGIN_TOP,
0.0316667f);
building_layouts_editor->set_anchor(MARGIN_RIGHT,
0.746094f);
building_layouts_editor->set_anchor(MARGIN_BOTTOM,
1.0f);
building_layouts_editor->set_name(
"building_layouts_editor");
building_layouts_editor->set_unique_name_in_owner(true);
building_layouts_editor->set_exclusive(false);
building_layouts_editor->call_deferred(
"set_owner",
SceneTree::get_singleton()->get_current_scene());
} else
building_layouts_editor = nullptr;
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);
@@ -728,6 +186,7 @@ void MainTabs::_notification(int which)
"building_position";
/* clang-format off */
std::vector<Variant> args_data = {
items[i].header,
/* 0 */
"Cursor position",
@@ -766,91 +225,131 @@ void MainTabs::_notification(int which)
/* 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);
ui_field::ui_field_builder(
this, tab,
"l_p{v{lh{e#!+e#!+e#!+b#!}lh{e#!+e#!+e#!+}h{le#!b#!}_lo#!Mlo#!T_b#!Qb#!QB#!qi.#!b#!}}",
args_data.data(),
args_data.size());
}
} break;
case 1: {
std::vector<Variant> args_data = {
items[i].header
};
ui_field::ui_field_builder(this, tab,
"l_p{v{}}",
args_data.data(),
args_data.size());
} break;
case 2: {
std::vector<Variant> args_data = {
items[i].header
};
ui_field::ui_field_builder(this, tab,
"l_p{v{}}",
args_data.data(),
args_data.size());
} break;
case 3: {
std::vector<Variant> args_data = {
/* clang-format off */
"road_lines_base",
items[i].header,
"road_lines_menu_block",
"File", 1,
101, "Save Lines", false,
"road_lines_file_menu",
"Edit", 1,
201, "Undo", false,
"road_lines_edit_menu",
"Point", 5,
11, "Create", false,
12, "Remove", false,
51, "Point To Cursor", false,
52, "Cursor To Point", false,
53, "Cursor to closest building", false,
"road_lines_point_menu",
"Line", 11,
21, "Create", false,
22, "Delete", false,
-1, "", false,
30, "Remove Generated", false,
31, "Place Generated Objects", false,
23, "Edit Line Metadata", false,
32, "Rebuild roads", false,
33, "Remove Road Meshes", false,
34, "Assign close (generated) buildings", false,
35, "Create new building at cursor", false,
36, "View Buildings", false,
"road_lines_line_menu",
"Options", 5,
201, "Update roads", true,
-1, "", false,
210, "Debug Road Nodes", true,
211, "Debug Road Edges", true,
212, "Debug Road Wedges", true,
"road_lines_options_menu",
"Road Lines mode",
"Filter: ",
"", "road_lines_filter",
0, Vector2(0, 80), "lines_list",
"line_index",
"Cursor position",
"road_lines_cursor_position",
"", "cursor_x",
"", "cursor_y",
"", "cursor_z",
"Set", "road_lines_set_cursor_position",
"Point position",
"road_lines_point_position",
"", "point_x",
"", "point_y",
"", "point_z",
"Set", "road_lines_set_point_position",
/* clang-format on */
};
ui_field::ui_field_builder(
this, tab,
"v{p#!{v{lh#!{m#!m#!m#!m#!m#!}_lh{le#!}i.#!x#!_lv#!{h{e#!e#!e#!b#!}}_lv#!{h{e#!e#!e#!b#!}}}}}",
// "p{v{lh#!{m#!m#!m#!m#!m#!}_lh{le#!}i.#!x#!_lv#!{h{e#!e#!e#!b#!}}_lv#!{h{e#!e#!e#!b#!}}}}",
args_data.data(), args_data.size());
} break;
case 4: {
std::vector<Variant> args_data = {
items[i].header
};
ui_field::ui_field_builder(this, tab,
"l_p{v{}}",
args_data.data(),
args_data.size());
} break;
case 5: {
std::vector<Variant> args_data = {
/* clang-format off */
items[i].header,
"Layouts:",
0, Vector2(0, 80), "building_layout_list",
"Create new layout",
"", "building_layouts_create_text", Control::SIZE_EXPAND_FILL,
"Create", "building_layouts_create_button",
/* clang-format on */
};
ui_field::ui_field_builder(
this, tab, "l_p{v{li.#!lh{e#+!b#!}}}",
args_data.data(), args_data.size());
} break;
}
}
handlers.push_back(
memnew(HandleFullPositionSetting(editor, this)));
set_process(true);
if (!Engine::get_singleton()->is_editor_hint()) {
handlers.push_back(memnew(
HandleFullPositionSetting(editor, this)));
handlers.push_back(memnew(MenuHandler(rleditor, this)));
handlers.push_back(
memnew(HandleLinesList(rleditor, this)));
handlers.push_back(memnew(BuildingLayoutGraphUI(
building_layouts_editor)));
set_process(true);
}
} break;
case NOTIFICATION_PROCESS: {
mode_visibility<Button>(0, "%buildings_delete_building");
@@ -879,6 +378,16 @@ void MainTabs::tab_changed(int tab)
return;
String command = get_tab_control(tab)->get_meta("command");
EditorEvent::get_singleton()->event.emit(command, varray());
if (tab == 4) {
npc_editor->set_exclusive(true);
npc_editor->show();
} else
npc_editor->hide();
if (tab == 5) {
building_layouts_editor->set_exclusive(true);
building_layouts_editor->show();
} else
building_layouts_editor->hide();
}
void MainTabs::hide_control(const String &path)

View File

@@ -1,8 +1,13 @@
#ifndef MAIN_TABS_H
#define MAIN_TABS_H
#include <scene/gui/tab_container.h>
class WindowDialog;
class MainTabs : public TabContainer {
GDCLASS(MainTabs, TabContainer)
Vector<Object *> handlers;
WindowDialog *npc_editor;
WindowDialog *building_layouts_editor;
template <class T>
inline void mode_visibility(int mode, const String &path);
void handle_event(const String &event, const Vector<Variant> &args);
@@ -20,3 +25,4 @@ public:
void hide_control(const String &path);
void show_control(const String &path);
};
#endif

View File

@@ -0,0 +1,219 @@
#ifndef MENU_HANDLER_H
#define MENU_HANDLER_H
#include <core/object.h>
#include <core/engine.h>
#include <scene/gui/option_button.h>
#include <scene/gui/item_list.h>
#include <scene/gui/line_edit.h>
#include <scene/gui/menu_button.h>
#include <scene/gui/text_edit.h>
#include "buildings_editor.h"
#include "base_data.h"
#include "world_editor.h"
#include "main_tabs.h"
#include "road_lines_data.h"
#include "road_lines_editor.h"
#include "editor_event.h"
class MenuHandler : public Object {
GDCLASS(MenuHandler, Object)
RoadLinesEditor *editor;
MainTabs *gui;
public:
MenuHandler(RoadLinesEditor *editor, MainTabs *gui)
: Object()
, editor(editor)
, gui(gui)
{
int i;
Node *menu_block =
gui->get_as_node<Node>("%road_lines_menu_block");
for (i = 0; i < menu_block->get_child_count(); i++) {
Node *menu_button_node = menu_block->get_child(i);
MenuButton *menu_button =
Object::cast_to<MenuButton>(menu_button_node);
if (!menu_button)
continue;
PopupMenu *popup = menu_button->get_popup();
popup->connect("id_pressed", this, "main_handler");
// popup->connect("mouse_exited", popup, "hide");
popup->connect("focus_exited", popup, "hide");
}
}
virtual ~MenuHandler()
{
int i;
Node *menu_block =
gui->get_as_node<Node>("%road_lines_menu_block");
for (i = 0; i < menu_block->get_child_count(); i++) {
Node *menu_button_node = menu_block->get_child(i);
MenuButton *menu_button =
Object::cast_to<MenuButton>(menu_button_node);
if (!menu_button)
continue;
PopupMenu *popup = menu_button->get_popup();
popup->disconnect("id_pressed", this, "main_handler");
}
}
/* FIXME: handle elsewhere */
void update_metadata_editor()
{
if (editor->get_current_line() == "")
return;
TextEdit *metadata_edit = editor->get_as_node<TextEdit>(
"%road_lines_metadata_edit");
String text = editor->get_current_line_metadata();
metadata_edit->set_text(text);
}
void update_line_buildings_editor()
{
int i;
if (editor->get_current_line() == "")
return;
ItemList *items =
gui->get_as_node<ItemList>("%line_buildings_list");
items->clear();
for (i = 0; i < (int)RoadLinesData::get_singleton()
->lines(editor->get_current_line())
.buildings.size();
i++) {
const String &key =
RoadLinesData::get_singleton()
->lines(editor->get_current_line())
.buildings[i]
.building_key;
items->add_item(key);
}
}
void main_handler(int id)
{
switch (id) {
case 11:
editor->line_create_point();
break;
case 12:
editor->line_delete_point();
break;
case 21:
/* Create line */
editor->get_as_node<Control>("%road_lines_base")->hide();
editor->get_as_node<Control>(
"%road_lines_create_new_line_dlg")
->show();
break;
case 22:
/* delete line */
editor->delete_current_line();
break;
case 23:
/* edit line metadata */
if (editor->get_current_line() == "") {
print_error("No current line set");
return;
}
editor->get_as_node<Control>("%road_lines_base")->hide();
editor->get_as_node<Control>(
"%road_lines_edit_metadata_dlg")
->show();
update_metadata_editor();
break;
case 30:
editor->remove_generated_stuff();
break;
case 31:
editor->place_generated_objects();
break;
case 32:
editor->rebuild_roads();
break;
case 33:
editor->remove_road_meshes();
break;
case 34: {
RoadLinesData::get_singleton()->assign_close_buildings(
editor->get_current_line());
editor->update_line_geometry();
} break;
case 36:
editor->get_as_node<Control>("%road_lines_base")->hide();
editor->get_as_node<Control>("%road_lines_buildings")
->show();
update_line_buildings_editor();
break;
case 51:
editor->set_point_to_cursor();
break;
case 52:
editor->move_cursor_to_point();
break;
case 53:
editor->move_cursor_to_closest_building();
case 101:
editor->save_data();
break;
case 201:
case 210:
case 211:
case 212: {
print_line("selected item 201");
int i, j;
Node *menu_block = gui->get_as_node<Node>(
"%road_lines_menu_block");
for (i = 0; i < menu_block->get_child_count(); i++) {
Node *menu_button_node =
menu_block->get_child(i);
MenuButton *menu_button =
Object::cast_to<MenuButton>(
menu_button_node);
if (!menu_button)
continue;
PopupMenu *popup = menu_button->get_popup();
for (j = 0; j < popup->get_item_count(); j++) {
int nid = popup->get_item_id(j);
if (nid == id) {
bool checked =
popup->is_item_checked(
j);
if (checked)
print_line("checked");
else
print_line("unchecked");
checked = !checked;
popup->set_item_checked(
j, checked);
switch (id) {
case 201:
editor->set_update_roads(
checked);
break;
case 210:
editor->set_debug_road_nodes(
checked);
break;
case 211:
editor->set_debug_road_edges(
checked);
break;
case 212:
editor->set_debug_road_wedges(
checked);
break;
}
}
}
}
} break;
default:
print_line("menu option pressed: " + itos(id));
assert(false);
}
}
static void _bind_methods()
{
ClassDB::bind_method(D_METHOD("main_handler", "id"),
&MenuHandler::main_handler);
}
};
#endif

View File

@@ -0,0 +1,285 @@
#include <scene/gui/control.h>
#include <scene/gui/box_container.h>
#include <scene/gui/panel_container.h>
#include <scene/gui/tab_container.h>
#include <scene/gui/scroll_container.h>
#include <scene/gui/label.h>
#include <scene/gui/line_edit.h>
#include <scene/gui/button.h>
#include <scene/gui/option_button.h>
#include <scene/gui/item_list.h>
#include <scene/gui/menu_button.h>
#include <scene/gui/spin_box.h>
#include <scene/gui/separator.h>
#include "base_data.h"
#include "world_editor.h"
#include "handle_cmd_button.h"
#include "handle_event_button.h"
#include "handle_building_type.h"
#include "handle_buildings_editor_mode.h"
#include "ui_field_builder.h"
Vector<Object *> ui_field::c_handlers;
void ui_field::ui_field_builder(Node *owner, Node *parent, const String format,
const Variant *args, int args_size)
{
int argp = 0, i;
List<Node *> stack;
int fmt_size = (int)format.length();
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;
assert(owner->is_inside_tree());
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 '=':
assert(argp < args_size);
last_created->set_v_size_flags(args[argp++]);
break;
case '*': {
assert(argp + 1 < args_size);
assert(args[argp].get_type() == Variant::INT);
assert(args[argp + 1].get_type() == Variant::REAL);
Margin m = args[argp++];
float value = args[argp++];
last_created->set_anchor(m, value);
} break;
case 'v':
case 'h':
if (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 'p': {
PanelContainer *p = memnew(PanelContainer);
parent->add_child(p);
p->set_owner(owner);
last_created = p;
} break;
case 't': {
TabContainer *t = memnew(TabContainer);
parent->add_child(t);
t->set_owner(owner);
last_created = t;
} break;
case 's': {
ScrollContainer *sc = memnew(ScrollContainer);
parent->add_child(sc);
sc->set_owner(owner);
last_created = sc;
} 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 'm':
assert(argp < args_size);
{
int j, count;
MenuButton *b = memnew(MenuButton);
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++];
assert(argp < args_size);
bool checkable = args[argp++];
if (id == -1)
b->get_popup()->add_separator(
text, id);
else {
if (checkable)
b->get_popup()
->add_check_item(
text,
id);
else
b->get_popup()->add_item(
text, id);
}
}
b->set_switch_on_hover(true);
last_created = b;
}
break;
case 'x': {
SpinBox *sp = memnew(SpinBox);
parent->add_child(sp);
sp->set_owner(owner);
last_created = sp;
} 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);
}
}
}

View File

@@ -0,0 +1,13 @@
#ifndef UI_FIELD_BUILDER_H
#define UI_FIELD_BUILDER_H
#include <scene/main/node.h>
#include <core/object.h>
class ui_field {
public:
static Vector<Object *> c_handlers;
static void ui_field_builder(Node *owner, Node *parent,
const String format, const Variant *args,
int args_size);
};
#endif