mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 17:09:06 +01:00
Add VM console output !
This commit is contained in:
parent
07f4288748
commit
88b9bc6b3e
5 changed files with 157 additions and 41 deletions
|
|
@ -829,16 +829,22 @@ uint8_t AppController::Syscall(chip32_ctx_t *ctx, uint8_t code)
|
|||
{
|
||||
std::string text = GetStringFromMemory(ctx->registers[R0]);
|
||||
int arg_count = ctx->registers[R1];
|
||||
char working_buf[200] = {0};
|
||||
char working_buf[400] = {0};
|
||||
|
||||
// Simplified printf logic for logging
|
||||
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;
|
||||
case 0: strcpy(working_buf, text.c_str()); break;
|
||||
case 1: snprintf(working_buf, sizeof(working_buf), text.c_str(), ctx->registers[R2]); break;
|
||||
case 2: snprintf(working_buf, sizeof(working_buf), text.c_str(), ctx->registers[R2], ctx->registers[R3]); break;
|
||||
case 3: snprintf(working_buf, sizeof(working_buf), text.c_str(), ctx->registers[R2], ctx->registers[R3], ctx->registers[R4]); break;
|
||||
default: m_logger.Log("Printf with unsupported arg_count: " + std::to_string(arg_count) + " text: " + text, true); break;
|
||||
}
|
||||
|
||||
// Send event to UI
|
||||
auto evObj = std::make_shared<VmStateEvent>();
|
||||
evObj->type = VmStateEvent::Type::PrintEvent;
|
||||
evObj->printOutput = working_buf;
|
||||
m_eventBus.Emit(evObj);
|
||||
}
|
||||
else if (code == 5) // WAIT (sleep)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,32 +7,35 @@ EmulatorDock::EmulatorDock(IStoryManager &proj)
|
|||
: WindowBase("Emulator")
|
||||
, m_story(proj)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void EmulatorDock::Initialize()
|
||||
{
|
||||
}
|
||||
|
||||
void EmulatorDock::AddVmOutput(const std::string& text)
|
||||
{
|
||||
std::scoped_lock<std::mutex> lock(m_vmOutputMutex);
|
||||
m_vmOutput.push_back({text, 0});
|
||||
|
||||
// Limiter à 1000 lignes
|
||||
if (m_vmOutput.size() > 1000) {
|
||||
m_vmOutput.erase(m_vmOutput.begin());
|
||||
}
|
||||
}
|
||||
|
||||
void EmulatorDock::ClearVmOutput()
|
||||
{
|
||||
std::scoped_lock<std::mutex> lock(m_vmOutputMutex);
|
||||
m_vmOutput.clear();
|
||||
}
|
||||
|
||||
void EmulatorDock::Draw()
|
||||
{
|
||||
// if (!IsVisible())
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
|
||||
static ImVec2 size(320.0f, 240.0f);
|
||||
|
||||
WindowBase::BeginDraw();
|
||||
ImGui::SetWindowSize(ImVec2(626, 744), ImGuiCond_FirstUseEver);
|
||||
|
||||
// ImGui::Image((void*)(intptr_t)my_image_texture, ImVec2(313, 367));
|
||||
|
||||
// float sz = ImGui::GetTextLineHeight();
|
||||
|
||||
// ===== ÉCRAN DE L'ÉMULATEUR =====
|
||||
ImVec2 p = ImGui::GetCursorScreenPos();
|
||||
|
||||
if (m_image.Valid())
|
||||
|
|
@ -41,44 +44,59 @@ void EmulatorDock::Draw()
|
|||
}
|
||||
else
|
||||
{
|
||||
ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 320, p.y + 240), ImGui::GetColorU32(ImVec4(1.0, 1.0, 1.0, 1.0)));
|
||||
ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 320, p.y + 240),
|
||||
ImGui::GetColorU32(ImVec4(0.1f, 0.1f, 0.1f, 1.0f)));
|
||||
|
||||
// Texte centré "No Image"
|
||||
ImGui::SetCursorScreenPos(ImVec2(p.x + 110, p.y + 110));
|
||||
ImGui::TextDisabled("No Image");
|
||||
}
|
||||
|
||||
ImGui::SetCursorScreenPos(ImVec2(p.x, p.y + 244));
|
||||
|
||||
// ===== BOUTONS DE CONTRÔLE =====
|
||||
float old_size = ImGui::GetFont()->Scale;
|
||||
ImGui::GetFont()->Scale *= 2;
|
||||
|
||||
ImGui::PushFont(ImGui::GetFont());
|
||||
|
||||
if (ImGui::Button(ICON_MDI_CHECK_CIRCLE_OUTLINE, ImVec2(50, 50)))
|
||||
{
|
||||
m_story.Ok();
|
||||
}
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("OK");
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(ICON_MDI_PAUSE, ImVec2(50, 50)))
|
||||
{
|
||||
m_story.Pause();
|
||||
}
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("Pause");
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(ICON_MDI_HOME, ImVec2(50, 50)))
|
||||
{
|
||||
m_story.Home();
|
||||
}
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("Home");
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(ICON_MDI_ARROW_LEFT_BOLD_CIRCLE_OUTLINE, ImVec2(50, 50)))
|
||||
{
|
||||
m_story.Previous();
|
||||
}
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("Previous");
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(ICON_MDI_ARROW_RIGHT_BOLD_CIRCLE_OUTLINE, ImVec2(50, 50)))
|
||||
{
|
||||
m_story.Next();
|
||||
}
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("Next");
|
||||
|
||||
ImGui::GetFont()->Scale = old_size;
|
||||
ImGui::PopFont();
|
||||
|
||||
// ===== CONTRÔLES DE SCRIPT ET DEBUG =====
|
||||
ImGui::SeparatorText("Script control and debug");
|
||||
|
||||
if (ImGui::Button("Build nodes"))
|
||||
|
|
@ -96,19 +114,16 @@ void EmulatorDock::Draw()
|
|||
m_story.Log("Play story");
|
||||
m_story.Play();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Stop"))
|
||||
{
|
||||
m_story.Log("Stop story");
|
||||
m_story.Stop();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::Text("VM state: %s", m_story.VmState().c_str());
|
||||
|
||||
|
||||
// ===== BOUTONS DE CHARGEMENT =====
|
||||
if (ImGui::Button("Load binary story (.c32)"))
|
||||
{
|
||||
IGFD::FileDialogConfig config;
|
||||
|
|
@ -130,46 +145,108 @@ void EmulatorDock::Draw()
|
|||
config.countSelectionMax = 1;
|
||||
config.flags = ImGuiFileDialogFlags_Modal;
|
||||
ImGuiFileDialog::Instance()->OpenDialog("SetSourceScriptDlgKey",
|
||||
"Choose a binary story",
|
||||
"Choose a source file",
|
||||
".chip32",
|
||||
config
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------- Load Binary story
|
||||
// ===== DIALOGS =====
|
||||
// Load Binary story
|
||||
if (ImGuiFileDialog::Instance()->Display("LoadBinaryStoryDlgKey"))
|
||||
{
|
||||
if (ImGuiFileDialog::Instance()->IsOk())
|
||||
{
|
||||
std::string filePathName = ImGuiFileDialog::Instance()->GetFilePathName();
|
||||
std::string filePath = ImGuiFileDialog::Instance()->GetCurrentPath();
|
||||
std::string filter = ImGuiFileDialog::Instance()->GetCurrentFilter();
|
||||
|
||||
m_story.LoadBinaryStory(filePathName);
|
||||
}
|
||||
// close
|
||||
ImGuiFileDialog::Instance()->Close();
|
||||
}
|
||||
|
||||
// ---------------- External source file
|
||||
// External source file
|
||||
if (ImGuiFileDialog::Instance()->Display("SetSourceScriptDlgKey"))
|
||||
{
|
||||
if (ImGuiFileDialog::Instance()->IsOk())
|
||||
{
|
||||
std::string filePathName = ImGuiFileDialog::Instance()->GetFilePathName();
|
||||
std::string filePath = ImGuiFileDialog::Instance()->GetCurrentPath();
|
||||
std::string filter = ImGuiFileDialog::Instance()->GetCurrentFilter();
|
||||
|
||||
m_story.SetExternalSourceFile(filePathName);
|
||||
}
|
||||
// close
|
||||
ImGuiFileDialog::Instance()->Close();
|
||||
}
|
||||
|
||||
// ===== CONSOLE VM (NOUVEAU) =====
|
||||
DrawVmConsole();
|
||||
|
||||
WindowBase::EndDraw();
|
||||
}
|
||||
|
||||
void EmulatorDock::DrawVmConsole()
|
||||
{
|
||||
ImGui::Separator();
|
||||
|
||||
// Header de la console
|
||||
ImGui::Text(ICON_MDI_CONSOLE " VM Output");
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::Checkbox("Auto-scroll##vm", &m_autoScrollVm);
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::SmallButton("Clear##vm"))
|
||||
{
|
||||
ClearVmOutput();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
// Zone de console scrollable
|
||||
ImGui::BeginChild("VmConsoleRegion", ImVec2(0, 150), true,
|
||||
ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_AlwaysVerticalScrollbar);
|
||||
|
||||
{
|
||||
std::scoped_lock<std::mutex> lock(m_vmOutputMutex);
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 2));
|
||||
ImGui::PushFont(ImGui::GetFont()); // Police monospace si disponible
|
||||
|
||||
if (m_vmOutput.empty())
|
||||
{
|
||||
ImGui::TextDisabled("(No VM output yet - run the program to see print statements)");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto& entry : m_vmOutput)
|
||||
{
|
||||
// Colorer les erreurs en rouge
|
||||
if (entry.type == 1) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.4f, 0.4f, 1.0f));
|
||||
}
|
||||
|
||||
ImGui::TextUnformatted(entry.text.c_str());
|
||||
|
||||
if (entry.type == 1) {
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::PopFont();
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
|
||||
// Auto-scroll intelligent (comme la console principale)
|
||||
float scrollY = ImGui::GetScrollY();
|
||||
float scrollMaxY = ImGui::GetScrollMaxY();
|
||||
const float BOTTOM_THRESHOLD = 5.0f;
|
||||
bool wasAtBottom = (scrollMaxY == 0) || (scrollY >= scrollMaxY - BOTTOM_THRESHOLD);
|
||||
|
||||
if (m_autoScrollVm && wasAtBottom)
|
||||
{
|
||||
ImGui::SetScrollHereY(1.0f);
|
||||
}
|
||||
|
||||
ImGui::EndChild();
|
||||
}
|
||||
|
||||
void EmulatorDock::ClearImage()
|
||||
{
|
||||
m_image.Clear();
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@
|
|||
#include "window_base.h"
|
||||
#include "i_story_manager.h"
|
||||
#include "gui.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
|
||||
class EmulatorDock : public WindowBase
|
||||
{
|
||||
|
|
@ -15,9 +18,24 @@ public:
|
|||
void ClearImage();
|
||||
void SetImage(const std::string &image);
|
||||
|
||||
// NEW: Console VM pour afficher la sortie des prints
|
||||
void AddVmOutput(const std::string& text);
|
||||
void ClearVmOutput();
|
||||
|
||||
private:
|
||||
IStoryManager &m_story;
|
||||
Gui::Image m_image;
|
||||
std::string m_imageFileName;
|
||||
};
|
||||
|
||||
// NEW: Buffer pour la console VM
|
||||
struct VmOutputEntry {
|
||||
std::string text;
|
||||
uint32_t type; // 0 = normal, 1 = error
|
||||
};
|
||||
|
||||
std::vector<VmOutputEntry> m_vmOutput;
|
||||
std::mutex m_vmOutputMutex;
|
||||
bool m_autoScrollVm = true;
|
||||
|
||||
void DrawVmConsole();
|
||||
};
|
||||
|
|
@ -13,11 +13,15 @@ struct VmStateEvent : public Event
|
|||
int currentLine;
|
||||
chip32_result_t vmResult;
|
||||
std::set<int> breakpoints;
|
||||
std::string printOutput;
|
||||
// Ajoutez d'autres données nécessaires, ex: std::vector<std::shared_ptr<Variable>> variables;
|
||||
|
||||
// Constructeur pour faciliter la création de l'événement
|
||||
VmStateEvent(const chip32_ctx_t& ctx, int line, chip32_result_t result, const std::set<int>& bps)
|
||||
: vmContext(ctx), currentLine(line), vmResult(result), breakpoints(bps) {}
|
||||
enum class Type
|
||||
{
|
||||
PrintEvent,
|
||||
};
|
||||
|
||||
Type type;
|
||||
};
|
||||
|
||||
class OpenProjectEvent : public Event
|
||||
|
|
|
|||
|
|
@ -83,6 +83,15 @@ MainWindow::MainWindow(ILogger& logger, EventBus& eventBus, AppController& appCo
|
|||
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()) {
|
||||
|
|
@ -103,6 +112,8 @@ MainWindow::MainWindow(ILogger& logger, EventBus& eventBus, AppController& appCo
|
|||
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
|
||||
|
|
|
|||
Loading…
Reference in a new issue