mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 17:09:06 +01:00
711 lines
21 KiB
C++
711 lines
21 KiB
C++
#include <filesystem>
|
|
#include <memory>
|
|
|
|
#include "main_window.h"
|
|
#include <SDL3/SDL.h>
|
|
#include "platform_folders.h"
|
|
|
|
#include "media_converter.h"
|
|
|
|
#include "pack_archive.h"
|
|
#include "uuid.h"
|
|
#include "sys_lib.h"
|
|
|
|
#ifdef USE_WINDOWS_OS
|
|
#include <winsock2.h>
|
|
#include <iphlpapi.h>
|
|
#include <icmpapi.h>
|
|
#include <stdio.h>
|
|
|
|
#pragma comment(lib, "iphlpapi.lib")
|
|
#pragma comment(lib, "ws2_32.lib")
|
|
#endif
|
|
#include "IconsMaterialDesignIcons.h"
|
|
#include "ImGuiFileDialog.h"
|
|
#include "imgui_memory_editor.h"
|
|
|
|
#include "app_controller.h"
|
|
#include "all_events.h"
|
|
#include "story_project.h"
|
|
|
|
#include "nodes_factory.h"
|
|
#include "media_node_widget.h"
|
|
#include "call_function_node_widget.h"
|
|
#include "module_node_widget.h"
|
|
#include "variable_node_widget.h"
|
|
#include "operator_node_widget.h"
|
|
#include "print_node_widget.h"
|
|
#include "function_entry_node_widget.h"
|
|
#include "branch_node_widget.h"
|
|
#include "play_media_node_widget.h"
|
|
#include "send_signal_node_widget.h"
|
|
#include "wait_delay_node_widget.h"
|
|
#include "wait_event_node_widget.h"
|
|
#include "for_loop_node_widget.h"
|
|
#include "while_loop_node_widget.h"
|
|
#include "break_node_widget.h"
|
|
#include "continue_node_widget.h"
|
|
#include "function_exit_node_widget.h"
|
|
|
|
|
|
MainWindow::MainWindow(ILogger& logger, EventBus& eventBus, AppController& appController)
|
|
: m_logger(logger)
|
|
, m_eventBus(eventBus)
|
|
, m_appController(appController)
|
|
, m_emulatorDock(appController)
|
|
, m_debuggerWindow(appController)
|
|
, m_cpuWindow(appController)
|
|
, m_resourcesDock(appController.GetResourceManager(), appController)
|
|
, m_nodeEditorWindow(appController, appController.GetNodesFactory(), m_widgetFactory, IStoryProject::PROJECT_TYPE_STORY)
|
|
, m_moduleEditorWindow(appController, appController.GetNodesFactory(), m_widgetFactory, IStoryProject::PROJECT_TYPE_MODULE)
|
|
, m_libraryWindow(appController, appController.GetLibraryManager(), appController.GetNodesFactory(), eventBus)
|
|
, m_projectPropertiesDialog(appController, appController.GetResourceManager())
|
|
, m_modulePropertiesDialog(appController)
|
|
{
|
|
CloseProject();
|
|
CloseModule();
|
|
|
|
// define style for all directories
|
|
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeDir, "", ImVec4(0.5f, 1.0f, 0.9f, 0.9f), ICON_MDI_FOLDER);
|
|
// define style for all files
|
|
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeFile, "", ImVec4(1.0f, 1.0f, 1.0f, 1.0f), ICON_MDI_FILE);
|
|
|
|
// registerNode<MediaNodeWidget>("media-node");
|
|
m_widgetFactory.registerNode<OperatorNodeWidget>(OperatorNodeUuid);
|
|
m_widgetFactory.registerNode<CallFunctionNodeWidget>(CallFunctionNodeUuid);
|
|
// m_widgetFactory.registerNode<ModuleNodeWidget>("module-node");
|
|
m_widgetFactory.registerNode<VariableNodeWidget>(VariableNodeUuid);
|
|
m_widgetFactory.registerNode<PrintNodeWidget>(PrintNodeUuid);
|
|
m_widgetFactory.registerNode<FunctionEntryNodeWidget>(FunctionEntryNodeUuid);
|
|
m_widgetFactory.registerNode<BranchNodeWidget>(BranchNodeUuid);
|
|
m_widgetFactory.registerNode<WaitEventNodeWidget>(WaitEventNodeUuid);
|
|
m_widgetFactory.registerNode<WaitDelayNodeWidget>(WaitDelayNodeUuid);
|
|
m_widgetFactory.registerNode<PlayMediaNodeWidget>(PlayMediaNodeUuid);
|
|
m_widgetFactory.registerNode<SendSignalNodeWidget>(SendSignalNodeUuid);
|
|
m_widgetFactory.registerNode<ForLoopNodeWidget>(ForLoopNodeUuid);
|
|
m_widgetFactory.registerNode<WhileLoopNodeWidget>(WhileLoopNodeUuid);
|
|
m_widgetFactory.registerNode<BreakNodeWidget>(BreakNodeUuid);
|
|
m_widgetFactory.registerNode<ContinueNodeWidget>(ContinueNodeUuid);
|
|
m_widgetFactory.registerNode<FunctionExitNodeWidget>(FunctionExitNodeUuid);
|
|
|
|
|
|
m_eventBus.Subscribe<OpenProjectEvent>([this](const OpenProjectEvent &event) {
|
|
OpenProject(event.GetUuid());
|
|
});
|
|
|
|
m_eventBus.Subscribe<OpenFunctionEvent>([this](const OpenFunctionEvent &event) {
|
|
OpenFunction(event.GetUuid(), event.GetName());
|
|
});
|
|
|
|
m_eventBus.Subscribe<VmStateEvent>([this](const VmStateEvent &event) {
|
|
|
|
if (event.type == VmStateEvent::Type::PrintEvent)
|
|
{
|
|
m_logger.Log("Print from VM: " + event.printOutput);
|
|
m_emulatorDock.AddVmOutput(event.printOutput);
|
|
}
|
|
});
|
|
|
|
m_eventBus.Subscribe<GenericResultEvent>([this](const GenericResultEvent &event) {
|
|
|
|
if (event.IsSuccess()) {
|
|
m_logger.Log("Operation successful: " + event.GetMessage());
|
|
m_toastNotifier.addToast("Success", event.GetMessage(), ToastType::Success);
|
|
} else {
|
|
m_logger.Log("Operation failed: " + event.GetMessage(), true);
|
|
m_toastNotifier.addToast("Error", event.GetMessage(), ToastType::Error);
|
|
}
|
|
});
|
|
|
|
m_eventBus.Subscribe<ModuleEvent>([this](const ModuleEvent &event) {
|
|
if (event.GetType() == ModuleEvent::Type::Open) {
|
|
OpenModule(event.GetUuid());
|
|
} else if (event.GetType() == ModuleEvent::Type::Closed) {
|
|
CloseModule();
|
|
} else if (event.GetType() == ModuleEvent::Type::BuildSuccess) {
|
|
m_toastNotifier.addToast("Module", "Module built successfully! Binary ready for testing.", ToastType::Success);
|
|
m_debuggerWindow.SetScript(m_appController.GetModuleAssembly());
|
|
|
|
m_emulatorDock.ClearVmOutput();
|
|
|
|
// Show success message if no errors
|
|
if (!m_errorListDock.HasErrors()) {
|
|
// You can also open a popup if desired
|
|
m_logger.Log("Module compilation successful - Binary saved and loaded into VM");
|
|
}
|
|
}
|
|
else if (event.GetType() == ModuleEvent::Type::BuildFailure) {
|
|
|
|
m_logger.Log("Module compilation failed: " + event.GetMessage(), true);
|
|
m_toastNotifier.addToast("Module", "Module build failed - Check Error List", ToastType::Error);
|
|
|
|
// Make sure error list is visible
|
|
m_errorListDock.Enable();
|
|
m_errorListDock.Show();
|
|
|
|
static CompilationError err;
|
|
err.line = event.GetLine();
|
|
err.message = event.GetMessage();
|
|
|
|
// Add error to dock
|
|
m_errorListDock.AddError(err);
|
|
}
|
|
});
|
|
|
|
|
|
m_languageSelector.SetOnLanguageChanged([this](const std::string& langCode) {
|
|
// Sauvegarder la préférence
|
|
m_appController.SaveParams();
|
|
m_logger.Log("Language changed to: " + langCode);
|
|
});
|
|
}
|
|
|
|
MainWindow::~MainWindow()
|
|
{
|
|
m_gui.Destroy();
|
|
}
|
|
|
|
|
|
float MainWindow::DrawMainMenuBar()
|
|
{
|
|
bool showNewProject = false;
|
|
bool showOpenProject = false;
|
|
|
|
float height = 60;
|
|
|
|
if (ImGui::BeginMainMenuBar())
|
|
{
|
|
if (ImGui::BeginMenu(TR("menu.file")))
|
|
{
|
|
|
|
if (ImGui::MenuItem("New story project"))
|
|
{
|
|
CloseProject();
|
|
|
|
auto newProject = m_appController.NewProject();
|
|
|
|
if (newProject)
|
|
{
|
|
m_appController.SaveProject();
|
|
OpenProject(newProject->GetUuid());
|
|
}
|
|
}
|
|
|
|
/*
|
|
if (ImGui::BeginMenu("Open Recent"))
|
|
{
|
|
for (auto &e : m_recentProjects)
|
|
{
|
|
if (e.size() > 0)
|
|
{
|
|
if (ImGui::MenuItem(e.c_str()))
|
|
{
|
|
OpenProject(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
ImGui::EndMenu();
|
|
}
|
|
*/
|
|
|
|
bool init = m_nodeEditorWindow.GetCurrentStory() ? true : false; // local copy because CloseProject() changes the status between BeginDisabled/EndDisabled
|
|
if (!init)
|
|
ImGui::BeginDisabled();
|
|
|
|
if (ImGui::MenuItem("Save project"))
|
|
{
|
|
m_appController.SaveProject();
|
|
}
|
|
|
|
if (ImGui::MenuItem("Close project"))
|
|
{
|
|
CloseProject();
|
|
}
|
|
|
|
if (ImGui::MenuItem("Project settings"))
|
|
{
|
|
m_projectPropertiesDialog.Show();
|
|
}
|
|
|
|
|
|
if (!init)
|
|
ImGui::EndDisabled();
|
|
|
|
ImGui::Separator();
|
|
|
|
if (ImGui::MenuItem("New module"))
|
|
{
|
|
// Current module project
|
|
CloseModule();
|
|
showNewProject = true;
|
|
NewModule();
|
|
}
|
|
|
|
if (ImGui::MenuItem("Save module (ctrl+s)"))
|
|
{
|
|
SaveModule();
|
|
}
|
|
|
|
if (ImGui::MenuItem("Close module"))
|
|
{
|
|
CloseModule();
|
|
}
|
|
|
|
if (ImGui::MenuItem("Module settings"))
|
|
{
|
|
m_modulePropertiesDialog.Show();
|
|
}
|
|
|
|
|
|
ImGui::EndMenu();
|
|
}
|
|
|
|
// if (ImGui::BeginMenu(TR("menu.view"))) {
|
|
// ImGui::MenuItem(TR("window.console"), nullptr, &m_showConsole);
|
|
// ImGui::MenuItem(TR("window.resources"), nullptr, &m_showResources);
|
|
// ImGui::MenuItem(TR("window.properties"), nullptr, &m_showProperties);
|
|
// ImGui::EndMenu();
|
|
// }
|
|
|
|
m_languageSelector.DrawMenu();
|
|
|
|
|
|
if (ImGui::BeginMenu("Help"))
|
|
{
|
|
if (ImGui::MenuItem("About"))
|
|
{
|
|
m_aboutDialog.Show();
|
|
}
|
|
ImGui::EndMenu();
|
|
}
|
|
|
|
|
|
height = ImGui::GetFrameHeight();
|
|
ImGui::EndMainMenuBar();
|
|
}
|
|
|
|
m_aboutDialog.Open();
|
|
if (m_nodeEditorWindow.GetCurrentStory())
|
|
{
|
|
m_projectPropertiesDialog.Open();
|
|
}
|
|
if (m_moduleEditorWindow.GetCurrentStory())
|
|
{
|
|
m_modulePropertiesDialog.Open();
|
|
}
|
|
|
|
return height;
|
|
}
|
|
|
|
bool MainWindow::Initialize()
|
|
{
|
|
bool success = false;
|
|
|
|
m_logger.RegisterSubject(shared_from_this());
|
|
|
|
// GUI Init
|
|
if (m_gui.Initialize())
|
|
{
|
|
// gui.ApplyTheme();
|
|
m_debuggerWindow.Initialize();
|
|
m_emulatorDock.Initialize();
|
|
m_nodeEditorWindow.Initialize();
|
|
m_moduleEditorWindow.Initialize();
|
|
m_propertiesWindow.Initialize();
|
|
m_libraryWindow.Initialize();
|
|
|
|
success = true;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
|
|
|
|
bool MainWindow::ShowQuitConfirm()
|
|
{
|
|
bool quitRequest = false;
|
|
// Always center this window when appearing
|
|
ImVec2 center = ImGui::GetMainViewport()->GetCenter();
|
|
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
|
|
// ImGui::SetNextWindowSize(ImVec2(200, 150));
|
|
if (ImGui::BeginPopupModal("QuitConfirm", NULL, ImGuiWindowFlags_AlwaysAutoResize))
|
|
{
|
|
ImGui::Text("Really quit without saving?");
|
|
ImGui::Separator();
|
|
|
|
if (ImGui::Button("OK", ImVec2(120, 0)))
|
|
{
|
|
quitRequest = true;
|
|
ImGui::CloseCurrentPopup();
|
|
}
|
|
ImGui::SetItemDefaultFocus();
|
|
ImGui::SameLine();
|
|
if (ImGui::Button("Cancel", ImVec2(120, 0)))
|
|
{
|
|
ImGui::CloseCurrentPopup();
|
|
}
|
|
ImGui::EndPopup();
|
|
}
|
|
|
|
return quitRequest;
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::OpenProject(const std::string &uuid)
|
|
{
|
|
auto p = dynamic_pointer_cast<StoryProject>(m_appController.GetCurrentProject());
|
|
m_nodeEditorWindow.Load(p);
|
|
auto proj = p->GetProjectFilePath();
|
|
// Add to recent if not exists
|
|
if (std::find(m_recentProjects.begin(), m_recentProjects.end(), proj) == m_recentProjects.end())
|
|
{
|
|
m_recentProjects.push_back(proj);
|
|
// Limit to 10 recent projects
|
|
if (m_recentProjects.size() > 10) {
|
|
m_recentProjects.pop_back();
|
|
}
|
|
|
|
// Save recent projects on disk
|
|
m_appController.SaveParams();
|
|
}
|
|
|
|
m_nodeEditorWindow.Enable();
|
|
|
|
m_emulatorDock.Enable();
|
|
m_consoleWindow.Enable();
|
|
m_debuggerWindow.Enable();
|
|
m_resourcesDock.Enable();
|
|
m_propertiesWindow.Enable();
|
|
m_variablesWindow.Enable();
|
|
m_cpuWindow.Enable();
|
|
|
|
RefreshProjectInformation();
|
|
}
|
|
|
|
void MainWindow::NewModule()
|
|
{
|
|
auto module = m_appController.NewModule();
|
|
|
|
if (module)
|
|
{
|
|
m_moduleEditorWindow.Load(module);
|
|
m_moduleEditorWindow.Enable();
|
|
m_logger.Log("New module created.");
|
|
}
|
|
else
|
|
{
|
|
m_logger.Log("Failed to create new module.");
|
|
}
|
|
}
|
|
|
|
void MainWindow::SaveModule()
|
|
{
|
|
m_moduleEditorWindow.SaveNodesToProject();
|
|
m_appController.SaveModule();
|
|
m_logger.Log("Modules saved");
|
|
m_toastNotifier.addToast("Module", "Module saved", ToastType::Success);
|
|
}
|
|
|
|
void MainWindow::OpenModule(const std::string &uuid)
|
|
{
|
|
auto module = m_appController.OpenModule(uuid);
|
|
if (module)
|
|
{
|
|
m_moduleEditorWindow.Load(module);
|
|
m_moduleEditorWindow.Enable();
|
|
|
|
m_emulatorDock.Enable();
|
|
m_consoleWindow.Enable();
|
|
m_debuggerWindow.Enable();
|
|
m_resourcesDock.Enable();
|
|
m_propertiesWindow.Enable();
|
|
m_variablesWindow.Enable();
|
|
m_cpuWindow.Enable();
|
|
}
|
|
}
|
|
|
|
|
|
void MainWindow::CloseProject()
|
|
{
|
|
// FIXME: not sure but if present, we lost some information in the library manager
|
|
|
|
// if (m_story)
|
|
// {
|
|
// m_story->Clear();
|
|
// m_story.reset();
|
|
// }
|
|
|
|
m_appController.CloseProject();
|
|
m_nodeEditorWindow.Clear();
|
|
m_nodeEditorWindow.Disable();
|
|
|
|
m_emulatorDock.ClearImage();
|
|
m_consoleWindow.ClearLog();
|
|
m_debuggerWindow.ClearErrors();
|
|
m_debuggerWindow.SetScript("");
|
|
|
|
m_emulatorDock.Disable();
|
|
m_debuggerWindow.Disable();
|
|
m_resourcesDock.Disable();
|
|
m_propertiesWindow.Disable();
|
|
m_variablesWindow.Disable();
|
|
m_cpuWindow.Disable();
|
|
|
|
RefreshProjectInformation();
|
|
}
|
|
|
|
|
|
void MainWindow::CloseModule()
|
|
{
|
|
m_moduleEditorWindow.Clear();
|
|
m_moduleEditorWindow.Disable();
|
|
|
|
}
|
|
|
|
|
|
void MainWindow::RefreshProjectInformation()
|
|
{
|
|
std::string fullText = "Story Editor " + LibraryManager::GetVersion();
|
|
|
|
auto p = m_nodeEditorWindow.GetCurrentStory();
|
|
if (p)
|
|
{
|
|
auto proj = dynamic_pointer_cast<StoryProject>(p);
|
|
if (proj)
|
|
{
|
|
fullText += " - " + proj->GetProjectFilePath();
|
|
}
|
|
}
|
|
m_gui.SetWindowTitle(fullText);
|
|
}
|
|
|
|
|
|
void MainWindow::DrawToolBar(float topPadding)
|
|
{
|
|
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration |
|
|
ImGuiWindowFlags_NoMove |
|
|
ImGuiWindowFlags_NoScrollbar |
|
|
ImGuiWindowFlags_NoScrollWithMouse |
|
|
ImGuiWindowFlags_NoDocking;
|
|
|
|
// Définit la taille et la position de la barre d'outils
|
|
ImVec2 size = ImVec2(60, ImGui::GetIO().DisplaySize.y - topPadding);
|
|
ImGui::SetNextWindowSize(size);
|
|
ImGui::SetNextWindowPos(ImVec2(0, topPadding));
|
|
|
|
// Style pour les coins arrondis des boutons
|
|
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 6.0f);
|
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(4, 4));
|
|
|
|
// Création de la fenêtre pour la barre d'outils
|
|
if (ImGui::Begin("ToolBar", nullptr, window_flags))
|
|
{
|
|
// Taille réduite des boutons
|
|
float buttonSize = 36.0f;
|
|
float windowWidth = ImGui::GetContentRegionAvail().x;
|
|
float offsetX = (windowWidth - buttonSize) * 0.5f;
|
|
|
|
// Style pour les couleurs des boutons
|
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.2f, 0.2f, 1.0f));
|
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.3f, 0.3f, 0.3f, 1.0f));
|
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.15f, 0.15f, 0.15f, 1.0f));
|
|
|
|
// Taille de fonte réduite pour les icônes
|
|
float old_size = ImGui::GetFont()->Scale;
|
|
ImGui::GetFont()->Scale *= 1.2f;
|
|
ImGui::PushFont(ImGui::GetFont());
|
|
|
|
// Bouton Stop Sound
|
|
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + offsetX);
|
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.9f, 0.3f, 0.3f, 1.0f));
|
|
if (ImGui::Button(ICON_MDI_SPEAKER_STOP "##stop_sound", ImVec2(buttonSize, buttonSize))) {
|
|
m_appController.StopAudio();
|
|
}
|
|
ImGui::PopStyleColor();
|
|
|
|
if (ImGui::IsItemHovered()) {
|
|
ImGui::SetTooltip("Stop Sound");
|
|
}
|
|
|
|
// Espacement vertical
|
|
ImGui::Dummy(ImVec2(0, 8));
|
|
|
|
// Bouton Build
|
|
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + offsetX);
|
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.3f, 0.8f, 0.9f, 1.0f));
|
|
if (ImGui::Button(ICON_MDI_HAMMER "##build_project", ImVec2(buttonSize, buttonSize))) {
|
|
// Compile story if window focused, otherwise module
|
|
if (m_nodeEditorWindow.IsFocused())
|
|
{
|
|
m_appController.CompileNodes(IStoryProject::PROJECT_TYPE_STORY);
|
|
}
|
|
else
|
|
{
|
|
m_appController.CompileNodes(IStoryProject::PROJECT_TYPE_MODULE);
|
|
}
|
|
}
|
|
ImGui::PopStyleColor();
|
|
|
|
if (ImGui::IsItemHovered()) {
|
|
ImGui::SetTooltip("Build Project");
|
|
}
|
|
|
|
// Restaurer le scale de la fonte
|
|
ImGui::GetFont()->Scale = old_size;
|
|
ImGui::PopFont();
|
|
|
|
// Pop les couleurs des boutons
|
|
ImGui::PopStyleColor(3); // Button, ButtonHovered, ButtonActive
|
|
|
|
// Fermeture de la fenêtre ImGui
|
|
ImGui::End();
|
|
}
|
|
|
|
// Pop les styles de frame
|
|
ImGui::PopStyleVar(2); // FrameRounding, FramePadding
|
|
}
|
|
|
|
#include "imgui_internal.h"
|
|
bool MainWindow::Loop()
|
|
{
|
|
// Main loop
|
|
static bool done = false;
|
|
|
|
|
|
Uint64 frameStart = SDL_GetTicks();
|
|
bool aboutToClose = m_gui.PollEvent();
|
|
|
|
m_gui.StartFrame();
|
|
|
|
auto vp = ImGui::GetMainViewport();
|
|
|
|
auto pos = vp->WorkPos;
|
|
auto size = vp->WorkSize;
|
|
pos.x += 60;
|
|
size.x -= 60;
|
|
vp->WorkPos = pos;
|
|
vp->WorkSize = size;
|
|
ImGui::DockSpaceOverViewport(0, vp);
|
|
float height = DrawMainMenuBar();
|
|
|
|
// ------------ Draw all windows
|
|
m_libraryWindow.Draw();
|
|
m_errorListDock.Draw();
|
|
|
|
if (m_appController.IsLibraryManagerInitialized())
|
|
{
|
|
bool nodeEditorFocused = m_nodeEditorWindow.IsFocused();
|
|
bool moduleEditorFocused = m_moduleEditorWindow.IsFocused();
|
|
|
|
m_consoleWindow.Draw();
|
|
m_emulatorDock.Draw();
|
|
m_debuggerWindow.Draw();
|
|
m_resourcesDock.Draw();
|
|
m_nodeEditorWindow.Draw();
|
|
m_moduleEditorWindow.Draw();
|
|
|
|
auto currentStory = nodeEditorFocused ? m_nodeEditorWindow.GetCurrentStory() : m_moduleEditorWindow.GetCurrentStory();
|
|
m_variablesWindow.Draw(currentStory);
|
|
m_cpuWindow.Draw();
|
|
|
|
static MemoryEditor mem_edit_1;
|
|
static uint32_t ram_size = 0;
|
|
static uint8_t *ram = m_appController.GetRam(ram_size);
|
|
mem_edit_1.DrawWindow("RAM view", ram, ram_size);
|
|
|
|
auto selectedNode = nodeEditorFocused ? m_nodeEditorWindow.GetSelectedNode() : m_moduleEditorWindow.GetSelectedNode();
|
|
m_propertiesWindow.SetSelectedNode(selectedNode);
|
|
|
|
m_propertiesWindow.Draw(currentStory);
|
|
|
|
|
|
// static ImGuiAxis toolbar2_axis = ImGuiAxis_Y;
|
|
// DockingToolbar("Toolbar2", &toolbar2_axis);
|
|
|
|
DrawToolBar(height);
|
|
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
if (io.KeyCtrl && ImGui::IsKeyPressed(ImGuiKey_S, false))
|
|
{
|
|
if (moduleEditorFocused && m_moduleEditorWindow.GetCurrentStory())
|
|
{
|
|
// Si l'éditeur de module a le focus, sauvegarder le module
|
|
m_appController.SaveModule();
|
|
m_toastNotifier.success("Module sauvegardé");
|
|
m_logger.Log("Module sauvegardé via Ctrl+S");
|
|
}
|
|
else if (m_nodeEditorWindow.GetCurrentStory())
|
|
{
|
|
// Sinon, sauvegarder l'histoire principale
|
|
m_appController.SaveProject();
|
|
m_toastNotifier.success("Projet sauvegardé");
|
|
m_logger.Log("Projet sauvegardé via Ctrl+S");
|
|
}
|
|
else
|
|
{
|
|
// Aucun projet ouvert
|
|
m_toastNotifier.warning("Aucun projet ou module à sauvegarder");
|
|
m_logger.Log("Tentative de sauvegarde sans projet ouvert", true);
|
|
}
|
|
}
|
|
|
|
if (io.KeyCtrl && ImGui::IsKeyPressed(ImGuiKey_B, false))
|
|
{
|
|
bool moduleEditorFocused = m_moduleEditorWindow.IsFocused();
|
|
|
|
if (moduleEditorFocused && m_moduleEditorWindow.GetCurrentStory())
|
|
{
|
|
m_logger.Log("Building module...");
|
|
m_appController.CompileNodes(IStoryProject::PROJECT_TYPE_MODULE);
|
|
}
|
|
else if (m_nodeEditorWindow.GetCurrentStory())
|
|
{
|
|
m_logger.Log("Building story...");
|
|
m_appController.CompileNodes(IStoryProject::PROJECT_TYPE_STORY);
|
|
}
|
|
}
|
|
}
|
|
|
|
m_aboutDialog.Draw();
|
|
m_projectPropertiesDialog.Draw();
|
|
m_modulePropertiesDialog.Draw();
|
|
|
|
m_toastNotifier.render();
|
|
|
|
if (aboutToClose)
|
|
{
|
|
ImGui::OpenPopup("QuitConfirm");
|
|
}
|
|
if (ShowQuitConfirm())
|
|
{
|
|
done = true;
|
|
}
|
|
|
|
m_gui.EndFrame();
|
|
|
|
|
|
// Rendering and event handling
|
|
Uint64 frameTime = SDL_GetTicks() - frameStart; // Temps écoulé pour la frame
|
|
|
|
if (frameTime < 32) { // 16 ms = 60 FPS
|
|
SDL_Delay(32 - frameTime); // Attendez pour compléter la frame
|
|
}
|
|
|
|
return done;
|
|
}
|
|
|
|
|
|
void MainWindow::LogEvent(const std::string &txt, bool critical)
|
|
{
|
|
m_consoleWindow.AddLog(txt, critical ? 1 : 0);
|
|
}
|
|
|
|
|
|
void MainWindow::OpenFunction(const std::string &uuid, const std::string &name)
|
|
{
|
|
m_nodeEditorWindow.OpenFunction(uuid, name);
|
|
}
|