wip move out logic from ui
Some checks failed
Build-StoryEditor / build_linux (push) Has been cancelled
Build-StoryEditor / build_win32 (push) Has been cancelled
Deploy-Documentation / deploy (push) Has been cancelled

This commit is contained in:
anthony@rabine.fr 2025-08-15 21:52:08 +02:00
parent 8a2f70ea01
commit 143bbfa8bc
14 changed files with 491 additions and 552 deletions

View file

@ -33,12 +33,15 @@ public:
virtual ~IStoryManager() {}
virtual void OpenProject(const std::string &uuid) = 0;
virtual void SaveProject() = 0;
virtual void ImportProject(const std::string &fileName, int format) = 0;
virtual void Log(const std::string &txt, bool critical = false) = 0;
virtual void PlaySoundFile(const std::string &fileName) = 0;
virtual std::string BuildFullAssetsPath(const std::string_view fileName) const = 0;
virtual void OpenFunction(const std::string &uuid, const std::string &name) = 0;
virtual std::shared_ptr<IStoryProject> GetCurrentProject() = 0;
// Modules
virtual void OpenModule(const std::string &uuid) = 0;

View file

@ -13,14 +13,30 @@ public:
{
PROJECT_TYPE_STORY = 0,
PROJECT_TYPE_MODULE = 1,
PROJECT_TYPE_PRIMITIVE = 2
};
virtual ~IStoryProject() {};
virtual std::string GetName() const = 0;
virtual std::string GetDescription() const = 0;
virtual Type GetProjectType() const = 0;
virtual bool IsModule() const = 0;
virtual std::string GetUuid() const = 0;
virtual std::string GetTitleImage() const = 0;
virtual std::string GetTitleSound() const = 0;
virtual void SetTitleImage(const std::string &titleImage) = 0;
virtual void SetTitleSound(const std::string &titleSound) = 0;
virtual void SetDescription(const std::string &description) = 0;
virtual void SetProjectType(Type type) = 0;
virtual void SetImageFormat(Resource::ImageFormat format) = 0;
virtual void SetSoundFormat(Resource::SoundFormat format) = 0;
virtual void SetDisplayFormat(int w, int h) = 0;
virtual void SetName(const std::string &name) = 0;
virtual void SetUuid(const std::string &uuid) = 0;
};

View file

@ -36,8 +36,50 @@ public:
return m_uuid;
}
virtual std::string GetTitleImage() const {
return ""; // No title image by default
}
virtual std::string GetTitleSound() const {
return ""; // No title sound by default
}
virtual Type GetProjectType() const {
return Type::PROJECT_TYPE_PRIMITIVE;
}
virtual void SetTitleImage(const std::string &titleImage) {
(void)titleImage; // No title image to set
}
virtual void SetTitleSound(const std::string &titleSound) {
(void)titleSound; // No title sound to set
}
virtual void SetDescription(const std::string &description) {
m_description = description;
}
virtual void SetProjectType(Type type) {
(void)type; // Project type is fixed for primitives
}
virtual void SetImageFormat(Resource::ImageFormat format) {
(void)format; // Image format is fixed for primitives
}
virtual void SetSoundFormat(Resource::SoundFormat format) {
(void)format; // Sound format is fixed for primitives
}
virtual void SetDisplayFormat(int w, int h) {
(void)w; // Display width is fixed for primitives
(void)h; // Display height is fixed for primitives
}
virtual void SetName(const std::string &name) {
m_name = name;
}
virtual void SetUuid(const std::string &uuid) {
m_uuid = uuid;
}
private:
std::string m_name;
std::string m_description;
std::string m_uuid;
std::string m_titleImage;
std::string m_titleSound;
};

View file

@ -61,16 +61,9 @@ public:
void Select(bool selected) { m_selected = selected; }
bool IsSelected() const { return m_selected; }
void SetImageFormat(Resource::ImageFormat format);
void SetSoundFormat(Resource::SoundFormat format);
void SetDisplayFormat(int w, int h);
void SetName(const std::string &name) { m_name = name; }
void SetUuid(const std::string &uuid) { m_uuid = uuid; }
std::string GetProjectFilePath() const;
std::string GetWorkingDir() const;
virtual std::string GetName() const override { return m_name; }
std::string GetUuid() const { return m_uuid; }
std::string GetDescription() const { return m_description; }
uint32_t GetVersion() const { return m_version; }
@ -83,14 +76,11 @@ public:
void SetTitleSound(const std::string &titleSound);
void SetDescription(const std::string &description) { m_description = description; }
std::string GetTitleImage() const { return m_titleImage; }
std::string GetTitleSound() const { return m_titleSound; }
// Initialize with an existing project
bool IsInitialized() const { return m_initialized; }
bool IsModule() const override { return m_projectType == IStoryProject::PROJECT_TYPE_MODULE; }
bool IsStory() const { return m_projectType == IStoryProject::PROJECT_TYPE_STORY; }
void SetProjectType(IStoryProject::Type type) { m_projectType = type; }
bool ParseStoryInformation(nlohmann::json &j);
@ -99,6 +89,16 @@ public:
virtual int OutputsCount(const std::string &nodeId);
StoryOptions GetOptions() { return m_storyOptions; }
virtual bool UseResource(const std::string &label);
virtual std::string GetName() const override { return m_name; }
virtual std::string GetTitleImage() const override { return m_titleImage; }
virtual std::string GetTitleSound() const override { return m_titleSound; }
virtual void SetProjectType(IStoryProject::Type type) override { m_projectType = type; }
virtual void SetImageFormat(Resource::ImageFormat format) override;
virtual void SetSoundFormat(Resource::SoundFormat format) override;
virtual void SetDisplayFormat(int w, int h) override;
virtual void SetName(const std::string &name) override { m_name = name; }
virtual void SetUuid(const std::string &uuid) override { m_uuid = uuid; }
virtual Type GetProjectType() const override { return m_projectType; }
// Node interaction
std::shared_ptr<StoryPage> CreatePage(const std::string &uuid);

