|
|
|
|
@@ -208,7 +208,855 @@ void createItemsMenu()
|
|
|
|
|
ImGui::EndMenu();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
static void _setCameraSelectedPos(flecs::entity e)
|
|
|
|
|
{
|
|
|
|
|
Ogre::Vector3 cursorPos;
|
|
|
|
|
Ogre::Quaternion cursorOrientation;
|
|
|
|
|
// setCursorSelectedPos(e, cursorPos, cursorOrientation);
|
|
|
|
|
StaticGeometryModule::getItemPositionAndRotation(e, cursorPos,
|
|
|
|
|
cursorOrientation);
|
|
|
|
|
ECS::get<EditorGizmo>().sceneNode->_setDerivedPosition(cursorPos);
|
|
|
|
|
ECS::get<EditorGizmo>().sceneNode->_setDerivedOrientation(
|
|
|
|
|
cursorOrientation);
|
|
|
|
|
Ogre::Vector3 cameraPos =
|
|
|
|
|
ECS::get<Camera>().mCameraPivot->_getDerivedPosition();
|
|
|
|
|
Ogre::Vector3 cameraOffset =
|
|
|
|
|
cursorOrientation * Ogre::Vector3::UNIT_Z * 30.0f;
|
|
|
|
|
cameraPos.x = cursorPos.x;
|
|
|
|
|
cameraPos.z = cursorPos.z;
|
|
|
|
|
cameraPos += cameraOffset;
|
|
|
|
|
cameraPos.y = TerrainModule::get_height(
|
|
|
|
|
ECS::get<Terrain>().mTerrainGroup, cameraPos) +
|
|
|
|
|
10.0f;
|
|
|
|
|
Ogre::TerrainGroup *tg = ECS::get<Terrain>().mTerrainGroup;
|
|
|
|
|
long x, y;
|
|
|
|
|
tg->convertWorldPositionToTerrainSlot(cameraPos, &x, &y);
|
|
|
|
|
if (tg->getTerrain(x, y) && tg->getTerrain(x, y)->isLoaded()) {
|
|
|
|
|
float height = tg->getHeightAtWorldPosition(cameraPos);
|
|
|
|
|
cameraPos.y = height + 10.0f;
|
|
|
|
|
}
|
|
|
|
|
ECS::get<Camera>().mCameraPivot->_setDerivedPosition(cameraPos);
|
|
|
|
|
ECS::get<Camera>().mCameraPivot->_setDerivedOrientation(
|
|
|
|
|
cursorOrientation);
|
|
|
|
|
cameraPos = ECS::get<Camera>().mCameraGoal->_getDerivedPosition();
|
|
|
|
|
ECS::get<Camera>().mCameraNode->_setDerivedPosition(cameraPos);
|
|
|
|
|
ECS::get<Camera>().mCameraNode->_setDerivedOrientation(
|
|
|
|
|
ECS::get<Camera>().mCameraGoal->_getDerivedOrientation());
|
|
|
|
|
// updateHeightmap();
|
|
|
|
|
}
|
|
|
|
|
void drawRectPreview(nlohmann::json::json_pointer ptr,
|
|
|
|
|
const nlohmann::json &item)
|
|
|
|
|
{
|
|
|
|
|
// Reserve a square area spanning across the table
|
|
|
|
|
ImVec2 canvas_p0 = ImGui::GetCursorScreenPos();
|
|
|
|
|
ImVec2 canvas_sz = ImVec2(ImGui::GetContentRegionAvail().x, 200);
|
|
|
|
|
ImVec2 canvas_p1 =
|
|
|
|
|
ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y);
|
|
|
|
|
Ogre::String rectName = ptr.back();
|
|
|
|
|
nlohmann::json::json_pointer tmpptr = ptr;
|
|
|
|
|
tmpptr.pop_back();
|
|
|
|
|
const nlohmann::json &colorRects = item[tmpptr];
|
|
|
|
|
|
|
|
|
|
ImDrawList *draw_list = ImGui::GetWindowDrawList();
|
|
|
|
|
// Draw background
|
|
|
|
|
draw_list->AddRectFilled(canvas_p0, canvas_p1,
|
|
|
|
|
IM_COL32(50, 50, 50, 255));
|
|
|
|
|
|
|
|
|
|
for (auto &[name, data] : colorRects.items()) {
|
|
|
|
|
std::cout << data.dump() << std::endl;
|
|
|
|
|
// Map 0..1 to Screen Pixels
|
|
|
|
|
ImVec2 p_min =
|
|
|
|
|
ImVec2(canvas_p0.x + (float)data["left"] * canvas_sz.x,
|
|
|
|
|
canvas_p0.y + (float)data["top"] * canvas_sz.y);
|
|
|
|
|
ImVec2 p_max = ImVec2(
|
|
|
|
|
canvas_p0.x + (float)data["right"] * canvas_sz.x,
|
|
|
|
|
canvas_p0.y + (float)data["bottom"] * canvas_sz.y);
|
|
|
|
|
|
|
|
|
|
// Handle Color (assuming rgba are 0..255 or 0..1)
|
|
|
|
|
ImVec4 col = ImVec4(data["color"]["r"], data["color"]["g"],
|
|
|
|
|
data["color"]["b"], data["color"]["a"]);
|
|
|
|
|
|
|
|
|
|
// Draw the rect
|
|
|
|
|
draw_list->AddRectFilled(p_min, p_max,
|
|
|
|
|
ImGui::ColorConvertFloat4ToU32(col));
|
|
|
|
|
|
|
|
|
|
// Outline if selected
|
|
|
|
|
if (rectName == name)
|
|
|
|
|
draw_list->AddRect(p_min, p_max,
|
|
|
|
|
IM_COL32(255, 255, 0, 255), 0.0f, 0,
|
|
|
|
|
2.0f);
|
|
|
|
|
}
|
|
|
|
|
ImGui::Dummy(canvas_sz); // Advance cursor
|
|
|
|
|
}
|
|
|
|
|
#if 1
|
|
|
|
|
bool DrawGridSelectorInTableCell(const char *id, ImVec2 &outValue,
|
|
|
|
|
float cellSize = 20.0f)
|
|
|
|
|
{
|
|
|
|
|
bool changed = false;
|
|
|
|
|
static ImVec2 hoveredCell(-1, -1);
|
|
|
|
|
|
|
|
|
|
// Push style to ensure consistent spacing
|
|
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
|
|
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
|
|
|
|
|
|
|
|
|
|
ImDrawList *drawList = ImGui::GetWindowDrawList();
|
|
|
|
|
ImVec2 cursorPos = ImGui::GetCursorScreenPos();
|
|
|
|
|
|
|
|
|
|
for (int y = 0; y < 10; y++) {
|
|
|
|
|
for (int x = 0; x < 10; x++) {
|
|
|
|
|
ImVec2 cellMin = ImVec2(cursorPos.x + x * cellSize,
|
|
|
|
|
cursorPos.y + y * cellSize);
|
|
|
|
|
ImVec2 cellMax = ImVec2(cellMin.x + cellSize,
|
|
|
|
|
cellMin.y + cellSize);
|
|
|
|
|
|
|
|
|
|
// Use a dummy for spacing and hit detection
|
|
|
|
|
ImGui::PushID(y * 10 + x);
|
|
|
|
|
ImGui::Dummy(ImVec2(cellSize, cellSize));
|
|
|
|
|
|
|
|
|
|
// Check for interaction
|
|
|
|
|
if (ImGui::IsItemHovered()) {
|
|
|
|
|
hoveredCell = ImVec2(x / 9.0f, y / 9.0f);
|
|
|
|
|
|
|
|
|
|
if (ImGui::IsMouseClicked(0)) {
|
|
|
|
|
outValue = hoveredCell;
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ImGui::PopID();
|
|
|
|
|
|
|
|
|
|
// Draw cell
|
|
|
|
|
bool isSelected = (outValue.x == x / 9.0f &&
|
|
|
|
|
outValue.y == y / 9.0f);
|
|
|
|
|
bool isHovered = (hoveredCell.x == x / 9.0f &&
|
|
|
|
|
hoveredCell.y == y / 9.0f);
|
|
|
|
|
|
|
|
|
|
ImU32 color;
|
|
|
|
|
if (isSelected)
|
|
|
|
|
color = IM_COL32(100, 150, 255, 255);
|
|
|
|
|
else if (isHovered)
|
|
|
|
|
color = IM_COL32(80, 80, 120, 255);
|
|
|
|
|
else
|
|
|
|
|
color = IM_COL32(60, 60, 70, 255);
|
|
|
|
|
|
|
|
|
|
drawList->AddRectFilled(cellMin, cellMax, color);
|
|
|
|
|
drawList->AddRect(cellMin, cellMax,
|
|
|
|
|
IM_COL32(200, 200, 200, 255));
|
|
|
|
|
|
|
|
|
|
if (x < 9)
|
|
|
|
|
ImGui::SameLine();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Move cursor past the grid
|
|
|
|
|
ImGui::Dummy(ImVec2(1, 1));
|
|
|
|
|
|
|
|
|
|
ImGui::PopStyleVar(2);
|
|
|
|
|
|
|
|
|
|
return changed;
|
|
|
|
|
}
|
|
|
|
|
enum EditType {
|
|
|
|
|
EditNone = 0,
|
|
|
|
|
EditString,
|
|
|
|
|
EditMultilineString,
|
|
|
|
|
EditColorRect,
|
|
|
|
|
EditFloat,
|
|
|
|
|
EditBool,
|
|
|
|
|
EditInt,
|
|
|
|
|
ViewJson,
|
|
|
|
|
EditItemPosition,
|
|
|
|
|
EditLuaScript,
|
|
|
|
|
};
|
|
|
|
|
struct PropertyEditor;
|
|
|
|
|
// Property editor definition
|
|
|
|
|
struct PropertyEditor {
|
|
|
|
|
int editType;
|
|
|
|
|
std::string name;
|
|
|
|
|
std::function<bool(const std::string &itemName,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
const nlohmann::json &j)>
|
|
|
|
|
matches;
|
|
|
|
|
std::function<void(flecs::entity entity,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
nlohmann::json &j)>
|
|
|
|
|
render;
|
|
|
|
|
std::function<void(flecs::entity entity,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
nlohmann::json &j)>
|
|
|
|
|
apply;
|
|
|
|
|
};
|
|
|
|
|
struct DPropertyEditor : PropertyEditor {
|
|
|
|
|
private:
|
|
|
|
|
virtual bool _matches(const std::string &itemName,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
const nlohmann::json &j) = 0;
|
|
|
|
|
virtual void _render(flecs::entity entity,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
nlohmann::json &j) = 0;
|
|
|
|
|
virtual void _apply(flecs::entity entity,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
nlohmann::json &j)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
DPropertyEditor(int type, const std::string &name)
|
|
|
|
|
{
|
|
|
|
|
editType = type;
|
|
|
|
|
this->name = name;
|
|
|
|
|
matches = [this](const std::string &itemName,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
const nlohmann::json &j) -> bool {
|
|
|
|
|
return _matches(itemName, ptr, j);
|
|
|
|
|
};
|
|
|
|
|
render = [this](flecs::entity entity,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
nlohmann::json &j) { _render(entity, ptr, j); };
|
|
|
|
|
apply = [this](flecs::entity entity,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
nlohmann::json &j) { _apply(entity, ptr, j); };
|
|
|
|
|
}
|
|
|
|
|
PropertyEditor getPropertyEditor()
|
|
|
|
|
{
|
|
|
|
|
return { editType, name, matches, render, apply };
|
|
|
|
|
}
|
|
|
|
|
virtual ~DPropertyEditor()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
struct StringPropertyEditor : DPropertyEditor {
|
|
|
|
|
bool _matches(const std::string &itemName,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
const nlohmann::json &j) override
|
|
|
|
|
{
|
|
|
|
|
return j[ptr].is_string();
|
|
|
|
|
}
|
|
|
|
|
void _render(flecs::entity entity,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
nlohmann::json &j) override
|
|
|
|
|
{
|
|
|
|
|
static char buffer[260];
|
|
|
|
|
strncpy(buffer, j[ptr].get<Ogre::String>().c_str(),
|
|
|
|
|
sizeof(buffer));
|
|
|
|
|
|
|
|
|
|
ImGui::TableSetColumnIndex(0);
|
|
|
|
|
ImGui::Text("%s", ptr.back().c_str());
|
|
|
|
|
ImGui::TableSetColumnIndex(1);
|
|
|
|
|
ImGui::InputText("##value", buffer, sizeof(buffer));
|
|
|
|
|
|
|
|
|
|
if (ImGui::IsItemDeactivatedAfterEdit()) {
|
|
|
|
|
j[ptr] = buffer;
|
|
|
|
|
StaticGeometryModule::setItemProperties(entity,
|
|
|
|
|
j.dump());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
StringPropertyEditor()
|
|
|
|
|
: DPropertyEditor(EditString, "String Editor")
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
~StringPropertyEditor() override
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
// EditLuaScript
|
|
|
|
|
struct LuaScriptPropertyEditor : DPropertyEditor {
|
|
|
|
|
bool _matches(const std::string &itemName,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
const nlohmann::json &j) override
|
|
|
|
|
{
|
|
|
|
|
return itemName == "cellScript" && j[ptr].is_string();
|
|
|
|
|
}
|
|
|
|
|
void _render(flecs::entity entity,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
nlohmann::json &j) override
|
|
|
|
|
{
|
|
|
|
|
static char buffer[16384];
|
|
|
|
|
strncpy(buffer, j[ptr].get<Ogre::String>().c_str(),
|
|
|
|
|
sizeof(buffer));
|
|
|
|
|
|
|
|
|
|
ImGui::TableSetColumnIndex(0);
|
|
|
|
|
ImGui::Text("%s", ptr.back().c_str());
|
|
|
|
|
ImGui::TableSetColumnIndex(1);
|
|
|
|
|
ImGui::InputTextMultiline("##value", buffer, sizeof(buffer),
|
|
|
|
|
ImVec2(0, 0),
|
|
|
|
|
ImGuiInputTextFlags_AllowTabInput);
|
|
|
|
|
|
|
|
|
|
if (ImGui::IsItemDeactivatedAfterEdit()) {
|
|
|
|
|
j[ptr] = buffer;
|
|
|
|
|
StaticGeometryModule::setItemProperties(entity,
|
|
|
|
|
j.dump());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
LuaScriptPropertyEditor()
|
|
|
|
|
: DPropertyEditor(EditLuaScript, "Lua Script Editor")
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
~LuaScriptPropertyEditor() override
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
struct MultilineStringPropertyEditor : DPropertyEditor {
|
|
|
|
|
bool _matches(const std::string &itemName,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
const nlohmann::json &j) override
|
|
|
|
|
{
|
|
|
|
|
return j[ptr].is_string() &&
|
|
|
|
|
(j[ptr].get<std::string>().find("\n") !=
|
|
|
|
|
std::string::npos ||
|
|
|
|
|
j[ptr].get<std::string>().length() >= 100);
|
|
|
|
|
}
|
|
|
|
|
void _render(flecs::entity entity,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
nlohmann::json &j) override
|
|
|
|
|
{
|
|
|
|
|
static char buffer[4096];
|
|
|
|
|
strncpy(buffer, j[ptr].get<Ogre::String>().c_str(),
|
|
|
|
|
sizeof(buffer));
|
|
|
|
|
|
|
|
|
|
ImGui::TableSetColumnIndex(0);
|
|
|
|
|
ImGui::Text("%s", ptr.back().c_str());
|
|
|
|
|
ImGui::TableSetColumnIndex(1);
|
|
|
|
|
ImGui::InputTextMultiline("##value", buffer, sizeof(buffer));
|
|
|
|
|
|
|
|
|
|
if (ImGui::IsItemDeactivatedAfterEdit()) {
|
|
|
|
|
j[ptr] = buffer;
|
|
|
|
|
StaticGeometryModule::setItemProperties(entity,
|
|
|
|
|
j.dump());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
MultilineStringPropertyEditor()
|
|
|
|
|
: DPropertyEditor(EditMultilineString,
|
|
|
|
|
"Multiline String Editor")
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
~MultilineStringPropertyEditor() override
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
// Float editor
|
|
|
|
|
struct FloatPropertyEditor : DPropertyEditor {
|
|
|
|
|
bool _matches(const std::string &itemName,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
const nlohmann::json &j) override
|
|
|
|
|
{
|
|
|
|
|
return j[ptr].is_number_float();
|
|
|
|
|
}
|
|
|
|
|
void _render(flecs::entity entity,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
nlohmann::json &j) override
|
|
|
|
|
{
|
|
|
|
|
ImGui::TableSetColumnIndex(0);
|
|
|
|
|
ImGui::Text("%s", ptr.back().c_str());
|
|
|
|
|
ImGui::TableSetColumnIndex(1);
|
|
|
|
|
|
|
|
|
|
float val = j[ptr].get<float>();
|
|
|
|
|
if (ImGui::InputFloat("##value", &val, 0.001f, 0.01f)) {
|
|
|
|
|
j[ptr] = val;
|
|
|
|
|
StaticGeometryModule::setItemProperties(entity,
|
|
|
|
|
j.dump());
|
|
|
|
|
StaticGeometryModule::updateItemGeometry(entity);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
FloatPropertyEditor()
|
|
|
|
|
: DPropertyEditor(EditFloat, "Float Editor")
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
~FloatPropertyEditor() override
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
// int editor
|
|
|
|
|
struct IntPropertyEditor : DPropertyEditor {
|
|
|
|
|
bool _matches(const std::string &itemName,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
const nlohmann::json &j) override
|
|
|
|
|
{
|
|
|
|
|
return j[ptr].is_number_integer();
|
|
|
|
|
}
|
|
|
|
|
void _render(flecs::entity entity,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
nlohmann::json &j) override
|
|
|
|
|
{
|
|
|
|
|
ImGui::TableSetColumnIndex(0);
|
|
|
|
|
ImGui::Text("%s", ptr.back().c_str());
|
|
|
|
|
ImGui::TableSetColumnIndex(1);
|
|
|
|
|
|
|
|
|
|
int val = j[ptr].get<int>();
|
|
|
|
|
if (ImGui::InputInt("##value", &val, 1, 10)) {
|
|
|
|
|
j[ptr] = val;
|
|
|
|
|
StaticGeometryModule::setItemProperties(entity,
|
|
|
|
|
j.dump());
|
|
|
|
|
StaticGeometryModule::updateItemGeometry(entity);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
IntPropertyEditor()
|
|
|
|
|
: DPropertyEditor(EditInt, "Int Editor")
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
~IntPropertyEditor() override
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
// bool editor
|
|
|
|
|
struct BoolPropertyEditor : DPropertyEditor {
|
|
|
|
|
bool _matches(const std::string &itemName,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
const nlohmann::json &j) override
|
|
|
|
|
{
|
|
|
|
|
return j[ptr].is_boolean();
|
|
|
|
|
}
|
|
|
|
|
void _render(flecs::entity entity,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
nlohmann::json &j) override
|
|
|
|
|
{
|
|
|
|
|
ImGui::TableSetColumnIndex(0);
|
|
|
|
|
ImGui::Text("%s", ptr.back().c_str());
|
|
|
|
|
ImGui::TableSetColumnIndex(1);
|
|
|
|
|
|
|
|
|
|
bool val = j[ptr].get<bool>();
|
|
|
|
|
if (ImGui::Checkbox("##value", &val)) {
|
|
|
|
|
j[ptr] = val;
|
|
|
|
|
StaticGeometryModule::setItemProperties(entity,
|
|
|
|
|
j.dump());
|
|
|
|
|
StaticGeometryModule::updateItemGeometry(entity);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
BoolPropertyEditor()
|
|
|
|
|
: DPropertyEditor(EditBool, "Bool Editor")
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
~BoolPropertyEditor() override
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
// color rect editor
|
|
|
|
|
struct ColorRectPropertyEditor : DPropertyEditor {
|
|
|
|
|
bool _matches(const std::string &itemName,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
const nlohmann::json &j) override
|
|
|
|
|
{
|
|
|
|
|
if (ptr.empty())
|
|
|
|
|
return false;
|
|
|
|
|
if (!ptr.parent_pointer().empty() &&
|
|
|
|
|
ptr.parent_pointer().back() == "colorRects") {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
void _render(flecs::entity entity,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
nlohmann::json &j) override
|
|
|
|
|
{
|
|
|
|
|
bool updateMaterial = false;
|
|
|
|
|
|
|
|
|
|
ImGui::TableSetColumnIndex(1);
|
|
|
|
|
drawRectPreview(ptr, j);
|
|
|
|
|
|
|
|
|
|
ImGui::TableNextRow();
|
|
|
|
|
ImGui::TableSetColumnIndex(0);
|
|
|
|
|
ImGui::Text("Bounds");
|
|
|
|
|
ImGui::TableSetColumnIndex(1);
|
|
|
|
|
|
|
|
|
|
nlohmann::json &d = j[ptr];
|
|
|
|
|
nlohmann::json &c = j[ptr]["color"];
|
|
|
|
|
|
|
|
|
|
float bounds[2] = { d["left"], d["top"] };
|
|
|
|
|
if (ImGui::InputFloat("Left", &bounds[0], 0.1f, 0.1f, "%.1f")) {
|
|
|
|
|
d["left"] = std::clamp(std::round(bounds[0] * 10.0f) /
|
|
|
|
|
10.0f,
|
|
|
|
|
0.0f, 1.0f);
|
|
|
|
|
d["right"] = std::clamp(
|
|
|
|
|
std::round((bounds[0] + 0.1f) * 10.0f) / 10.0f,
|
|
|
|
|
0.0f, 1.0f);
|
|
|
|
|
updateMaterial = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ImGui::InputFloat("Top", &bounds[1], 0.1f, 0.1f, "%.1f")) {
|
|
|
|
|
d["top"] = std::clamp(std::round(bounds[1] * 10.0f) /
|
|
|
|
|
10.0f,
|
|
|
|
|
0.0f, 1.0f);
|
|
|
|
|
d["bottom"] = std::clamp(
|
|
|
|
|
std::round((bounds[1] + 0.1f) * 10.0f) / 10.0f,
|
|
|
|
|
0.0f, 1.0f);
|
|
|
|
|
updateMaterial = true;
|
|
|
|
|
}
|
|
|
|
|
ImVec2 value;
|
|
|
|
|
value.x = bounds[0];
|
|
|
|
|
value.y = bounds[1];
|
|
|
|
|
if (DrawGridSelectorInTableCell("##selectRect", value)) {
|
|
|
|
|
bounds[0] = value.x;
|
|
|
|
|
bounds[1] = value.y;
|
|
|
|
|
d["left"] = std::clamp(std::round(bounds[0] * 10.0f) /
|
|
|
|
|
10.0f,
|
|
|
|
|
0.0f, 1.0f);
|
|
|
|
|
d["right"] = std::clamp(
|
|
|
|
|
std::round((bounds[0] + 0.1f) * 10.0f) / 10.0f,
|
|
|
|
|
0.0f, 1.0f);
|
|
|
|
|
d["top"] = std::clamp(std::round(bounds[1] * 10.0f) /
|
|
|
|
|
10.0f,
|
|
|
|
|
0.0f, 1.0f);
|
|
|
|
|
d["bottom"] = std::clamp(
|
|
|
|
|
std::round((bounds[1] + 0.1f) * 10.0f) / 10.0f,
|
|
|
|
|
0.0f, 1.0f);
|
|
|
|
|
updateMaterial = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ImGui::TableNextRow();
|
|
|
|
|
ImGui::TableSetColumnIndex(0);
|
|
|
|
|
ImGui::Text("Color");
|
|
|
|
|
ImGui::TableSetColumnIndex(1);
|
|
|
|
|
|
|
|
|
|
float col[4] = { c["r"], c["g"], c["b"], c["a"] };
|
|
|
|
|
if (ImGui::ColorEdit4("##color", col)) {
|
|
|
|
|
c["r"] = col[0];
|
|
|
|
|
c["g"] = col[1];
|
|
|
|
|
c["b"] = col[2];
|
|
|
|
|
c["a"] = col[3];
|
|
|
|
|
updateMaterial = true;
|
|
|
|
|
}
|
|
|
|
|
if (updateMaterial) {
|
|
|
|
|
StaticGeometryModule::setItemProperties(entity,
|
|
|
|
|
j.dump());
|
|
|
|
|
Geometry::createTownMaterial(entity, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ColorRectPropertyEditor()
|
|
|
|
|
: DPropertyEditor(EditColorRect, "Color Rect Editor")
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
~ColorRectPropertyEditor() override
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
template <typename T> struct registerPropertyEditor {
|
|
|
|
|
registerPropertyEditor(std::vector<PropertyEditor> ®)
|
|
|
|
|
{
|
|
|
|
|
static T regdata;
|
|
|
|
|
reg.push_back(regdata);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
static std::vector<PropertyEditor> propertyEditors;
|
|
|
|
|
// ViewJson editor (fallback)
|
|
|
|
|
struct FallbackPropertyEditor : DPropertyEditor {
|
|
|
|
|
bool _matches(const std::string &itemName,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
const nlohmann::json &j) override
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
void _render(flecs::entity entity,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
nlohmann::json &j) override
|
|
|
|
|
{
|
|
|
|
|
ImGui::TableSetColumnIndex(1);
|
|
|
|
|
ImGui::TextWrapped("%s", j[ptr].dump(4).c_str());
|
|
|
|
|
}
|
|
|
|
|
FallbackPropertyEditor()
|
|
|
|
|
: DPropertyEditor(ViewJson, "JSON Viewer")
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
static registerPropertyEditor<StringPropertyEditor>
|
|
|
|
|
stringPropertyEditor(propertyEditors);
|
|
|
|
|
static registerPropertyEditor<LuaScriptPropertyEditor>
|
|
|
|
|
luaScriptPropertyEditor(propertyEditors);
|
|
|
|
|
static registerPropertyEditor<MultilineStringPropertyEditor>
|
|
|
|
|
multilineStringPropertyEditor(propertyEditors);
|
|
|
|
|
static registerPropertyEditor<FloatPropertyEditor>
|
|
|
|
|
floatPropertyEditor(propertyEditors);
|
|
|
|
|
static registerPropertyEditor<IntPropertyEditor>
|
|
|
|
|
intPropertyEditor(propertyEditors);
|
|
|
|
|
static registerPropertyEditor<BoolPropertyEditor>
|
|
|
|
|
boolPropertyEditor(propertyEditors);
|
|
|
|
|
static registerPropertyEditor<ColorRectPropertyEditor>
|
|
|
|
|
colorRectPropertyEditor(propertyEditors);
|
|
|
|
|
static registerPropertyEditor<FallbackPropertyEditor>
|
|
|
|
|
fallbackPropertyEditor(propertyEditors);
|
|
|
|
|
void itemsEditor()
|
|
|
|
|
{
|
|
|
|
|
struct EditorState {
|
|
|
|
|
flecs::entity edited;
|
|
|
|
|
nlohmann::json::json_pointer edited_ptr;
|
|
|
|
|
int edited_type;
|
|
|
|
|
EditorState()
|
|
|
|
|
: edited_type(EditNone)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
void clear()
|
|
|
|
|
{
|
|
|
|
|
edited = flecs::entity();
|
|
|
|
|
edited_ptr = nlohmann::json::json_pointer();
|
|
|
|
|
edited_type = EditNone;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
static EditorState state;
|
|
|
|
|
// Helper to find matching editor
|
|
|
|
|
auto findEditor = [](int editType, const std::string &itemName,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
const nlohmann::json &j) -> PropertyEditor * {
|
|
|
|
|
for (auto &editor : propertyEditors) {
|
|
|
|
|
if (editor.editType == editType &&
|
|
|
|
|
editor.matches(itemName, ptr, j)) {
|
|
|
|
|
return &editor;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
};
|
|
|
|
|
// Leaf node detection - keeping your working logic
|
|
|
|
|
auto is_leaf = [](const std::string &itemName,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr) -> bool {
|
|
|
|
|
// Direct key matches
|
|
|
|
|
if (itemName == "name" || itemName == "position" ||
|
|
|
|
|
itemName == "orientation" || itemName == "rotation" ||
|
|
|
|
|
itemName == "cells" || itemName == "furniture_cells" ||
|
|
|
|
|
itemName == "roofs" || itemName == "pierPath" ||
|
|
|
|
|
itemName == "cellScript") {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Parent-based matches
|
|
|
|
|
if (!ptr.empty() && !ptr.parent_pointer().empty()) {
|
|
|
|
|
std::string parent = ptr.parent_pointer().back();
|
|
|
|
|
if (parent == "colorRects" || parent == "npcs" ||
|
|
|
|
|
parent == "centerBuildings") {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
// Edit type determination
|
|
|
|
|
auto set_edit_type = [&findEditor](
|
|
|
|
|
const std::string &itemName,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
const nlohmann::json &j) {
|
|
|
|
|
// Try to find by specific rules first
|
|
|
|
|
if (itemName == "name") {
|
|
|
|
|
state.edited_type = EditString;
|
|
|
|
|
} else if (itemName == "position" ||
|
|
|
|
|
itemName == "orientation" ||
|
|
|
|
|
itemName == "rotation" || itemName == "cells" ||
|
|
|
|
|
itemName == "furniture_cells" ||
|
|
|
|
|
itemName == "roofs" || itemName == "pierPath") {
|
|
|
|
|
state.edited_type = ViewJson;
|
|
|
|
|
} else if (itemName == "cellScript") {
|
|
|
|
|
state.edited_type = EditMultilineString;
|
|
|
|
|
} else if (!ptr.empty() && !ptr.parent_pointer().empty()) {
|
|
|
|
|
std::string parent = ptr.parent_pointer().back();
|
|
|
|
|
if (parent == "colorRects") {
|
|
|
|
|
state.edited_type = EditColorRect;
|
|
|
|
|
} else if (parent == "npcs" ||
|
|
|
|
|
parent == "centerBuildings") {
|
|
|
|
|
state.edited_type = ViewJson;
|
|
|
|
|
} else {
|
|
|
|
|
// Fall back to type-based detection
|
|
|
|
|
if (j[ptr].is_number_float())
|
|
|
|
|
state.edited_type = EditFloat;
|
|
|
|
|
else if (j[ptr].is_number_integer())
|
|
|
|
|
state.edited_type = EditInt;
|
|
|
|
|
else if (j[ptr].is_boolean())
|
|
|
|
|
state.edited_type = EditBool;
|
|
|
|
|
else if (j[ptr].is_string())
|
|
|
|
|
state.edited_type = EditString;
|
|
|
|
|
else
|
|
|
|
|
state.edited_type = ViewJson;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Fall back to type-based detection
|
|
|
|
|
if (j[ptr].is_number_float())
|
|
|
|
|
state.edited_type = EditFloat;
|
|
|
|
|
else if (j[ptr].is_number_integer())
|
|
|
|
|
state.edited_type = EditInt;
|
|
|
|
|
else if (j[ptr].is_boolean())
|
|
|
|
|
state.edited_type = EditBool;
|
|
|
|
|
else if (j[ptr].is_string())
|
|
|
|
|
state.edited_type = EditString;
|
|
|
|
|
else
|
|
|
|
|
state.edited_type = ViewJson;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
// Recursive hierarchy renderer
|
|
|
|
|
std::function<void(
|
|
|
|
|
const Ogre::String &, flecs::entity, ImGuiTreeNodeFlags,
|
|
|
|
|
const nlohmann::json::json_pointer &, nlohmann::json &)>
|
|
|
|
|
renderHierarchy;
|
|
|
|
|
|
|
|
|
|
renderHierarchy = [&renderHierarchy, &is_leaf, &set_edit_type](
|
|
|
|
|
const Ogre::String &label, flecs::entity item,
|
|
|
|
|
ImGuiTreeNodeFlags flags,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
nlohmann::json &j) {
|
|
|
|
|
// Generate a unique ID for this node
|
|
|
|
|
ImGui::PushID(
|
|
|
|
|
static_cast<int>(reinterpret_cast<intptr_t>(&j[ptr])));
|
|
|
|
|
|
|
|
|
|
// Set flags
|
|
|
|
|
ImGuiTreeNodeFlags nodeFlags = flags;
|
|
|
|
|
if (state.edited == item && state.edited_ptr == ptr)
|
|
|
|
|
nodeFlags |= ImGuiTreeNodeFlags_Selected;
|
|
|
|
|
|
|
|
|
|
// Render the node
|
|
|
|
|
std::string displayLabel = label;
|
|
|
|
|
if (!ptr.empty() && j[ptr].is_string() &&
|
|
|
|
|
ptr.back() == "name") {
|
|
|
|
|
// Optionally show value for name fields
|
|
|
|
|
displayLabel += ": " + j[ptr].get<std::string>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool nodeOpen = ImGui::TreeNodeEx((void *)&j[ptr], nodeFlags,
|
|
|
|
|
"%s", displayLabel.c_str());
|
|
|
|
|
|
|
|
|
|
// Handle click
|
|
|
|
|
if (ImGui::IsItemClicked()) {
|
|
|
|
|
state.edited = item;
|
|
|
|
|
state.edited_ptr = ptr;
|
|
|
|
|
std::string itemName = ptr.empty() ? "" : ptr.back();
|
|
|
|
|
set_edit_type(itemName, ptr, j);
|
|
|
|
|
std::cout << ptr << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Render children
|
|
|
|
|
if (nodeOpen) {
|
|
|
|
|
std::string itemName = ptr.empty() ? "" : ptr.back();
|
|
|
|
|
bool leaf = is_leaf(itemName, ptr);
|
|
|
|
|
|
|
|
|
|
if (!leaf) {
|
|
|
|
|
if (j[ptr].is_array()) {
|
|
|
|
|
for (size_t i = 0; i < j[ptr].size();
|
|
|
|
|
++i) {
|
|
|
|
|
auto nptr = ptr / i;
|
|
|
|
|
renderHierarchy(
|
|
|
|
|
std::to_string(i), item,
|
|
|
|
|
flags, nptr, j);
|
|
|
|
|
}
|
|
|
|
|
} else if (j[ptr].is_object()) {
|
|
|
|
|
nlohmann::json &obj = j[ptr];
|
|
|
|
|
for (auto it = obj.begin();
|
|
|
|
|
it != obj.end(); ++it) {
|
|
|
|
|
auto nptr = ptr / it.key();
|
|
|
|
|
renderHierarchy(it.key(), item,
|
|
|
|
|
flags, nptr, j);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ImGui::TreePop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ImGui::PopID();
|
|
|
|
|
};
|
|
|
|
|
// Property editor rendering using registry
|
|
|
|
|
auto renderPropertyEditor =
|
|
|
|
|
[&findEditor](flecs::entity entity,
|
|
|
|
|
const nlohmann::json::json_pointer &ptr,
|
|
|
|
|
int editType) {
|
|
|
|
|
Ogre::String jsonStr =
|
|
|
|
|
StaticGeometryModule::getItemProperties(entity);
|
|
|
|
|
nlohmann::json j = nlohmann::json::parse(jsonStr);
|
|
|
|
|
|
|
|
|
|
std::string itemName = ptr.empty() ? "" : ptr.back();
|
|
|
|
|
PropertyEditor *editor =
|
|
|
|
|
findEditor(editType, itemName, ptr, j);
|
|
|
|
|
|
|
|
|
|
if (editor) {
|
|
|
|
|
editor->render(entity, ptr, j);
|
|
|
|
|
} else {
|
|
|
|
|
// Fallback
|
|
|
|
|
ImGui::TableSetColumnIndex(1);
|
|
|
|
|
ImGui::TextWrapped("%s",
|
|
|
|
|
j[ptr].dump(4).c_str());
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
if (ImGui::SmallButton("Edit items..."))
|
|
|
|
|
ImGui::OpenPopup("Edit Items Popup");
|
|
|
|
|
if (ImGui::BeginPopupModal("Edit Items Popup", NULL,
|
|
|
|
|
ImGuiWindowFlags_MenuBar)) {
|
|
|
|
|
// Optional: Add a menu bar for "Add District/Lot" actions
|
|
|
|
|
if (ImGui::BeginMenuBar()) {
|
|
|
|
|
if (ImGui::BeginMenu("File")) { /* ... */
|
|
|
|
|
ImGui::EndMenu();
|
|
|
|
|
}
|
|
|
|
|
ImGui::EndMenuBar();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- LEFT SIDE: HIERARCHY ---
|
|
|
|
|
ImGui::BeginChild("HierarchyRegion", ImVec2(300, 400), true);
|
|
|
|
|
std::list<std::pair<flecs::entity, Ogre::String> > items;
|
|
|
|
|
StaticGeometryModule::getItemsProperties(&items);
|
|
|
|
|
ImGuiTreeNodeFlags baseFlags =
|
|
|
|
|
ImGuiTreeNodeFlags_OpenOnArrow |
|
|
|
|
|
ImGuiTreeNodeFlags_SpanAvailWidth |
|
|
|
|
|
ImGuiTreeNodeFlags_DefaultOpen;
|
|
|
|
|
for (const auto &itemPair : items) {
|
|
|
|
|
flecs::entity entity = itemPair.first;
|
|
|
|
|
const Ogre::String &jsonStr = itemPair.second;
|
|
|
|
|
|
|
|
|
|
ImGui::PushID(static_cast<int>(entity.id()));
|
|
|
|
|
|
|
|
|
|
nlohmann::json j = nlohmann::json::parse(jsonStr);
|
|
|
|
|
|
|
|
|
|
// Create label
|
|
|
|
|
Ogre::String label =
|
|
|
|
|
Ogre::StringConverter::toString(entity.id());
|
|
|
|
|
label += ":" + j["type"].get<Ogre::String>();
|
|
|
|
|
if (j.find("name") != j.end() &&
|
|
|
|
|
!j["name"].get<Ogre::String>().empty())
|
|
|
|
|
label = j["name"].get<Ogre::String>();
|
|
|
|
|
|
|
|
|
|
// Render hierarchy for this item
|
|
|
|
|
renderHierarchy(label, entity, baseFlags,
|
|
|
|
|
nlohmann::json::json_pointer(), j);
|
|
|
|
|
|
|
|
|
|
ImGui::PopID();
|
|
|
|
|
}
|
|
|
|
|
ImGui::EndChild();
|
|
|
|
|
|
|
|
|
|
ImGui::SameLine();
|
|
|
|
|
|
|
|
|
|
// --- RIGHT SIDE: PROPERTIES ---
|
|
|
|
|
ImGui::BeginChild("PropertiesRegion", ImVec2(0, 400), true);
|
|
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding,
|
|
|
|
|
ImVec2(10.0f, 4.0f));
|
|
|
|
|
if (ImGui::BeginTable("PropTable", 2,
|
|
|
|
|
ImGuiTableFlags_SizingStretchProp |
|
|
|
|
|
ImGuiTableFlags_Resizable)) {
|
|
|
|
|
ImGui::TableSetupColumn(
|
|
|
|
|
"Property", ImGuiTableColumnFlags_WidthFixed,
|
|
|
|
|
0.0f);
|
|
|
|
|
ImGui::TableSetupColumn(
|
|
|
|
|
"Value", ImGuiTableColumnFlags_WidthStretch);
|
|
|
|
|
ImGui::TableHeadersRow();
|
|
|
|
|
ImGui::TableNextRow();
|
|
|
|
|
if (state.edited.is_valid() &&
|
|
|
|
|
!state.edited_ptr.empty()) {
|
|
|
|
|
renderPropertyEditor(state.edited,
|
|
|
|
|
state.edited_ptr,
|
|
|
|
|
state.edited_type);
|
|
|
|
|
} else if (state.edited.is_valid()) {
|
|
|
|
|
// Show item summary when no specific property is selected
|
|
|
|
|
ImGui::TableSetColumnIndex(0);
|
|
|
|
|
ImGui::Text("Item");
|
|
|
|
|
ImGui::TableSetColumnIndex(1);
|
|
|
|
|
Ogre::String jsonStr =
|
|
|
|
|
StaticGeometryModule::getItemProperties(
|
|
|
|
|
state.edited);
|
|
|
|
|
nlohmann::json j =
|
|
|
|
|
nlohmann::json::parse(jsonStr);
|
|
|
|
|
ImGui::TextWrapped("%s", j.dump(4).c_str());
|
|
|
|
|
}
|
|
|
|
|
ImGui::EndTable();
|
|
|
|
|
}
|
|
|
|
|
ImGui::PopStyleVar();
|
|
|
|
|
// DrawPropertyInspector(); // Uses the Table logic from before
|
|
|
|
|
ImGui::EndChild();
|
|
|
|
|
|
|
|
|
|
if (ImGui::Button("Close")) {
|
|
|
|
|
ImGui::CloseCurrentPopup();
|
|
|
|
|
state.clear();
|
|
|
|
|
}
|
|
|
|
|
ImGui::EndPopup();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
namespace Geometry
|
|
|
|
|
{
|
|
|
|
|
|