Reorganize source files into logical subdirectories

Co-authored-by: Hirek193 <23196899+Hirek193@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-03-14 19:01:57 +00:00
parent f981f81d55
commit 0531086bb9
221 changed files with 131 additions and 108 deletions

622
application/uilayer.cpp Normal file
View File

@@ -0,0 +1,622 @@
/*
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 "uilayer.h"
#include <utility>
#include "Globals.h"
#include "renderer.h"
#include "Logs.h"
#include "simulation.h"
#include "translation.h"
#include "application.h"
#include "editormode.h"
#include "imgui/imgui_impl_glfw.h"
GLFWwindow *ui_layer::m_window{nullptr};
ImGuiIO *ui_layer::m_imguiio{nullptr};
GLint ui_layer::m_textureunit{GL_TEXTURE0};
bool ui_layer::m_cursorvisible;
ImFont *ui_layer::font_default{nullptr};
ImFont *ui_layer::font_mono{nullptr};
ImFont *ui_layer::font_loading{nullptr};
ui_panel::ui_panel(std::string Identifier, bool const Isopen) : is_open(Isopen), m_name(std::move(Identifier)) {}
void ui_panel::render()
{
if (false == is_open)
return;
int flags = window_flags;
if (flags == -1)
flags = ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoCollapse;
if (size.x > 0)
flags |= ImGuiWindowFlags_NoResize;
if (no_title_bar)
flags |= ImGuiWindowFlags_NoTitleBar;
if (pos.x != -1 && pos.y != -1)
ImGui::SetNextWindowPos(ImVec2(pos.x, pos.y), ImGuiCond_Always);
if (size.x > 0)
ImGui::SetNextWindowSize(ImVec2S(size.x, size.y), ImGuiCond_Always);
else if (size_min.x == -1)
ImGui::SetNextWindowSize(ImVec2(0, 0), ImGuiCond_FirstUseEver);
if (size_min.x > 0)
ImGui::SetNextWindowSizeConstraints(ImVec2S(size_min.x, size_min.y), ImVec2S(size_max.x, size_max.y));
auto const panelname{(title.empty() ? m_name : title) + "###" + m_name};
if (ImGui::Begin(panelname.c_str(), &is_open, flags))
{
render_contents();
popups.remove_if([](const std::unique_ptr<ui::popup> &popup) { return popup->render(); });
}
ImGui::End();
}
void ui_panel::render_contents()
{
for (auto const &line : text_lines)
{
ImGui::TextColored(ImVec4(line.color.r, line.color.g, line.color.b, line.color.a), line.data.c_str());
}
}
void ui_panel::register_popup(std::unique_ptr<ui::popup> &&popup)
{
popups.push_back(std::move(popup));
}
void ui_expandable_panel::render_contents()
{
ImGui::Checkbox(STR_C("expand"), &is_expanded);
ui_panel::render_contents();
}
void ui_log_panel::render_contents()
{
ImGui::PushFont(ui_layer::font_mono);
for (const std::string &s : log_scrollback)
ImGui::TextUnformatted(s.c_str());
if (ImGui::GetScrollY() == ImGui::GetScrollMaxY())
ImGui::SetScrollHereY(1.0f);
ImGui::PopFont();
}
ui_layer::ui_layer()
{
if (Global.loading_log)
add_external_panel(&m_logpanel);
m_logpanel.size = {700, 400};
}
ui_layer::~ui_layer() {}
bool ui_layer::key_callback(int key, int scancode, int action, int mods)
{
ImGui_ImplGlfw_KeyCallback(m_window, key, scancode, action, mods);
return m_imguiio->WantCaptureKeyboard;
}
bool ui_layer::char_callback(unsigned int c)
{
ImGui_ImplGlfw_CharCallback(m_window, c);
return m_imguiio->WantCaptureKeyboard;
}
bool ui_layer::scroll_callback(double xoffset, double yoffset)
{
ImGui_ImplGlfw_ScrollCallback(m_window, xoffset, yoffset);
return m_imguiio->WantCaptureMouse;
}
bool ui_layer::mouse_button_callback(int button, int action, int mods)
{
ImGui_ImplGlfw_MouseButtonCallback(m_window, button, action, mods);
return m_imguiio->WantCaptureMouse;
}
static ImVec4 imvec_lerp(const ImVec4 &a, const ImVec4 &b, float t)
{
return ImVec4(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t, a.w + (b.w - a.w) * t);
}
void ui_layer::imgui_style()
{
ImVec4 *colors = ImGui::GetStyle().Colors;
colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImGuiCol_TextDisabled] = ImVec4(0.35f, 0.35f, 0.35f, 1.00f);
colors[ImGuiCol_WindowBg] = ImVec4(0.04f, 0.04f, 0.04f, 0.94f);
colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
colors[ImGuiCol_PopupBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f);
colors[ImGuiCol_Border] = ImVec4(0.31f, 0.34f, 0.31f, 0.50f);
colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
colors[ImGuiCol_FrameBg] = ImVec4(0.21f, 0.28f, 0.17f, 0.54f);
colors[ImGuiCol_FrameBgHovered] = ImVec4(0.42f, 0.64f, 0.23f, 0.40f);
colors[ImGuiCol_FrameBgActive] = ImVec4(0.42f, 0.64f, 0.23f, 0.67f);
colors[ImGuiCol_TitleBg] = ImVec4(0.03f, 0.03f, 0.03f, 1.00f);
colors[ImGuiCol_TitleBgActive] = ImVec4(0.21f, 0.28f, 0.17f, 1.00f);
colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f);
colors[ImGuiCol_MenuBarBg] = ImVec4(0.10f, 0.10f, 0.10f, 1.00f);
colors[ImGuiCol_ScrollbarBg] = ImVec4(0.01f, 0.01f, 0.01f, 0.53f);
colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.22f, 0.22f, 0.22f, 1.00f);
colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.29f, 0.29f, 0.29f, 1.00f);
colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.36f, 0.36f, 0.36f, 1.00f);
colors[ImGuiCol_CheckMark] = ImVec4(0.42f, 0.64f, 0.23f, 1.00f);
colors[ImGuiCol_SliderGrab] = ImVec4(0.37f, 0.53f, 0.25f, 1.00f);
colors[ImGuiCol_SliderGrabActive] = ImVec4(0.42f, 0.64f, 0.23f, 1.00f);
colors[ImGuiCol_Button] = ImVec4(0.42f, 0.64f, 0.23f, 0.40f);
colors[ImGuiCol_ButtonHovered] = ImVec4(0.42f, 0.64f, 0.23f, 1.00f);
colors[ImGuiCol_ButtonActive] = ImVec4(0.37f, 0.54f, 0.19f, 1.00f);
colors[ImGuiCol_Header] = ImVec4(0.42f, 0.64f, 0.23f, 0.31f);
colors[ImGuiCol_HeaderHovered] = ImVec4(0.42f, 0.64f, 0.23f, 0.80f);
colors[ImGuiCol_HeaderActive] = ImVec4(0.42f, 0.64f, 0.23f, 1.00f);
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.29f, 0.41f, 0.18f, 0.78f);
colors[ImGuiCol_SeparatorActive] = ImVec4(0.29f, 0.41f, 0.18f, 1.00f);
colors[ImGuiCol_ResizeGrip] = ImVec4(0.42f, 0.64f, 0.23f, 0.25f);
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.42f, 0.64f, 0.23f, 0.67f);
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.42f, 0.64f, 0.23f, 0.95f);
colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.42f, 0.64f, 0.23f, 0.35f);
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
colors[ImGuiCol_Separator] = colors[ImGuiCol_Border];
colors[ImGuiCol_Tab] = imvec_lerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);
colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
colors[ImGuiCol_TabActive] = imvec_lerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
colors[ImGuiCol_TabUnfocused] = imvec_lerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
colors[ImGuiCol_TabUnfocusedActive] = imvec_lerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
ImGui::GetStyle().ScaleAllSizes(Global.ui_scale);
}
bool ui_layer::init(GLFWwindow *Window)
{
m_window = Window;
IMGUI_CHECKVERSION();
ImGui::CreateContext();
m_imguiio = &ImGui::GetIO();
m_imguiio->ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange;
// m_imguiio->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
// m_imguiio->ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
static const ImWchar ranges[] =
{
0x0020, 0x00FF, // Basic Latin + Latin Supplement
0x0100, 0x017F, // Latin Extended-A
0x2070, 0x2079, // superscript
0x2500, 0x256C, // box drawings
0,
};
ImFontConfig config;
// config.FontDataOwnedByAtlas = false; // Avoid duplicate release of font data
if (FileExists("fonts/dejavusans.ttf")) {
// Load basic font first
font_default = m_imguiio->Fonts->AddFontFromFileTTF("fonts/dejavusans.ttf", Global.ui_fontsize, &config, &ranges[0]);
// Add support for Chinese character ranges
if (font_default) {
ImFontConfig chinese_config;
chinese_config.MergeMode = true;
chinese_config.PixelSnapH = true;
chinese_config.OversampleH = 1;
chinese_config.OversampleV = 1;
// Use NotoSansSC-Regular.ttf font file
if (FileExists("fonts/NotoSansSC-Regular.ttf")) {
const ImWchar* chinese_ranges = m_imguiio->Fonts->GetGlyphRangesChineseFull();
m_imguiio->Fonts->AddFontFromFileTTF("fonts/NotoSansSC-Regular.ttf", Global.ui_fontsize, &chinese_config, chinese_ranges);
}
}
}
if (FileExists("fonts/dejavusansmono.ttf")) {
ImFontConfig mono_config;
mono_config.GlyphRanges = &ranges[0]; // Basic Latin characters
font_mono = m_imguiio->Fonts->AddFontFromFileTTF("fonts/dejavusansmono.ttf", Global.ui_fontsize, &mono_config, &ranges[0]);
// Add Chinese character support for monospace font as well
if (font_mono) {
ImFontConfig chinese_mono_config;
chinese_mono_config.OversampleH = 1;
chinese_mono_config.OversampleV = 1;
chinese_mono_config.MergeMode = true;
chinese_mono_config.PixelSnapH = true;
// Use NotoSansSC-Regular.ttf for monospace font as well
if (FileExists("fonts/NotoSansSC-Regular.ttf")) {
const ImWchar* chinese_ranges = m_imguiio->Fonts->GetGlyphRangesChineseFull();
m_imguiio->Fonts->AddFontFromFileTTF("fonts/NotoSansSC-Regular.ttf", Global.ui_fontsize, &chinese_mono_config, chinese_ranges);
}
}
}
if (FileExists("fonts/bahnschrift.ttf")) {
ImFontConfig loading_config;
font_loading = m_imguiio->Fonts->AddFontFromFileTTF("fonts/bahnschrift.ttf", 48, &loading_config, &ranges[0]);
// Add Chinese character support for loading font as well
if (font_loading) {
ImFontConfig chinese_loading_config;
chinese_loading_config.OversampleH = 1;
chinese_loading_config.OversampleV = 1;
chinese_loading_config.MergeMode = true;
chinese_loading_config.PixelSnapH = true;
// Use NotoSansMonoCJKsc-Regular.ttf for loading font
if (FileExists("fonts/NotoSansMonoCJKsc-Regular.ttf")) {
const ImWchar* chinese_ranges = m_imguiio->Fonts->GetGlyphRangesChineseFull();
m_imguiio->Fonts->AddFontFromFileTTF("fonts/NotoSansMonoCJKsc-Regular.ttf", 48, &chinese_loading_config, chinese_ranges);
}
}
}
if (!font_default && !font_mono)
font_default = font_mono = m_imguiio->Fonts->AddFontDefault();
else if (!font_default)
font_default = font_mono;
else if (!font_mono)
font_mono = font_default;
if (!font_loading)
font_loading = font_default;
imgui_style();
ImGui_ImplGlfw_InitForOpenGL(m_window, false);
if (!GfxRenderer->GetImguiRenderer() || !GfxRenderer->GetImguiRenderer()->Init())
{
return false;
}
return true;
}
void ui_layer::shutdown()
{
ImGui::EndFrame();
GfxRenderer->GetImguiRenderer()->Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
}
bool ui_layer::on_key(int const Key, int const Action)
{
if (Action == GLFW_PRESS)
{
if (Key == GLFW_KEY_PRINT_SCREEN)
{
Application.queue_screenshot();
return true;
}
if (Key == GLFW_KEY_F9)
{
m_logpanel.is_open = !m_logpanel.is_open;
return true;
}
if (Key == GLFW_KEY_F10)
{
m_quit_active = !m_quit_active;
return true;
}
if (m_quit_active)
{
if (Key == GLFW_KEY_Y)
{
Application.queue_quit(false);
return true;
}
else if (Key == GLFW_KEY_N)
{
m_quit_active = false;
return true;
}
}
}
return false;
}
bool ui_layer::on_cursor_pos(double const Horizontal, double const Vertical)
{
return false;
}
bool ui_layer::on_mouse_button(int const Button, int const Action)
{
return false;
}
void ui_layer::on_window_resize(int w, int h)
{
for (auto *panel : m_panels)
panel->on_window_resize(w, h);
}
void ui_layer::update()
{
for (auto *panel : m_panels)
panel->update();
for (auto it = m_ownedpanels.rbegin(); it != m_ownedpanels.rend(); it++)
{
(*it)->update();
if (!(*it)->is_open)
m_ownedpanels.erase(std::next(it).base());
}
}
void ui_layer::render()
{
render_background();
render_panels();
render_tooltip();
render_menu();
render_quit_widget();
render_hierarchy();
// template method implementation
render_();
render_internal();
}
void ui_layer::render_internal()
{
ImGui::Render();
GfxRenderer->GetImguiRenderer()->Render();
}
void ui_layer::begin_ui_frame()
{
begin_ui_frame_internal();
}
void ui_layer::begin_ui_frame_internal()
{
GfxRenderer->GetImguiRenderer()->BeginFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
}
void ui_layer::render_quit_widget()
{
if (!m_quit_active)
return;
ImGui::SetNextWindowSize(ImVec2(0, 0));
ImGui::Begin(STR_C("Quit"), &m_quit_active, ImGuiWindowFlags_NoResize);
ImGui::TextUnformatted(STR_C("Quit simulation?"));
if (ImGui::Button(STR_C("Yes")))
Application.queue_quit(false);
ImGui::SameLine();
if (ImGui::Button(STR_C("No")))
m_quit_active = false;
ImGui::End();
}
void ui_layer::render_hierarchy(){
if(!m_editor_hierarchy)
return;
ImGui::SetNextWindowSize(ImVec2(0, 0));
ImGui::Begin(STR_C("Scene Hierarchy"), &m_editor_hierarchy, ImGuiWindowFlags_AlwaysAutoResize);
ImGui::Text("Registered nodes: %zu", scene::Hierarchy.size());
ImGui::BeginChild("hierarchy_list", ImVec2(500, 300), true);
for (auto &entry : scene::Hierarchy)
{
const std::string &uuid = entry.first;
scene::basic_node *node = entry.second;
if (node)
{
char buf[512];
std::snprintf(buf, sizeof(buf), "%s | %s (%.1f, %.1f, %.1f)",
node->name().c_str(),
uuid.c_str(),
node->location().x,
node->location().y,
node->location().z);
if (ImGui::Selectable(buf, false))
{
// Focus camera on selected node
auto const node_pos = node->location();
auto const camera_offset = glm::dvec3(0.0, 10.0, -20.0);
editor_mode::set_focus_active(false);
TCamera &camera = editor_mode::get_camera();
camera.Pos = node_pos + camera_offset;
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("UUID: %s\nNode type: %s", uuid.c_str(), typeid(*node).name());
}
}
}
ImGui::EndChild();
ImGui::End();
}
void ui_layer::set_cursor(int const Mode)
{
glfwSetInputMode(m_window, GLFW_CURSOR, Mode);
m_cursorvisible = (Mode != GLFW_CURSOR_DISABLED);
}
void ui_layer::set_progress(std::string const &Text)
{
m_progresstext = Text;
}
void ui_layer::set_progress(float const progress, float const subtaskprogress)
{
m_progress = progress * 0.01f;
m_subtaskprogress = subtaskprogress * 0.01f;
}
void ui_layer::set_background(std::string const &Filename)
{
m_background = Filename.empty() ? null_handle : GfxRenderer->Fetch_Texture(Filename);
}
void ui_layer::clear_panels()
{
m_panels.clear();
m_ownedpanels.clear();
}
void ui_layer::add_owned_panel(ui_panel *Panel)
{
for (auto &panel : m_ownedpanels)
if (panel->name() == Panel->name())
{
delete Panel;
return;
}
Panel->is_open = true;
m_ownedpanels.emplace_back(Panel);
}
void ui_layer::render_panels()
{
for (auto *panel : m_panels)
panel->render();
for (auto &panel : m_ownedpanels)
panel->render();
if (m_imgui_demo)
ImGui::ShowDemoWindow(&m_imgui_demo);
}
void ui_layer::render_tooltip()
{
if (!m_cursorvisible || m_imguiio->WantCaptureMouse || m_tooltip.empty())
return;
ImGui::BeginTooltip();
ImGui::TextUnformatted(m_tooltip.c_str());
ImGui::EndTooltip();
}
void ui_layer::render_menu_contents()
{
if (ImGui::BeginMenu(STR_C("General")))
{
bool flag = DebugModeFlag;
if (ImGui::MenuItem(STR_C("Debug mode"), nullptr, &flag))
{
command_relay relay;
relay.post(user_command::debugtoggle, 0.0, 0.0, GLFW_RELEASE, 0);
}
ImGui::MenuItem(STR_C("Quit"), "F10", &m_quit_active);
ImGui::EndMenu();
}
if (ImGui::BeginMenu(STR_C("Tools")))
{
static bool log = Global.iWriteLogEnabled & 1;
ImGui::MenuItem(STR_C("Logging to log.txt"), nullptr, &log);
if (log)
Global.iWriteLogEnabled |= 1;
else
Global.iWriteLogEnabled &= ~1;
if (ImGui::MenuItem(STR_C("Screenshot"), "PrtScr"))
Application.queue_screenshot();
ImGui::EndMenu();
}
if (ImGui::BeginMenu(STR_C("Windows")))
{
ImGui::MenuItem(STR_C("Log"), "F9", &m_logpanel.is_open);
if (DebugModeFlag)
{
ImGui::MenuItem(STR_C("ImGui Demo"), nullptr, &m_imgui_demo);
bool ret = ImGui::MenuItem(STR_C("Headlight config"), nullptr, GfxRenderer->Debug_Ui_State(std::nullopt));
GfxRenderer->Debug_Ui_State(ret);
}
if(EditorModeFlag){
ImGui::MenuItem("Hierarchy", nullptr, &m_editor_hierarchy);
bool change_history_enabled = editor_mode::change_history();
if (ImGui::MenuItem("Change History", nullptr, &change_history_enabled))
{
editor_mode::set_change_history(change_history_enabled);
}
}
ImGui::EndMenu();
}
}
void ui_layer::render_menu()
{
glm::dvec2 mousepos = Global.cursor_pos;
if (!((Global.ControlPicking && mousepos.y < 50.0f) || m_imguiio->WantCaptureMouse) || m_suppress_menu)
return;
if (ImGui::BeginMainMenuBar())
{
render_menu_contents();
ImGui::EndMainMenuBar();
}
}
void ui_layer::render_background()
{
if (m_background == 0)
return;
ImVec2 display_size = ImGui::GetIO().DisplaySize;
ITexture &tex = GfxRenderer->Texture(m_background);
tex.create();
float tex_w = (float)tex.get_width();
float tex_h = (float)tex.get_height();
// skalowanie "cover" wypełnia cały ekran, zachowując proporcje
float scale_factor = (display_size.x / display_size.y) > (tex_w / tex_h) ? display_size.x / tex_w : display_size.y / tex_h;
ImVec2 image_size(tex_w * scale_factor, tex_h * scale_factor);
// wyśrodkowanie obrazka
ImVec2 start_position((display_size.x - image_size.x) * 0.5f, (display_size.y - image_size.y) * 0.5f);
ImVec2 end_position(start_position.x + image_size.x, start_position.y + image_size.y);
// obrazek jest odwrócony w pionie odwracamy UV
ImGui::GetBackgroundDrawList()->AddImage(reinterpret_cast<ImTextureID>(tex.get_id()), start_position, end_position, ImVec2(0, 1), ImVec2(1, 0));
}