View file

@ -125,7 +125,6 @@ set(SRCS
src/windows/window_base.cpp
src/windows/console_window.cpp
src/windows/library_window.cpp
src/windows/resources_window.cpp
src/windows/properties_window.cpp
src/windows/debugger_window.cpp
src/windows/cpu_window.cpp
@ -133,6 +132,7 @@ set(SRCS
## Docks
src/docks/emulator_dock.cpp
src/docks/resources_dock.cpp
# src/node_editor/media_node_widget.cpp
src/node_editor/base_node_widget.cpp

View file

@ -62,33 +62,6 @@
#endif
// Implémentation du callback pour le syscall de la VM
// C'est un peu délicat avec une fonction membre.
// Une solution courante est d'utiliser un 'trampoline' ou std::function.
// Pour ce projet, nous allons faire une adaptation simple en passant 'this'
// via un mécanisme global ou un wrapper. L'approche originale de MainWindow
// utilisait une classe Callback statique, que nous allons adapter ici.
// Classe trampoline pour les syscalls de la VM
// Ceci est une version simplifiée. Dans un système plus robuste, vous pourriez
// vouloir un registre de callbacks ou une approche plus souple.
class SyscallTrampoline
{
public:
static AppController* s_instance; // Pointer vers l'instance de AppController
static uint8_t Callback(chip32_ctx_t *ctx, uint8_t code)
{
if (s_instance)
{
return s_instance->Syscall(ctx, code);
}
return SYSCALL_RET_OK; // Ou gérer l'erreur
}
};
AppController* SyscallTrampoline::s_instance = nullptr;
AppController::AppController(ILogger& logger, EventBus& eventBus)
: m_logger(logger)
, m_eventBus(eventBus) // m_eventBus pour les événements
@ -348,6 +321,26 @@ void AppController::BuildCode(std::shared_ptr<StoryProject> story, bool compileo
}
}
void AppController::BuildCode(bool compileonly)
{
m_currentCode = SysLib::ReadFile(m_externalSourceFileName);
// m_debuggerWindow.SetScript(m_currentCode); // FIXME: GUI event
Build(compileonly);
}
void AppController::BuildNodes(bool compileonly)
{
if (m_story->GenerateScript(m_currentCode))
{
// m_debuggerWindow.SetScript(m_currentCode); // FIXME: GUI event
Build(compileonly);
}
}
void AppController::SetExternalSourceFile(const std::string &filename)
{
m_externalSourceFileName = filename;
@ -762,11 +755,11 @@ uint8_t AppController::Syscall(chip32_ctx_t *ctx, uint8_t code)
std::string imageFile = m_story->BuildFullAssetsPath(GetStringFromMemory(ctx->registers[R0]));
m_logger.Log("Image: " + imageFile);
// Ici, vous notifieriez la fenêtre de l'émulateur
// m_emulatorWindow.SetImage(imageFile); // Ceci est une dépendance GUI
// m_emulatorDock.SetImage(imageFile); // Ceci est une dépendance GUI
}
else
{
// m_emulatorWindow.ClearImage(); // Dépendance GUI
// m_emulatorDock.ClearImage(); // Dépendance GUI
}
if (ctx->registers[R1] != 0)
@ -865,6 +858,7 @@ void AppController::CloseProject()
m_story->Clear(); // Clear story resources/data
m_story.reset(); // Release shared_ptr
}
m_resources.Clear();
// Clear VM state
m_dbg.run_result = VM_FINISHED;
@ -875,24 +869,21 @@ void AppController::CloseProject()
m_resources.Clear(); // Clear loaded resources
m_eventQueue.clear(); // Clear any pending VM events
// Notify GUI (or specific windows) to clear/disable project-related data
// These would be events or direct calls from AppController to GUI objects
// m_nodeEditorWindow.Clear();
// m_emulatorWindow.ClearImage();
// m_consoleWindow.ClearLog();
// m_debuggerWindow.ClearErrors();
// m_debuggerWindow.SetScript("");
// m_nodeEditorWindow.Disable();
// m_emulatorWindow.Disable();
// m_debuggerWindow.Disable();
// m_resourcesWindow.Disable();
// m_PropertiesWindow.Disable();
// m_variablesWindow.Disable();
// m_cpuWindow.Disable();
m_logger.Log("Project closed.");
}
void AppController::SaveProject()
{
if (m_story)
{
m_story->Save(m_resources);
m_libraryManager.Scan(); // Add new project to library
m_logger.Log("Project saved: " + m_story->GetProjectFilePath());
} else {
m_logger.Log("No project open to save.", true);
}
}
void AppController::NewModule()
{
m_module = m_nodesFactory.NewModule();
@ -941,7 +932,7 @@ void AppController::CloseModule()
void AppController::ImportProject(const std::string &filePathName, int format)
{
(void) format; // Not used in the original snippet but kept for signature.
PackArchive archive(*this, m_nodesFactory); // PackArchive constructor might need an ILogger, adjust if needed
PackArchive archive(m_logger, m_nodesFactory); // PackArchive constructor might need an ILogger, adjust if needed
auto ext = SysLib::GetFileExtension(filePathName);
auto filename = SysLib::GetFileName(filePathName);
@ -962,12 +953,7 @@ void AppController::ImportProject(const std::string &filePathName, int format)
}
}
std::pair<FilterIterator, FilterIterator> AppController::Images()
std::shared_ptr<IStoryProject> AppController::GetCurrentProject()
{
return m_resources.Images();
}
std::pair<FilterIterator, FilterIterator> AppController::Sounds()
{
return m_resources.Sounds();
return m_story; // Retourne le projet actuel
}

View file

