mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-17 23:39:18 +02:00
677 lines
23 KiB
C++
677 lines
23 KiB
C++
/*
|
|
This Source Code Form is subject to the
|
|
terms of the Mozilla Public License, v.
|
|
2.0. If a copy of the MPL was not
|
|
distributed with this file, You can
|
|
obtain one at
|
|
http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "application/driveruilayer.h"
|
|
|
|
#include "utilities/Globals.h"
|
|
#include "utilities/utilities.h"
|
|
#include "application/application.h"
|
|
#include "utilities/translation.h"
|
|
#include "simulation/simulation.h"
|
|
#include "vehicle/Train.h"
|
|
#include "model/AnimModel.h"
|
|
#include "rendering/renderer.h"
|
|
#include "DevConsole/devconsole.h"
|
|
#include "entitysystem/ECScene.h"
|
|
#include "entitysystem/components/BasicComponents.h"
|
|
#include "entitysystem/components/RenderComponents.h"
|
|
#include "entitysystem/ECSPersistence.h"
|
|
|
|
driver_ui::driver_ui()
|
|
{
|
|
|
|
clear_panels();
|
|
// bind the panels with ui object. maybe not the best place for this but, eh
|
|
add_external_panel(&m_aidpanel);
|
|
add_external_panel(&m_scenariopanel);
|
|
add_external_panel(&m_timetablepanel);
|
|
add_external_panel(&m_debugpanel);
|
|
if (Global.gui_showtranscripts)
|
|
add_external_panel(&m_transcriptspanel);
|
|
|
|
add_external_panel(&m_trainingcardpanel);
|
|
add_external_panel(&m_vehiclelist);
|
|
add_external_panel(&m_timepanel);
|
|
add_external_panel(&m_mappanel);
|
|
add_external_panel(&m_logpanel);
|
|
add_external_panel(&m_perfgraphpanel);
|
|
add_external_panel(&dev::Console);
|
|
add_external_panel(&m_cameraviewpanel);
|
|
m_logpanel.is_open = false;
|
|
|
|
m_aidpanel.title = STR("Driving Aid");
|
|
|
|
m_scenariopanel.title = STR("Scenario");
|
|
m_scenariopanel.size_min = {435, 85};
|
|
m_scenariopanel.size_max = {Global.fb_size.x * 0.95f, Global.fb_size.y * 0.95};
|
|
|
|
m_timetablepanel.title = STR("%-*.*s Time: %d:%02d:%02d");
|
|
m_timetablepanel.size_min = {435, 70};
|
|
m_timetablepanel.size_max = {435, Global.fb_size.y * 0.95};
|
|
|
|
m_transcriptspanel.title = STR("Transcripts");
|
|
m_transcriptspanel.size_min = {435, 85};
|
|
m_transcriptspanel.size_max = {Global.fb_size.x * 0.95, Global.fb_size.y * 0.95};
|
|
|
|
if (Global.gui_defaultwindows)
|
|
{
|
|
m_aidpanel.is_open = true;
|
|
m_scenariopanel.is_open = true;
|
|
}
|
|
|
|
if (Global.gui_trainingdefault)
|
|
{
|
|
m_mappanel.is_open = true;
|
|
m_trainingcardpanel.is_open = true;
|
|
m_vehiclelist.is_open = true;
|
|
}
|
|
|
|
register_driver_commands();
|
|
}
|
|
|
|
void driver_ui::register_driver_commands()
|
|
{
|
|
auto &con = dev::Console;
|
|
|
|
// --- UI toggles ---
|
|
con.register_command("debug", "Toggle debug panel",
|
|
[this](const dev::args_t &) {
|
|
m_debugpanel.is_open = !m_debugpanel.is_open;
|
|
dev::Console.print_ok(m_debugpanel.is_open ? "Debug panel opened" : "Debug panel closed");
|
|
});
|
|
|
|
con.register_command("map", "Toggle map panel",
|
|
[this](const dev::args_t &) {
|
|
m_mappanel.is_open = !m_mappanel.is_open;
|
|
});
|
|
|
|
con.register_command("aid", "Toggle driving-aid panel",
|
|
[this](const dev::args_t &) {
|
|
m_aidpanel.is_open = !m_aidpanel.is_open;
|
|
});
|
|
|
|
con.register_command("timetable", "Toggle timetable panel",
|
|
[this](const dev::args_t &) {
|
|
m_timetablepanel.is_open = !m_timetablepanel.is_open;
|
|
});
|
|
|
|
// --- Simulation control ---
|
|
con.register_command("pause", "Pause or unpause simulation",
|
|
[](const dev::args_t &) {
|
|
command_relay relay;
|
|
relay.post(user_command::pausetoggle, 0.0, 0.0, GLFW_PRESS, 0);
|
|
});
|
|
|
|
con.register_command("debugmode", "Toggle debug mode (enable/disable)",
|
|
[](const dev::args_t &args) {
|
|
command_relay relay;
|
|
relay.post(user_command::debugtoggle, 0.0, 0.0, GLFW_RELEASE, 0);
|
|
dev::Console.print_ok(std::string("Debug mode: ") + (DebugModeFlag ? "on" : "off"));
|
|
});
|
|
|
|
// --- Weather ---
|
|
con.register_command("overcast", "Set overcast level: overcast <0.0-1.0>",
|
|
[](const dev::args_t &args) {
|
|
if (args.size() < 2) {
|
|
dev::Console.print_info("Current overcast: " + std::to_string(Global.Overcast));
|
|
return;
|
|
}
|
|
try {
|
|
float v = std::stof(args[1]);
|
|
v = std::max(0.0f, std::min(1.0f, v));
|
|
Global.Overcast = v;
|
|
dev::Console.print_ok("Overcast set to " + std::to_string(v));
|
|
} catch (...) {
|
|
dev::Console.print_error("Expected a float 0.0-1.0");
|
|
}
|
|
});
|
|
|
|
// --- Screenshot ---
|
|
con.register_command("screenshot", "Take a screenshot",
|
|
[](const dev::args_t &) {
|
|
Application.queue_screenshot();
|
|
dev::Console.print_ok("Screenshot queued");
|
|
});
|
|
|
|
// --- Log ---
|
|
con.register_command("log", "Enable or disable file logging: log [on|off]",
|
|
[](const dev::args_t &args) {
|
|
if (args.size() < 2) {
|
|
dev::Console.print_info(std::string("File logging: ") +
|
|
((Global.iWriteLogEnabled & 1) ? "on" : "off"));
|
|
return;
|
|
}
|
|
if (args[1] == "on") {
|
|
Global.iWriteLogEnabled |= 1;
|
|
dev::Console.print_ok("File logging enabled");
|
|
} else if (args[1] == "off") {
|
|
Global.iWriteLogEnabled &= ~1;
|
|
dev::Console.print_ok("File logging disabled");
|
|
} else {
|
|
dev::Console.print_error("Usage: log [on|off]");
|
|
}
|
|
});
|
|
|
|
// --- ECS ---
|
|
con.register_command("ecs.list", "List all ECS entities (optional filter: ecs.list [name_fragment])",
|
|
[](const dev::args_t &args) {
|
|
ECScene *scene = Application.sceneManager.CurrentScene();
|
|
if (!scene) { dev::Console.print_warn("No active scene"); return; }
|
|
ECWorld &world = scene->World();
|
|
|
|
std::string filter = args.size() >= 2 ? args[1] : "";
|
|
int count = 0;
|
|
for (auto entity : world.GetEntities()) {
|
|
std::string name = std::to_string(static_cast<unsigned>(entity));
|
|
if (auto *id = world.GetComponent<ECSComponent::Identification>(entity))
|
|
name = id->Name.ToString();
|
|
if (!filter.empty() && name.find(filter) == std::string::npos)
|
|
continue;
|
|
dev::Console.print(" [" + std::to_string(static_cast<unsigned>(entity)) + "] " + name);
|
|
++count;
|
|
}
|
|
dev::Console.print_info("Total: " + std::to_string(count) + " entities");
|
|
});
|
|
|
|
con.register_command("ecs.info", "Show components of entity by name: ecs.info <name>",
|
|
[](const dev::args_t &args) {
|
|
if (args.size() < 2) { dev::Console.print_error("Usage: ecs.info <name>"); return; }
|
|
ECScene *scene = Application.sceneManager.CurrentScene();
|
|
if (!scene) { dev::Console.print_warn("No active scene"); return; }
|
|
ECWorld &world = scene->World();
|
|
|
|
entt::entity entity = world.FindEntityByName(args[1]);
|
|
if (entity == entt::null) { dev::Console.print_error("Entity not found: " + args[1]); return; }
|
|
|
|
dev::Console.print_ok("Entity: " + args[1]);
|
|
if (auto *t = world.GetComponent<ECSComponent::Transform>(entity)) {
|
|
dev::Console.print(" Transform: pos=("
|
|
+ std::to_string(t->Position.x) + ", "
|
|
+ std::to_string(t->Position.y) + ", "
|
|
+ std::to_string(t->Position.z) + ")");
|
|
}
|
|
if (auto *v = world.GetComponent<ECSComponent::Velocity>(entity)) {
|
|
dev::Console.print(" Velocity: ("
|
|
+ std::to_string(v->Value.x) + ", "
|
|
+ std::to_string(v->Value.y) + ", "
|
|
+ std::to_string(v->Value.z) + ")");
|
|
}
|
|
if (world.HasComponent<ECSComponent::MeshRenderer>(entity))
|
|
dev::Console.print(" MeshRenderer: yes");
|
|
if (world.HasComponent<ECSComponent::ParticleEmitter>(entity))
|
|
dev::Console.print(" ParticleEmitter: yes");
|
|
if (auto *id = world.GetComponent<ECSComponent::Identification>(entity))
|
|
dev::Console.print(" ID: " + id->Name.ToString() + " #" + std::to_string(id->Id));
|
|
});
|
|
|
|
con.register_command("ecs.setvel", "Set entity velocity: ecs.setvel <name> <x> <y> <z>",
|
|
[](const dev::args_t &args) {
|
|
if (args.size() < 5) { dev::Console.print_error("Usage: ecs.setvel <name> <x> <y> <z>"); return; }
|
|
ECScene *scene = Application.sceneManager.CurrentScene();
|
|
if (!scene) { dev::Console.print_warn("No active scene"); return; }
|
|
ECWorld &world = scene->World();
|
|
|
|
entt::entity entity = world.FindEntityByName(args[1]);
|
|
if (entity == entt::null) { dev::Console.print_error("Entity not found: " + args[1]); return; }
|
|
|
|
try {
|
|
glm::vec3 vel{ std::stof(args[2]), std::stof(args[3]), std::stof(args[4]) };
|
|
if (auto *v = world.GetComponent<ECSComponent::Velocity>(entity)) {
|
|
v->Value = vel;
|
|
dev::Console.print_ok("Velocity set");
|
|
} else {
|
|
world.AddComponent<ECSComponent::Velocity>(entity).Value = vel;
|
|
dev::Console.print_ok("Velocity component added and set");
|
|
}
|
|
} catch (...) { dev::Console.print_error("Invalid numbers"); }
|
|
});
|
|
|
|
con.register_command("ecs.kill", "Destroy entity by name: ecs.kill <name>",
|
|
[](const dev::args_t &args) {
|
|
if (args.size() < 2) { dev::Console.print_error("Usage: ecs.kill <name>"); return; }
|
|
ECScene *scene = Application.sceneManager.CurrentScene();
|
|
if (!scene) { dev::Console.print_warn("No active scene"); return; }
|
|
ECWorld &world = scene->World();
|
|
|
|
entt::entity entity = world.FindEntityByName(args[1]);
|
|
if (entity == entt::null) { dev::Console.print_error("Entity not found: " + args[1]); return; }
|
|
world.DestroyEntity(entity);
|
|
dev::Console.print_ok("Entity destroyed: " + args[1]);
|
|
});
|
|
|
|
con.register_command("ecs.count", "Show total entity count in current scene",
|
|
[](const dev::args_t &) {
|
|
ECScene *scene = Application.sceneManager.CurrentScene();
|
|
if (!scene) { dev::Console.print_warn("No active scene"); return; }
|
|
dev::Console.print_info("Entities: " + std::to_string(scene->World().GetEntityCount()));
|
|
});
|
|
|
|
con.register_command("ecs.setpos", "Teleport entity to position: ecs.setpos <name> <x> <y> <z>",
|
|
[](const dev::args_t &args) {
|
|
if (args.size() < 5) { dev::Console.print_error("Usage: ecs.setpos <name> <x> <y> <z>"); return; }
|
|
ECScene *scene = Application.sceneManager.CurrentScene();
|
|
if (!scene) { dev::Console.print_warn("No active scene"); return; }
|
|
ECWorld &world = scene->World();
|
|
|
|
entt::entity entity = world.FindEntityByName(args[1]);
|
|
if (entity == entt::null) { dev::Console.print_error("Entity not found: " + args[1]); return; }
|
|
|
|
try {
|
|
glm::dvec3 pos{ std::stod(args[2]), std::stod(args[3]), std::stod(args[4]) };
|
|
if (auto *t = world.GetComponent<ECSComponent::Transform>(entity)) {
|
|
t->Position = pos;
|
|
dev::Console.print_ok("Position set: ("
|
|
+ args[2] + ", " + args[3] + ", " + args[4] + ")");
|
|
} else {
|
|
dev::Console.print_error("Entity has no Transform component");
|
|
}
|
|
} catch (...) { dev::Console.print_error("Invalid numbers"); }
|
|
});
|
|
|
|
con.register_command("ecs.spawn", "Spawn a named entity with Transform at position: ecs.spawn <name> <x> <y> <z>",
|
|
[](const dev::args_t &args) {
|
|
if (args.size() < 5) { dev::Console.print_error("Usage: ecs.spawn <name> <x> <y> <z>"); return; }
|
|
ECScene *scene = Application.sceneManager.CurrentScene();
|
|
if (!scene) { dev::Console.print_warn("No active scene"); return; }
|
|
ECWorld &world = scene->World();
|
|
|
|
try {
|
|
glm::dvec3 pos{ std::stod(args[2]), std::stod(args[3]), std::stod(args[4]) };
|
|
auto entity = world.CreateEntity();
|
|
auto &id = world.AddComponent<ECSComponent::Identification>(entity);
|
|
id.Name = args[1];
|
|
auto &t = world.AddComponent<ECSComponent::Transform>(entity);
|
|
t.Position = pos;
|
|
dev::Console.print_ok("Spawned entity '" + args[1] + "' at ("
|
|
+ args[2] + ", " + args[3] + ", " + args[4] + ")");
|
|
} catch (...) { dev::Console.print_error("Invalid position arguments"); }
|
|
});
|
|
|
|
con.register_command("ecs.find", "Find entities whose name contains a substring: ecs.find <fragment>",
|
|
[](const dev::args_t &args) {
|
|
if (args.size() < 2) { dev::Console.print_error("Usage: ecs.find <fragment>"); return; }
|
|
ECScene *scene = Application.sceneManager.CurrentScene();
|
|
if (!scene) { dev::Console.print_warn("No active scene"); return; }
|
|
ECWorld &world = scene->World();
|
|
|
|
const std::string &fragment = args[1];
|
|
int found = 0;
|
|
for (auto entity : world.GetEntities()) {
|
|
auto *id = world.GetComponent<ECSComponent::Identification>(entity);
|
|
if (!id) continue;
|
|
std::string name = id->Name.ToString();
|
|
if (name.find(fragment) != std::string::npos) {
|
|
dev::Console.print(" [" + std::to_string(static_cast<unsigned>(entity)) + "] " + name);
|
|
++found;
|
|
}
|
|
}
|
|
if (found == 0)
|
|
dev::Console.print_warn("No entities found matching: " + fragment);
|
|
else
|
|
dev::Console.print_info(std::to_string(found) + " match(es)");
|
|
});
|
|
|
|
con.register_command("ecs.disable", "Disable entity (systems will skip it): ecs.disable <name>",
|
|
[](const dev::args_t &args) {
|
|
if (args.size() < 2) { dev::Console.print_error("Usage: ecs.disable <name>"); return; }
|
|
ECScene *scene = Application.sceneManager.CurrentScene();
|
|
if (!scene) { dev::Console.print_warn("No active scene"); return; }
|
|
ECWorld &world = scene->World();
|
|
|
|
entt::entity entity = world.FindEntityByName(args[1]);
|
|
if (entity == entt::null) { dev::Console.print_error("Entity not found: " + args[1]); return; }
|
|
if (!world.HasComponent<ECSComponent::Disabled>(entity))
|
|
world.AddComponent<ECSComponent::Disabled>(entity);
|
|
dev::Console.print_ok("Disabled: " + args[1]);
|
|
});
|
|
|
|
con.register_command("ecs.enable", "Re-enable a disabled entity: ecs.enable <name>",
|
|
[](const dev::args_t &args) {
|
|
if (args.size() < 2) { dev::Console.print_error("Usage: ecs.enable <name>"); return; }
|
|
ECScene *scene = Application.sceneManager.CurrentScene();
|
|
if (!scene) { dev::Console.print_warn("No active scene"); return; }
|
|
ECWorld &world = scene->World();
|
|
|
|
entt::entity entity = world.FindEntityByName(args[1]);
|
|
if (entity == entt::null) { dev::Console.print_error("Entity not found: " + args[1]); return; }
|
|
world.RemoveComponent<ECSComponent::Disabled>(entity);
|
|
dev::Console.print_ok("Enabled: " + args[1]);
|
|
});
|
|
|
|
con.register_command("ecs.addparticles", "Add a particle emitter to an entity: ecs.addparticles <name>",
|
|
[](const dev::args_t &args) {
|
|
if (args.size() < 2) { dev::Console.print_error("Usage: ecs.addparticles <name>"); return; }
|
|
ECScene *scene = Application.sceneManager.CurrentScene();
|
|
if (!scene) { dev::Console.print_warn("No active scene"); return; }
|
|
ECWorld &world = scene->World();
|
|
|
|
entt::entity entity = world.FindEntityByName(args[1]);
|
|
if (entity == entt::null) { dev::Console.print_error("Entity not found: " + args[1]); return; }
|
|
|
|
auto& emitter = world.AddComponent<ECSComponent::ParticleEmitter>(entity);
|
|
emitter.isActive = true;
|
|
emitter.spawnRate = 20.0f;
|
|
emitter.particleLifetime = 2.5f;
|
|
emitter.gravity = glm::vec3(0.0f, 0.4f, 0.0f);
|
|
emitter.airResistance = 0.15f;
|
|
emitter.colorFade = glm::vec4(0.0f, 0.0f, 0.0f, -0.5f);
|
|
if (auto *t = world.GetComponent<ECSComponent::Transform>(entity))
|
|
emitter.emitterLocation = glm::vec3(t->Position);
|
|
dev::Console.print_ok("ParticleEmitter added to: " + args[1]);
|
|
});
|
|
|
|
con.register_command("ecs.addspotlight",
|
|
"Spawn SpotLight at position: ecs.addspotlight <name> <x> <y> <z> [r g b] [intensity] [range]",
|
|
[](const dev::args_t &args) {
|
|
if (args.size() < 5) { dev::Console.print_error("Usage: ecs.addspotlight <name> <x> <y> <z> [r g b] [intensity] [range]"); return; }
|
|
ECScene *scene = Application.sceneManager.CurrentScene();
|
|
if (!scene) { dev::Console.print_warn("No active scene"); return; }
|
|
ECWorld &world = scene->World();
|
|
|
|
auto entity = world.CreateEntity();
|
|
|
|
auto& id = world.AddComponent<ECSComponent::Identification>(entity);
|
|
id.Name = args[1];
|
|
|
|
auto& t = world.AddComponent<ECSComponent::Transform>(entity);
|
|
t.Position = glm::dvec3(std::stod(args[2]), std::stod(args[3]), std::stod(args[4]));
|
|
|
|
auto& spot = world.AddComponent<ECSComponent::SpotLight>(entity);
|
|
if (args.size() > 7) {
|
|
spot.Color = glm::vec3(std::stof(args[5]), std::stof(args[6]), std::stof(args[7]));
|
|
}
|
|
if (args.size() > 8) spot.Intensity = std::stof(args[8]);
|
|
if (args.size() > 9) spot.Range = std::stof(args[9]);
|
|
spot.Enabled = true;
|
|
|
|
dev::Console.print_ok("SpotLight '" + args[1] + "' spawned at ("
|
|
+ args[2] + ", " + args[3] + ", " + args[4] + ")");
|
|
});
|
|
|
|
con.register_command("ecs.clone",
|
|
"Clone entity with optional offset: ecs.clone <src> <newname> [dx dy dz]",
|
|
[](const dev::args_t &args) {
|
|
if (args.size() < 3) { dev::Console.print_error("Usage: ecs.clone <src> <newname> [dx dy dz]"); return; }
|
|
ECScene *scene = Application.sceneManager.CurrentScene();
|
|
if (!scene) { dev::Console.print_warn("No active scene"); return; }
|
|
ECWorld &world = scene->World();
|
|
|
|
entt::entity src = world.FindEntityByName(args[1]);
|
|
if (src == entt::null) { dev::Console.print_error("Entity not found: " + args[1]); return; }
|
|
if (world.FindEntityByName(args[2]) != entt::null) { dev::Console.print_error("Name already exists: " + args[2]); return; }
|
|
|
|
glm::dvec3 offset{0.0};
|
|
if (args.size() >= 6) {
|
|
offset = glm::dvec3(std::stod(args[3]), std::stod(args[4]), std::stod(args[5]));
|
|
}
|
|
|
|
auto dst = world.CreateEntity();
|
|
auto &id = world.AddComponent<ECSComponent::Identification>(dst);
|
|
id.Name = args[2];
|
|
|
|
if (auto *t = world.GetComponent<ECSComponent::Transform>(src)) {
|
|
auto &nt = world.AddComponent<ECSComponent::Transform>(dst);
|
|
nt = *t;
|
|
nt.Position += offset;
|
|
}
|
|
if (auto *s = world.GetComponent<ECSComponent::SpotLight>(src))
|
|
world.AddComponent<ECSComponent::SpotLight>(dst) = *s;
|
|
if (auto *p = world.GetComponent<ECSComponent::ParticleEmitter>(src))
|
|
world.AddComponent<ECSComponent::ParticleEmitter>(dst) = *p;
|
|
if (auto *b = world.GetComponent<ECSComponent::Billboard>(src))
|
|
world.AddComponent<ECSComponent::Billboard>(dst) = *b;
|
|
if (auto *l = world.GetComponent<ECSComponent::Line>(src))
|
|
world.AddComponent<ECSComponent::Line>(dst) = *l;
|
|
if (auto *lod = world.GetComponent<ECSComponent::LODController>(src))
|
|
world.AddComponent<ECSComponent::LODController>(dst) = *lod;
|
|
|
|
dev::Console.print_ok("Cloned '" + args[1] + "' → '" + args[2] + "'");
|
|
});
|
|
|
|
con.register_command("ecs.save",
|
|
"Save ECS entities to JSON: ecs.save [filename=ecs_save.json]",
|
|
[](const dev::args_t &args) {
|
|
ECScene *scene = Application.sceneManager.CurrentScene();
|
|
if (!scene) { dev::Console.print_warn("No active scene"); return; }
|
|
std::string filename = (args.size() > 1) ? args[1] : "ecs_save.json";
|
|
int n = ecs_persistence::save(scene->World(), filename);
|
|
if (n >= 0)
|
|
dev::Console.print_ok("Saved " + std::to_string(n) + " entities to " + filename);
|
|
else
|
|
dev::Console.print_error("Cannot write: " + filename);
|
|
});
|
|
|
|
con.register_command("ecs.load",
|
|
"Load ECS entities from JSON: ecs.load [filename=ecs_save.json]",
|
|
[](const dev::args_t &args) {
|
|
ECScene *scene = Application.sceneManager.CurrentScene();
|
|
if (!scene) { dev::Console.print_warn("No active scene"); return; }
|
|
std::string filename = (args.size() > 1) ? args[1] : "ecs_save.json";
|
|
int n = ecs_persistence::load(scene->World(), filename);
|
|
if (n >= 0)
|
|
dev::Console.print_ok("Loaded " + std::to_string(n) + " entities from " + filename);
|
|
else
|
|
dev::Console.print_error("Cannot read or parse: " + filename);
|
|
});
|
|
|
|
con.print_info("Driver console ready. Type 'help' for commands.");
|
|
}
|
|
|
|
void driver_ui::render_menu_contents()
|
|
{
|
|
ui_layer::render_menu_contents();
|
|
|
|
if (ImGui::BeginMenu(STR_C("Mode windows")))
|
|
{
|
|
ImGui::MenuItem(m_aidpanel.title.c_str(), "F1", &m_aidpanel.is_open);
|
|
ImGui::MenuItem(m_scenariopanel.title.c_str(), "F1", &m_aidpanel.is_open);
|
|
ImGui::MenuItem(STR_C("Timetable"), "F2", &m_timetablepanel.is_open);
|
|
ImGui::MenuItem(m_debugpanel.name().c_str(), "F12", &m_debugpanel.is_open);
|
|
ImGui::MenuItem(m_mappanel.name().c_str(), "Tab", &m_mappanel.is_open);
|
|
ImGui::MenuItem(m_vehiclelist.name().c_str(), nullptr, &m_vehiclelist.is_open);
|
|
ImGui::MenuItem(m_trainingcardpanel.name().c_str(), nullptr, &m_trainingcardpanel.is_open);
|
|
ImGui::MenuItem(m_cameraviewpanel.name().c_str(), nullptr, &m_cameraviewpanel.is_open);
|
|
if (DebugModeFlag)
|
|
ImGui::MenuItem(m_perfgraphpanel.name().c_str(), nullptr, &m_perfgraphpanel.is_open);
|
|
|
|
if (ImGui::MenuItem(m_timepanel.name().c_str()))
|
|
m_timepanel.open();
|
|
|
|
ImGui::EndMenu();
|
|
}
|
|
}
|
|
|
|
void driver_ui::showDebugUI()
|
|
{
|
|
m_debugpanel.is_open = !m_debugpanel.is_open;
|
|
}
|
|
|
|
// potentially processes provided input key. returns: true if key was processed, false otherwise
|
|
bool driver_ui::on_key(int const Key, int const Action)
|
|
{
|
|
if (ui_layer::on_key(Key, Action))
|
|
return true;
|
|
|
|
switch (Key)
|
|
{
|
|
case GLFW_KEY_TAB:
|
|
case GLFW_KEY_F1:
|
|
case GLFW_KEY_F2:
|
|
case GLFW_KEY_F3:
|
|
case GLFW_KEY_F10:
|
|
case GLFW_KEY_F12:
|
|
{ // ui mode selectors
|
|
|
|
if ((true == Global.ctrlState) || (true == Global.shiftState))
|
|
{
|
|
// only react to keys without modifiers
|
|
return false;
|
|
}
|
|
|
|
if (Action != GLFW_PRESS)
|
|
{
|
|
return true;
|
|
} // recognized, but ignored
|
|
}
|
|
|
|
default:
|
|
{ // everything else
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (Key)
|
|
{
|
|
|
|
case GLFW_KEY_TAB:
|
|
{
|
|
m_mappanel.is_open = !m_mappanel.is_open;
|
|
|
|
return true;
|
|
}
|
|
|
|
case GLFW_KEY_F1:
|
|
{
|
|
// basic consist info
|
|
auto state = ((m_aidpanel.is_open == false) ? 0 : (m_aidpanel.is_expanded == false) ? 1 : 2);
|
|
state = clamp_circular(++state, 3);
|
|
|
|
m_aidpanel.is_open = (state > 0);
|
|
m_aidpanel.is_expanded = (state > 1);
|
|
|
|
return true;
|
|
}
|
|
|
|
case GLFW_KEY_F2:
|
|
{
|
|
// timetable
|
|
auto state = ((m_timetablepanel.is_open == false) ? 0 : (m_timetablepanel.is_expanded == false) ? 1 : 2);
|
|
state = clamp_circular(++state, 3);
|
|
|
|
m_timetablepanel.is_open = (state > 0);
|
|
m_timetablepanel.is_expanded = (state > 1);
|
|
|
|
return true;
|
|
}
|
|
|
|
case GLFW_KEY_F3:
|
|
{
|
|
// debug panel
|
|
m_scenariopanel.is_open = !m_scenariopanel.is_open;
|
|
return true;
|
|
}
|
|
|
|
case GLFW_KEY_F12:
|
|
{
|
|
// debug panel
|
|
if (Global.shiftState)
|
|
{
|
|
m_debugpanel.is_open = !m_debugpanel.is_open;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// potentially processes provided mouse movement. returns: true if the input was processed, false otherwise
|
|
bool driver_ui::on_cursor_pos(double const Horizontal, double const Vertical)
|
|
{
|
|
// intercept mouse movement when the pause window is on
|
|
return m_paused;
|
|
}
|
|
|
|
// potentially processes provided mouse button. returns: true if the input was processed, false otherwise
|
|
bool driver_ui::on_mouse_button(int const Button, int const Action)
|
|
{
|
|
// intercept mouse movement when the pause window is on
|
|
return m_paused;
|
|
}
|
|
|
|
// updates state of UI elements
|
|
void driver_ui::update()
|
|
{
|
|
|
|
auto const pausemask{1 | 2};
|
|
auto ispaused{(false == DebugModeFlag) && ((Global.iPause & pausemask) != 0)};
|
|
if ((ispaused != m_paused) && (false == Global.ControlPicking))
|
|
{
|
|
set_cursor(ispaused);
|
|
}
|
|
m_paused = ispaused;
|
|
|
|
ui_layer::update();
|
|
}
|
|
|
|
void driver_ui::set_cursor(bool const Visible)
|
|
{
|
|
|
|
if (Visible)
|
|
{
|
|
Application.set_cursor(GLFW_CURSOR_NORMAL);
|
|
Application.set_cursor_pos(Global.window_size.x / 2, Global.window_size.y / 2);
|
|
}
|
|
else
|
|
{
|
|
Application.set_cursor(GLFW_CURSOR_DISABLED);
|
|
Application.set_cursor_pos(0, 0);
|
|
}
|
|
}
|
|
|
|
// render() subclass details
|
|
void driver_ui::render_()
|
|
{
|
|
const std::string *rec_name = m_trainingcardpanel.is_recording();
|
|
if (rec_name && m_cameraviewpanel.set_state(true))
|
|
{
|
|
m_cameraviewpanel.rec_name = *rec_name;
|
|
m_cameraviewpanel.is_open = true;
|
|
}
|
|
else if (!rec_name)
|
|
m_cameraviewpanel.set_state(false);
|
|
|
|
// pause/quit modal
|
|
auto const popupheader{STR_C("Simulation Paused")};
|
|
|
|
ImGui::SetNextWindowSize(ImVec2(-1, -1));
|
|
if (ImGui::BeginPopupModal(popupheader, nullptr, 0))
|
|
{
|
|
if ((ImGui::Button(STR_C("Resume"), ImVec2(150, 0))) || (ImGui::IsKeyReleased(ImGui::GetKeyIndex(ImGuiKey_Escape))))
|
|
{
|
|
m_relay.post(user_command::pausetoggle, 0.0, 0.0, GLFW_RELEASE, 0);
|
|
}
|
|
if (ImGui::Button(STR_C("Quit"), ImVec2(150, 0)))
|
|
{
|
|
Application.queue_quit(false);
|
|
}
|
|
if (!m_paused)
|
|
ImGui::CloseCurrentPopup();
|
|
ImGui::EndPopup();
|
|
}
|
|
else if (m_paused)
|
|
{
|
|
ImGui::OpenPopup(popupheader);
|
|
}
|
|
|
|
if (Global.desync != 0.0f)
|
|
{
|
|
ImGui::SetNextWindowSize(ImVec2(-1, -1));
|
|
if (ImGui::Begin("network", nullptr, ImGuiWindowFlags_NoCollapse))
|
|
ImGui::Text("desync: %0.2f", Global.desync);
|
|
ImGui::End();
|
|
}
|
|
}
|