@ -48,6 +48,7 @@ public:
// Initialisation de l'AppController
bool Initialize();
std::shared_ptr<StoryProject> NewProject() { return m_libraryManager.NewProject(); }
void OpenProject(const std::string &uuid);
void ImportProject(const std::string &fileName, int format);
void Log(const std::string &txt, bool critical = false) override;
@ -56,6 +57,7 @@ public:
void OpenFunction(const std::string &uuid, const std::string &name);
void NewStory();
void CloseProject();
void SaveProject();
void NewModule();
void SaveModule();
void CloseModule();
@ -87,6 +89,9 @@ public:
virtual void Next() override;
virtual void Previous() override;
virtual std::string VmState() const override;
virtual void BuildNodes(bool compileonly);
virtual void BuildCode(bool compileonly);
virtual std::shared_ptr<IStoryProject> GetCurrentProject() override;
// --- Fonctions de IAudioEvent ---
virtual void EndOfAudio() override;
@ -117,9 +122,6 @@ public:
// Méthode pour mettre à jour l'état de la vue VM (peut être un événement notifié à la GUI)
void UpdateVmView();
virtual std::pair<FilterIterator, FilterIterator> Images() override;
virtual std::pair<FilterIterator, FilterIterator> Sounds() override;
private:
ILogger& m_logger; // Référence au logger pour les messages métier
EventBus& m_eventBus; // Bus d'événements pour la communication entre composants

View file

@ -2,16 +2,12 @@
#ifndef ABOUT_DIALOG_H
#define ABOUT_DIALOG_H
#include "imgui.h" // Nécessaire pour ImGui::BeginPopupModal, ImGui::Text, etc.
#include "dialog_base.h" // Pour DialogBase
#include <string> // Pour std::string
#include "library_manager.h" // Pour LibraryManager::GetVersion()
#include <SDL3/SDL.h> // Pour SDL_GetPlatform(), SDL_GetNumLogicalCPUCores(), SDL_GetSystemRAM()
#include <SDL3/SDL.h>
// Il est important de noter que cette classe AboutDialog
// dépendra de ImGui et de SDL pour afficher les informations
// système, comme c'est le cas dans le code original de MainWindow.
class AboutDialog
class AboutDialog : public DialogBase
{
public:
AboutDialog() = default;
@ -24,7 +20,7 @@ public:
ImVec2 center = ImGui::GetMainViewport()->GetCenter();
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
if (ImGui::BeginPopupModal("AboutPopup", nullptr, ImGuiWindowFlags_AlwaysAutoResize))
if (ImGui::BeginPopupModal(GetTitle(), nullptr, ImGuiWindowFlags_AlwaysAutoResize))
{
ImGui::Text("Story Editor - v%s", LibraryManager::GetVersion().c_str());
ImGui::Text("http://www.openstoryteller.org");
@ -41,33 +37,19 @@ public:
if (ImGui::Button("Close", ImVec2(100, 35)))
{
ImGui::CloseCurrentPopup();
Reset(); // Cache le popup après la fermeture
}
ImGui::EndPopup();
}
}
// Ouvre le popup "About".
// Doit être appelée lorsque l'utilisateur clique sur "About" dans le menu.
void Open()
{
if (m_showAboutPopup)
{
ImGui::OpenPopup("AboutPopup");
}
}
void Show()
{
m_showAboutPopup = true;
}
void Reset()
{
m_showAboutPopup = false;
}
private:
bool m_showAboutPopup = false; // Indique si le popup "About" doit être affiché
// Implémentation de la méthode virtuelle pure GetTitle()
const char* GetTitle() const override
{
return "AboutPopup";
}
};
#endif // ABOUT_DIALOG_H

View file

@ -0,0 +1,49 @@
// dialog_base.h
#ifndef DIALOG_BASE_H
#define DIALOG_BASE_H
#include "imgui.h" // Nécessaire pour ImGui::BeginPopupModal
class DialogBase
{
public:
virtual ~DialogBase() = default;
// Affiche le contenu de la fenêtre de dialogue.
// Cette méthode est virtuelle pure et doit être implémentée par les classes dérivées.
virtual void Draw() = 0;
// Ouvre le popup de la fenêtre de dialogue.
// Note: Ceci ne rend pas le dialogue visible tant que Draw() n'est pas appelé.
// Cette méthode est utilisée pour les popups modaux ImGui.
void Open()
{
if (m_show)
{
ImGui::OpenPopup(GetTitle());
}
}
// Rend le dialogue visible au prochain appel de Draw().
void Show()
{
m_show = true;
m_firstOpen = true;
}
// Cache le dialogue au prochain appel de Draw().
void Reset()
{
m_show = false;
m_firstOpen = false;
}
protected:
// Permet d'accéder au titre pour l'ouverture du popup.
virtual const char* GetTitle() const = 0;
bool m_show = false;
bool m_firstOpen = false;
};
#endif // DIALOG_BASE_H

View file

@ -0,0 +1,269 @@
// about_dialog.h
#ifndef PROJECT_PROPERTIES_DIALOG_H
#define PROJECT_PROPERTIES_DIALOG_H
#include "dialog_base.h" // Pour DialogBase
#include <string> // Pour std::string
#include "library_manager.h" // Pour LibraryManager::GetVersion()
#include <SDL3/SDL.h> // Pour SDL_GetPlatform(), SDL_GetNumLogicalCPUCores(), SDL_GetSystemRAM()
#include "i_story_manager.h"
#include "IconsMaterialDesignIcons.h"
class ProjectPropertiesDialog : public DialogBase
{
public:
ProjectPropertiesDialog(IStoryManager &story, ResourceManager &resources)
: m_storyManager(story)
, m_resources(resources)
{
m_project_name[0] = '\0';
}
// Affiche le popup "Project Properties".
// Doit être appelée à chaque frame dans la boucle de rendu ImGui.
void Draw()
{
auto story = m_storyManager.GetCurrentProject();
if (story)
{
if (m_firstOpen)
{
ImVec2 center = ImGui::GetMainViewport()->GetCenter();
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
m_firstOpen = false;
std::size_t length = story->GetName().copy(m_project_name, sizeof(m_project_name));
m_project_name[length] = '\0';
}
DrawContent(story);
}
else
{
Reset();
return;
}
}
private:
IStoryManager &m_storyManager;
ResourceManager &m_resources;
char m_project_name[256] = "";
// Implémentation de la méthode virtuelle pure GetTitle()
const char* GetTitle() const override
{
return "ProjectPropertiesPopup";
}
void DrawContent(std::shared_ptr<IStoryProject> story)
{
if (ImGui::BeginPopupModal(GetTitle(), NULL, ImGuiWindowFlags_AlwaysAutoResize))
{
ImGui::Text("Project name: "); ImGui::SameLine();
ImGui::InputTextWithHint("##project_name", "Project name", m_project_name, IM_ARRAYSIZE(m_project_name));
ImGui::Text("Size of display screen: ");
ImGui::SameLine();
static ImGuiComboFlags flags = 0;
static int display_item_current_idx = 0; // Here we store our selection data as an index.
static int image_item_current_idx = 0; // Here we store our selection data as an index.
static int sound_item_current_idx = 0; // Here we store our selection data as an index.
{
// Using the generic BeginCombo() API, you have full control over how to display the combo contents.
// (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
// stored in the object itself, etc.)
const char* display_items[] = { "320x240", "640x480" };
const char* combo_preview_value = display_items[display_item_current_idx]; // Pass in the preview value visible before opening the combo (it could be anything)
if (ImGui::BeginCombo("##ComboDisplay", combo_preview_value, flags))
{
for (int n = 0; n < IM_ARRAYSIZE(display_items); n++)
{
const bool is_selected = (display_item_current_idx == n);
if (ImGui::Selectable(display_items[n], is_selected))
display_item_current_idx = n;
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
}
ImGui::Text("Image format: ");
ImGui::SameLine();
{
// Using the generic BeginCombo() API, you have full control over how to display the combo contents.
// (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
// stored in the object itself, etc.)
const char* image_items[] = { "Native (no conversion)", "QOIF (Quite Ok Image Format" };
const char* image_combo_preview_value = image_items[image_item_current_idx]; // Pass in the preview value visible before opening the combo (it could be anything)
if (ImGui::BeginCombo("##ComboImage", image_combo_preview_value, flags))
{
for (int n = 0; n < IM_ARRAYSIZE(image_items); n++)
{
const bool is_selected = (image_item_current_idx == n);
if (ImGui::Selectable(image_items[n], is_selected))
image_item_current_idx = n;
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
}
ImGui::Text("Sound format: ");
ImGui::SameLine();
{
// Using the generic BeginCombo() API, you have full control over how to display the combo contents.
// (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
// stored in the object itself, etc.)
const char* sound_items[] = { "Native (no conversion)", "WAV (16-bit stereo)", "QOAF (Quite Ok Audio Format" };
const char* sound_combo_preview_value = sound_items[sound_item_current_idx]; // Pass in the preview value visible before opening the combo (it could be anything)
if (ImGui::BeginCombo("##ComboSound", sound_combo_preview_value, flags))
{
for (int n = 0; n < IM_ARRAYSIZE(sound_items); n++)
{
const bool is_selected = (sound_item_current_idx == n);
if (ImGui::Selectable(sound_items[n], is_selected))
sound_item_current_idx = n;
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
}
ImGui::AlignTextToFramePadding();
ImGui::Text("Image");
ImGui::SameLine();
ImGui::Text("%s", story->GetTitleImage().c_str());
ImGui::SameLine();
static bool isImage = true;
if (ImGui::Button("Select...##image")) {
ImGui::OpenPopup("popup_button");
isImage = true;
}
ImGui::SameLine();
if (ImGui::Button(ICON_MDI_CLOSE_BOX_OUTLINE "##delimage")) {
story->SetTitleImage("");
}
ImGui::AlignTextToFramePadding();
ImGui::Text("Sound");
ImGui::SameLine();
ImGui::Text("%s", story->GetTitleSound().c_str());
ImGui::SameLine();
if (ImGui::Button("Play " ICON_MDI_PLAY))
{
m_storyManager.PlaySoundFile(m_storyManager.BuildFullAssetsPath(story->GetTitleSound()));
}
ImGui::SameLine();
if (ImGui::Button("Select...##sound")) {
ImGui::OpenPopup("popup_button");
isImage = false;
}
ImGui::SameLine();
if (ImGui::Button(ICON_MDI_CLOSE_BOX_OUTLINE "##delsound")) {
story->SetTitleSound("");
}
if (ImGui::BeginPopup("popup_button")) {
ImGui::SeparatorText(isImage ? "Images" : "Sounds");
auto [filtreDebut, filtreFin] = isImage ? m_resources.Images() : m_resources.Sounds();
int n = 0;
for (auto it = filtreDebut; it != filtreFin; ++it, n++)
{
if (ImGui::Selectable((*it)->file.c_str()))
{
if (isImage)
{
story->SetTitleImage((*it)->file);
}
else
{
story->SetTitleSound((*it)->file);
}
}
}
ImGui::EndPopup(); // Note this does not do anything to the popup open/close state. It just terminates the content declaration.
}
auto GetImageFormat = [](int idx) -> Resource::ImageFormat
{
Resource::ImageFormat img{Resource::IMG_SAME_FORMAT};
if (idx < Resource::IMG_FORMAT_COUNT) {
img = static_cast<Resource::ImageFormat>(idx);
}
return img;
};
auto GetSoundFormat = [](int idx) -> Resource::SoundFormat {
Resource::SoundFormat img{Resource::SND_FORMAT_WAV};
if (idx < Resource::IMG_FORMAT_COUNT) {
img = static_cast<Resource::SoundFormat>(idx);
}
return img;
};
if (ImGui::Button("OK", ImVec2(120, 0)))
{
if (display_item_current_idx == 0)
{
story->SetDisplayFormat(320, 240);
}
else
{
story->SetDisplayFormat(640, 480);
}
story->SetImageFormat(GetImageFormat(image_item_current_idx));
story->SetSoundFormat(GetSoundFormat(sound_item_current_idx));
story->SetName(m_project_name);
m_storyManager.SaveProject();
ImGui::CloseCurrentPopup();
}
ImGui::SetItemDefaultFocus();
ImGui::SameLine();
if (ImGui::Button("Cancel", ImVec2(120, 0)))
{
ImGui::CloseCurrentPopup();
Reset();
}
ImGui::EndPopup();
}
}
};
#endif // PROJECT_PROPERTIES_DIALOG_H

View file

@ -1,4 +1,4 @@
#include "resources_window.h"
#include "resources_dock.h"
#include "imgui.h"
#include <filesystem>
#include <memory>
@ -7,19 +7,20 @@
//static thread_pool pool;
ResourcesWindow::ResourcesWindow(ResourceManager &resources)
ResourcesDock::ResourcesDock(ResourceManager &resources, IStoryManager &manager)
: WindowBase("Resources")
, m_resources(resources)
, m_storyManager(manager)
{
}
ResourcesWindow::~ResourcesWindow()
ResourcesDock::~ResourcesDock()
{
}
void ResourcesWindow::ChooseFile()
void ResourcesDock::ChooseFile()
{
static const char * soundFormats = ".wav,.mp3,.ogg,.flac";
static const char * imagesFormats = ".bmp,.png,.jpg";
@ -29,7 +30,7 @@ void ResourcesWindow::ChooseFile()
m_showImportDialog = false;
// open Dialog Simple
IGFD::FileDialogConfig config;
config.path = m_resources.BuildFullAssetsPath("");
config.path = m_storyManager.BuildFullAssetsPath("");
config.countSelectionMax = 1;
config.sidePaneWidth = 350.0f;
config.flags = ImGuiFileDialogFlags_Modal;
@ -49,7 +50,7 @@ void ResourcesWindow::ChooseFile()
std::filesystem::path p(filePathName);
std::filesystem::path p2 = m_resources.BuildFullAssetsPath( p.filename().generic_string());
std::filesystem::path p2 = m_storyManager.BuildFullAssetsPath( p.filename().generic_string());
bool allowCopy = true;
// On ne copie pas le fichier sur lui-même
@ -81,7 +82,7 @@ void ResourcesWindow::ChooseFile()
}
void ResourcesWindow::Draw()
void ResourcesDock::Draw()
{
WindowBase::BeginDraw();
@ -168,7 +169,7 @@ void ResourcesWindow::Draw()
ImGui::TableNextColumn();
if (ImGui::SmallButton("Delete"))
{
m_resources.DeleteResource(it);
m_resources.Delete(it);
quitLoop = true;
}
ImGui::PopID();

View file

@ -4,15 +4,16 @@
#include "window_base.h"
#include "resource_manager.h"
class ResourcesWindow : public WindowBase
class ResourcesDock : public WindowBase
{
public:
ResourcesWindow(ResourceManager &resources);
~ResourcesWindow();
ResourcesDock(ResourceManager &resources, IStoryManager &manager);
~ResourcesDock();
virtual void Draw() override;
private:
ResourceManager &m_resources;
IStoryManager &m_storyManager;
bool m_showImportDialog{false};
bool m_soundFile{false};

View file

@ -29,14 +29,15 @@ MainWindow::MainWindow(ILogger& logger, EventBus& eventBus, AppController& appCo
: m_logger(logger)
, m_eventBus(eventBus)
, m_appController(appController)
, m_emulatorWindow(appController)
, m_emulatorDock(appController)
, m_debuggerWindow(appController)
, m_cpuWindow(appController)
, m_resourcesWindow(appController.GetResourceManager())
, m_nodeEditorWindow(appController)
, m_moduleEditorWindow(appController)
, m_libraryWindow(appController)
, m_resourcesDock(appController.GetResourceManager(), appController)
, m_nodeEditorWindow(appController, appController.GetNodesFactory(), IStoryProject::PROJECT_TYPE_STORY)
, m_moduleEditorWindow(appController, appController.GetNodesFactory(), IStoryProject::PROJECT_TYPE_MODULE)
, m_libraryWindow(appController, appController.GetLibraryManager(), appController.GetNodesFactory())
, m_variablesWindow(appController)
, m_projectPropertiesDialog(appController, appController.GetResourceManager())
{
logger.RegisterSubject(shared_from_this());
@ -65,126 +66,8 @@ MainWindow::~MainWindow()
}
std::string MainWindow::GetStringFromMemory(uint32_t addr)
{
char strBuf[100];
bool isRam = addr & 0x80000000;
addr &= 0xFFFF; // mask the RAM/ROM bit, ensure 16-bit addressing
if (isRam) {
strcpy(&strBuf[0], (const char *)&m_chip32_ctx.ram.mem[addr]);
} else {
strcpy(&strBuf[0], (const char *)&m_chip32_ctx.rom.mem[addr]);
}
return strBuf;
}
void MainWindow::StepInstruction()
{
m_dbg.run_result = chip32_step(&m_chip32_ctx);
UpdateVmView();
}
uint8_t MainWindow::Syscall(chip32_ctx_t *ctx, uint8_t code)
{
uint8_t retCode = SYSCALL_RET_OK;
m_logger.Log("SYSCALL: " + std::to_string(code));
// Media
if (code == 1) // Execute media
{
if (m_chip32_ctx.registers[R0] != 0)
{
// image file name address is in R0
std::string imageFile = m_story->BuildFullAssetsPath(GetStringFromMemory(m_chip32_ctx.registers[R0]));
m_logger.Log("Image: " + imageFile);
m_emulatorWindow.SetImage(imageFile);
}
else
{
m_emulatorWindow.ClearImage();
}
if (m_chip32_ctx.registers[R1] != 0)
{
// sound file name address is in R1
std::string soundFile = m_story->BuildFullAssetsPath(GetStringFromMemory(m_chip32_ctx.registers[R1]));
m_logger.Log("Sound: " + soundFile);
m_player.Play(soundFile);
}
retCode = SYSCALL_RET_OK; // We continue execution, script must wait for event if necessary (end of audio)
}
// WAIT EVENT bits:
// 0: block
// 1: OK button
// 2: home button
// 3: pause button
// 4: rotary left
// 5: rotary right
else if (code == 2) // Wait for event
{
// Empty event queue
m_eventQueue.clear();
// Event mask is located in R0
m_dbg.event_mask = m_chip32_ctx.registers[R0];
// optional timeout is located in R1
// if timeout is set to zero, wait for infinite and beyond
retCode = SYSCALL_RET_WAIT_EV; // set the VM in pause
}
else if (code == 3)
{
// FIXME
}
else // Printf
if (code == 4)
{
// In R0: string with escaped characters
// R1: Number of arguments
// R2, R3 ... arguments
// Integers: stored in registers by values
// Strings: first character address in register
std::string text = GetStringFromMemory(ctx->registers[R0]);
int arg_count = ctx->registers[R1];
char working_buf[200] = {0};
switch(arg_count){
case 0:
m_logger.Log(text);
break;
case 1:
snprintf(working_buf, sizeof(working_buf), text.c_str(), ctx->registers[R2]);
m_logger.Log(working_buf);
break;
case 2:
snprintf(working_buf, sizeof(working_buf), text.c_str(), ctx->registers[R2], ctx->registers[R3]);
m_logger.Log(working_buf);
break;
case 3:
snprintf(working_buf, sizeof(working_buf), text.c_str(), ctx->registers[R2], ctx->registers[R3], ctx->registers[R4]);
m_logger.Log(working_buf);
break;
default:
break;
}
}
// WAIT (sleep)
else if (code == 5)
{
std::this_thread::sleep_for(std::chrono::milliseconds(ctx->registers[R0]));
}
return retCode;
}
float MainWindow::DrawMainMenuBar()
{
bool showParameters = false;
bool showNewProject = false;
bool showOpenProject = false;
@ -199,12 +82,11 @@ float MainWindow::DrawMainMenuBar()
{
CloseProject();
m_story = m_libraryManager.NewProject();
m_story = m_appController.NewProject();
if (m_story)
{
SaveProject();
m_libraryManager.Scan(); // Add new project to library
m_appController.SaveProject();
OpenProject(m_story->GetUuid());
}
}
@ -247,11 +129,9 @@ float MainWindow::DrawMainMenuBar()
ImGui::Separator();
if (ImGui::MenuItem("Save project"))
{
SaveProject();
m_appController.SaveProject();
}
if (ImGui::MenuItem("Close project"))
{
CloseProject();
@ -259,7 +139,7 @@ float MainWindow::DrawMainMenuBar()
if (ImGui::MenuItem("Project settings"))
{
showParameters = true;
m_projectPropertiesDialog.Show();
}
if (ImGui::MenuItem("Close module"))
@ -288,17 +168,9 @@ float MainWindow::DrawMainMenuBar()
}
m_aboutDialog.Open();
if (showParameters)
{
if (m_story)
{
ImGui::OpenPopup("ProjectPropertiesPopup");
// Init some variables
std::size_t length = m_story->GetName().copy(m_project_name, sizeof(m_project_name));
m_project_name[length] = '\0';
}
m_projectPropertiesDialog.Open();
}
return height;
@ -307,18 +179,13 @@ float MainWindow::DrawMainMenuBar()
bool MainWindow::Initialize()
{
bool success = false;
LoadParams();
m_nodesFactory.ScanModules();
// GUI Init
if (m_gui.Initialize())
{
m_player.Initialize(); // Initialize audio after GUI (uses SDL)
// gui.ApplyTheme();
m_debuggerWindow.Initialize();
m_emulatorWindow.Initialize();
m_emulatorDock.Initialize();
m_nodeEditorWindow.Initialize();
m_moduleEditorWindow.Initialize();
m_PropertiesWindow.Initialize();
@ -362,224 +229,6 @@ bool MainWindow::ShowQuitConfirm()
}
void MainWindow::ProjectPropertiesPopup()
{
// Always center this window when appearing
ImVec2 center = ImGui::GetMainViewport()->GetCenter();
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
if (ImGui::BeginPopupModal("ProjectPropertiesPopup", NULL, ImGuiWindowFlags_AlwaysAutoResize))
{
ImGui::Text("Project name: "); ImGui::SameLine();
ImGui::InputTextWithHint("##project_name", "Project name", m_project_name, IM_ARRAYSIZE(m_project_name));
ImGui::Text("Size of display screen: ");
ImGui::SameLine();
static ImGuiComboFlags flags = 0;
static int display_item_current_idx = 0; // Here we store our selection data as an index.
static int image_item_current_idx = 0; // Here we store our selection data as an index.
static int sound_item_current_idx = 0; // Here we store our selection data as an index.
{
// Using the generic BeginCombo() API, you have full control over how to display the combo contents.
// (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
// stored in the object itself, etc.)
const char* display_items[] = { "320x240", "640x480" };
const char* combo_preview_value = display_items[display_item_current_idx]; // Pass in the preview value visible before opening the combo (it could be anything)
if (ImGui::BeginCombo("##ComboDisplay", combo_preview_value, flags))
{
for (int n = 0; n < IM_ARRAYSIZE(display_items); n++)
{
const bool is_selected = (display_item_current_idx == n);
if (ImGui::Selectable(display_items[n], is_selected))
display_item_current_idx = n;
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
}
ImGui::Text("Image format: ");
ImGui::SameLine();
{
// Using the generic BeginCombo() API, you have full control over how to display the combo contents.
// (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
// stored in the object itself, etc.)
const char* image_items[] = { "Native (no conversion)", "QOIF (Quite Ok Image Format" };
const char* image_combo_preview_value = image_items[image_item_current_idx]; // Pass in the preview value visible before opening the combo (it could be anything)
if (ImGui::BeginCombo("##ComboImage", image_combo_preview_value, flags))
{
for (int n = 0; n < IM_ARRAYSIZE(image_items); n++)
{
const bool is_selected = (image_item_current_idx == n);
if (ImGui::Selectable(image_items[n], is_selected))
image_item_current_idx = n;
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
}
ImGui::Text("Sound format: ");
ImGui::SameLine();
{
// Using the generic BeginCombo() API, you have full control over how to display the combo contents.
// (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
// stored in the object itself, etc.)
const char* sound_items[] = { "Native (no conversion)", "WAV (16-bit stereo)", "QOAF (Quite Ok Audio Format" };
const char* sound_combo_preview_value = sound_items[sound_item_current_idx]; // Pass in the preview value visible before opening the combo (it could be anything)
if (ImGui::BeginCombo("##ComboSound", sound_combo_preview_value, flags))
{
for (int n = 0; n < IM_ARRAYSIZE(sound_items); n++)
{
const bool is_selected = (sound_item_current_idx == n);
if (ImGui::Selectable(sound_items[n], is_selected))
sound_item_current_idx = n;
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
}
ImGui::AlignTextToFramePadding();
ImGui::Text("Image");
ImGui::SameLine();
ImGui::Text("%s", m_story->GetTitleImage().c_str());
ImGui::SameLine();
static bool isImage = true;
if (ImGui::Button("Select...##image")) {
ImGui::OpenPopup("popup_button");
isImage = true;
}
ImGui::SameLine();
if (ImGui::Button(ICON_MDI_CLOSE_BOX_OUTLINE "##delimage")) {
m_story->SetTitleImage("");
}
ImGui::AlignTextToFramePadding();
ImGui::Text("Sound");
ImGui::SameLine();
ImGui::Text("%s", m_story->GetTitleSound().c_str());
ImGui::SameLine();
if (ImGui::Button("Play " ICON_MDI_PLAY))
{
PlaySoundFile(BuildFullAssetsPath(m_story->GetTitleSound()));
}
ImGui::SameLine();
if (ImGui::Button("Select...##sound")) {
ImGui::OpenPopup("popup_button");
isImage = false;
}
ImGui::SameLine();
if (ImGui::Button(ICON_MDI_CLOSE_BOX_OUTLINE "##delsound")) {
m_story->SetTitleSound("");
}
if (ImGui::BeginPopup("popup_button")) {
ImGui::SeparatorText(isImage ? "Images" : "Sounds");
auto [filtreDebut, filtreFin] = isImage ? Images() : Sounds();
int n = 0;
for (auto it = filtreDebut; it != filtreFin; ++it, n++)
{
if (ImGui::Selectable((*it)->file.c_str()))
{
if (isImage)
{
m_story->SetTitleImage((*it)->file);
}
else
{
m_story->SetTitleSound((*it)->file);
}
}
}
ImGui::EndPopup(); // Note this does not do anything to the popup open/close state. It just terminates the content declaration.
}
auto GetImageFormat = [](int idx) -> Resource::ImageFormat
{
Resource::ImageFormat img{Resource::IMG_SAME_FORMAT};
if (idx < Resource::IMG_FORMAT_COUNT) {
img = static_cast<Resource::ImageFormat>(idx);
}
return img;
};
auto GetSoundFormat = [](int idx) -> Resource::SoundFormat {
Resource::SoundFormat img{Resource::SND_FORMAT_WAV};
if (idx < Resource::IMG_FORMAT_COUNT) {
img = static_cast<Resource::SoundFormat>(idx);
}
return img;
};
if (ImGui::Button("OK", ImVec2(120, 0)))
{
if (display_item_current_idx == 0)
{
m_story->SetDisplayFormat(320, 240);
}
else
{
m_story->SetDisplayFormat(640, 480);
}
m_story->SetImageFormat(GetImageFormat(image_item_current_idx));
m_story->SetSoundFormat(GetSoundFormat(sound_item_current_idx));
m_story->SetName(m_project_name);
SaveProject();
ImGui::CloseCurrentPopup();
}
ImGui::SetItemDefaultFocus();
ImGui::SameLine();
if (ImGui::Button("Cancel", ImVec2(120, 0)))
{
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
}
void MainWindow::SaveProject()
{
nlohmann::json model;
m_story->Save(m_resources);
m_logger.Log("Project saved");
}
void MainWindow::OpenProject(const std::string &uuid)
{
@ -600,10 +249,10 @@ void MainWindow::OpenProject(const std::string &uuid)
m_nodeEditorWindow.Enable();
m_emulatorWindow.Enable();
m_emulatorDock.Enable();
m_consoleWindow.Enable();
m_debuggerWindow.Enable();
m_resourcesWindow.Enable();
m_resourcesDock.Enable();
m_PropertiesWindow.Enable();
m_variablesWindow.Enable();
m_cpuWindow.Enable();
@ -613,7 +262,7 @@ void MainWindow::OpenProject(const std::string &uuid)
void MainWindow::NewModule()
{
auto module = m_nodesFactory.NewModule();
auto module = m_appController.NewModule();
m_moduleEditorWindow.Load(module);
m_moduleEditorWindow.Enable();
@ -622,7 +271,7 @@ void MainWindow::NewModule()
void MainWindow::SaveModule()
{
m_nodesFactory.SaveAllModules(m_resources);;
m_appController.SaveAllModules(m_resources);;
m_logger.Log("Modules saved");
}
@ -656,18 +305,18 @@ void MainWindow::CloseProject()
// m_story.reset();
// }
m_resources.Clear();
m_appController.CloseProject();
m_nodeEditorWindow.Clear();
m_nodeEditorWindow.Disable();
m_emulatorWindow.ClearImage();
m_emulatorDock.ClearImage();
m_consoleWindow.ClearLog();
m_debuggerWindow.ClearErrors();
m_debuggerWindow.SetScript("");
m_emulatorWindow.Disable();
m_emulatorDock.Disable();
m_debuggerWindow.Disable();
m_resourcesWindow.Disable();
m_resourcesDock.Disable();
m_PropertiesWindow.Disable();
m_variablesWindow.Disable();
m_cpuWindow.Disable();
@ -787,9 +436,9 @@ void MainWindow::Loop()
if (m_libraryManager.IsInitialized())
{
m_consoleWindow.Draw();
m_emulatorWindow.Draw();
m_emulatorDock.Draw();
m_debuggerWindow.Draw();
m_resourcesWindow.Draw();
m_resourcesDock.Draw();
m_nodeEditorWindow.Draw();
m_moduleEditorWindow.Draw();
m_variablesWindow.Draw();
@ -809,7 +458,7 @@ void MainWindow::Loop()
}
m_aboutDialog.Draw();
ProjectPropertiesPopup();
m_projectPropertiesDialog.Draw();
if (aboutToClose)
{
@ -843,59 +492,12 @@ void MainWindow::LogEvent(const std::string &txt, bool critical)
}
std::string MainWindow::BuildFullAssetsPath(const std::string_view fileName) const
{
return m_story->BuildFullAssetsPath(fileName);
}
void MainWindow::OpenFunction(const std::string &uuid, const std::string &name)
{
m_nodeEditorWindow.OpenFunction(uuid, name);
}
void MainWindow::LoadBinaryStory(const std::string &filename)
{
FILE *fp = fopen(filename.c_str(), "rb");
if (fp != NULL)
{
fseek(fp, 0L, SEEK_END);
long int sz = ftell(fp);
fseek(fp, 0L, SEEK_SET);
if (sz <= m_chip32_ctx.rom.size)
{
size_t sizeRead = fread(m_chip32_ctx.rom.mem, sz, 1, fp);
if (sizeRead == sz)
{
m_dbg.run_result = VM_READY;
chip32_initialize(&m_chip32_ctx);
m_logger.Log("Loaded binary file: " + filename);
}
else
{
m_logger.Log("Failed to load binary file", true);
}
}
fclose(fp);
}
}
void MainWindow::BuildNodes(bool compileonly)
{
if (m_story->GenerateScript(m_currentCode))
{
m_debuggerWindow.SetScript(m_currentCode);
Build(compileonly);
}
}
void MainWindow::Build(bool compileonly)
{
m_dbg.run_result = VM_FINISHED;
@ -936,13 +538,6 @@ void MainWindow::Build(bool compileonly)
}
void MainWindow::BuildCode(bool compileonly)
{
m_currentCode = SysLib::ReadFile(m_externalSourceFileName);
m_debuggerWindow.SetScript(m_currentCode);
Build(compileonly);
}
void MainWindow::SetExternalSourceFile(const std::string &filename)
{
m_externalSourceFileName = filename;

View file

@ -10,7 +10,7 @@
#include "console_window.h"
#include "debugger_window.h"
#include "emulator_dock.h"
#include "resources_window.h"
#include "resources_dock.h"
#include "node_editor_window.h"
#include "properties_window.h"
#include "variables_window.h"
@ -18,6 +18,7 @@
#include "cpu_window.h"
// Dialogs
#include "about_dialog.h"
#include "project_properties_dialog.h"
#include "event_bus.h"
#include "app_controller.h"
@ -46,14 +47,11 @@ private:
std::vector<std::string> m_recentProjects;
Gui m_gui;
EmulatorDock m_emulatorWindow;
EmulatorDock m_emulatorDock;
ConsoleWindow m_consoleWindow;
DebuggerWindow m_debuggerWindow;
CpuWindow m_cpuWindow;
char m_project_name[256] = "";
ResourcesWindow m_resourcesWindow;
ResourcesDock m_resourcesDock;
NodeEditorWindow m_nodeEditorWindow;
NodeEditorWindow m_moduleEditorWindow;
PropertiesWindow m_PropertiesWindow;
@ -62,12 +60,12 @@ private:
// Dialogs
AboutDialog m_aboutDialog;
ProjectPropertiesDialog m_projectPropertiesDialog;
// From IStoryManager (proxy to StoryProject class)
void OpenProject(const std::string &uuid);
void SaveProject();
void CloseProject();
void OpenFunction(const std::string &uuid, const std::string &name);
void OpenModule(const std::string &uuid);
void NewModule();
void SaveModule();
@ -77,18 +75,13 @@ private:
virtual void LogEvent(const std::string &txt, bool critical) override;
void LoadParams();
void RefreshProjectInformation();
float DrawMainMenuBar();
bool ShowQuitConfirm();
void DrawToolBar(float topPadding);
void UpdateVmView();
uint8_t Syscall(chip32_ctx_t *ctx, uint8_t code);
std::string GetStringFromMemory(uint32_t addr);
void ProcessStory();
void StepInstruction();
void RefreshProjectInformation();
void ProjectPropertiesPopup();
void RefreshProjectIœnformation();
void Build(bool compileonly);
};