load/save module success, better toaster

This commit is contained in:
anthony@rabine.fr 2025-10-01 17:25:56 +02:00
parent 883257fd78
commit 479497f1df
12 changed files with 370 additions and 123 deletions

View file

@ -42,9 +42,6 @@ public:
virtual std::shared_ptr<IStoryProject> GetCurrentProject() = 0;
// Modules
virtual std::shared_ptr<IStoryProject> OpenModule(const std::string &uuid) = 0;
// Node interaction
virtual void CompileNodes(bool compileonly) = 0;
virtual void BuildCode(bool compileonly) = 0;

View file

@ -114,14 +114,19 @@ public:
void SaveAllModules(ResourceManager &manager)
{
for (const auto &entry : m_registry)
for (const auto &n : m_registry)
{
// Only modules
auto module = std::dynamic_pointer_cast<StoryProject>(entry.second.first);
if (module)
auto p = dynamic_cast<StoryProject*>(n.second.first.get());
if (p)
{
module->Save(manager);
p->Save(manager);
}
// Only modules
// auto module = std::dynamic_pointer_cast<StoryProject>(entry.second.first);
// if (module)
// {
// module->Save(manager);
// }
}
}

View file

@ -637,10 +637,6 @@ void StoryProject::Save(ResourceManager &manager)
void StoryProject::Clear()
{
m_uuid = "";
m_working_dir = "";
m_project_file_path = "";
m_initialized = false;
m_variables.clear();
m_pages.clear();
}

View file

@ -1,6 +1,6 @@
[Window][WindowOverViewport_11111111]
Pos=60,26
Size=1220,694
Size=1343,777
Collapsed=0
[Window][Debug##Default]
@ -9,32 +9,32 @@ Size=400,400
Collapsed=0
[Window][Library Manager]
Pos=591,26
Size=689,224
Pos=714,26
Size=689,465
Collapsed=0
DockId=0x00000003,0
[Window][Console]
Pos=60,533
Size=610,187
Size=672,270
Collapsed=0
DockId=0x00000004,0
[Window][Emulator]
Pos=591,26
Size=689,224
Pos=714,26
Size=689,465
Collapsed=0
DockId=0x00000003,5
[Window][Code viewer]
Pos=591,26
Size=689,224
Pos=714,26
Size=689,465
Collapsed=0
DockId=0x00000003,4
[Window][Resources]
Pos=591,26
Size=689,224
Pos=714,26
Size=689,465
Collapsed=0
DockId=0x00000003,1
@ -50,36 +50,36 @@ Size=150,42
Collapsed=0
[Window][Variables]
Pos=672,533
Size=608,187
Pos=734,533
Size=669,270
Collapsed=0
DockId=0x00000005,0
[Window][CPU]
Pos=591,26
Size=689,224
Pos=714,26
Size=689,465
Collapsed=0
DockId=0x00000003,2
[Window][RAM view]
Pos=591,26
Size=689,224
Pos=714,26
Size=689,465
Collapsed=0
DockId=0x00000003,3
[Window][Properties]
Pos=591,252
Size=689,279
Pos=714,493
Size=689,38
Collapsed=0
DockId=0x00000006,0
[Window][ToolBar]
Pos=0,26
Size=60,694
Size=60,777
Collapsed=0
[Window][QuitConfirm]
Pos=508,312
Pos=569,353
Size=264,96
Collapsed=0
@ -90,15 +90,15 @@ Collapsed=0
[Window][Module editor]
Pos=60,26
Size=529,505
Size=652,505
Collapsed=0
DockId=0x00000001,1
DockId=0x00000001,0
[Window][Story editor]
Pos=60,26
Size=529,505
Size=652,505
Collapsed=0
DockId=0x00000001,0
DockId=0x00000001,1
[Window][Choose a library directory##ChooseLibraryDirDialog]
Pos=490,260
@ -142,13 +142,13 @@ RefScale=20
Column 0 Sort=0v
[Docking][Data]
DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=60,26 Size=1220,694 Split=Y
DockNode ID=0x00000007 Parent=0x08BD597D SizeRef=1220,505 Split=X
DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=60,26 Size=1343,777 Split=Y
DockNode ID=0x00000007 Parent=0x08BD597D SizeRef=1220,422 Split=X
DockNode ID=0x00000001 Parent=0x00000007 SizeRef=721,694 CentralNode=1 Selected=0x93ADCAAB
DockNode ID=0x00000002 Parent=0x00000007 SizeRef=689,694 Split=Y Selected=0x52EB28B5
DockNode ID=0x00000003 Parent=0x00000002 SizeRef=718,224 Selected=0x63869CAF
DockNode ID=0x00000006 Parent=0x00000002 SizeRef=718,279 Selected=0x8C72BEA8
DockNode ID=0x00000008 Parent=0x08BD597D SizeRef=1220,187 Split=X Selected=0xEA83D666
DockNode ID=0x00000003 Parent=0x00000002 SizeRef=718,388 Selected=0x63869CAF
DockNode ID=0x00000006 Parent=0x00000002 SizeRef=718,32 Selected=0x8C72BEA8
DockNode ID=0x00000008 Parent=0x08BD597D SizeRef=1220,270 Split=X Selected=0xEA83D666
DockNode ID=0x00000004 Parent=0x00000008 SizeRef=610,192 Selected=0xEA83D666
DockNode ID=0x00000005 Parent=0x00000008 SizeRef=608,192 Selected=0x6DE9B20C

View file

@ -880,23 +880,21 @@ void AppController::SaveModule()
m_logger.Log("Modules saved.");
}
std::shared_ptr<IStoryProject> AppController::OpenModule(const std::string &uuid)
std::shared_ptr<StoryProject> AppController::OpenModule(const std::string &uuid)
{
m_module = m_nodesFactory.GetModule(uuid);
if (!m_module)
{
m_eventBus.Emit(std::make_shared<GenericResultEvent>(false, "Cannot find module: " + uuid));
m_logger.Log("Cannot find module: " + uuid, true);
}
else if (m_module->Load(m_resources, m_nodesFactory))
{
m_eventBus.Emit(std::make_shared<ModuleEvent>(ModuleEvent::Type::Opened, uuid));
m_logger.Log("Open module success: " + uuid);
m_eventBus.Emit(std::make_shared<GenericResultEvent>(true, "Open module success: " + uuid));
}
else
{
m_eventBus.Emit(std::make_shared<GenericResultEvent>(false, "Failed to open module: " + uuid));
m_logger.Log("Open module error: " + uuid, true);
}
return m_module;
}

View file

@ -61,7 +61,7 @@ public:
std::shared_ptr<StoryProject> NewModule();
void SaveModule();
void CloseModule();
std::shared_ptr<IStoryProject> OpenModule(const std::string &uuid);
std::shared_ptr<StoryProject> OpenModule(const std::string &uuid);
void OpenStory(const std::string &path = "");
void SaveStory(const std::string &path = "");
void ExportStory(const std::string &filename);

View file

@ -60,7 +60,7 @@ class ModuleEvent : public Event
public:
enum class Type
{
Opened,
Open,
Closed,
};

View file

@ -26,6 +26,8 @@ struct Toast {
class ImGuiToastNotifier {
private:
std::vector<Toast> toasts;
const float TOAST_WIDTH = 300.0f;
const float TOAST_PADDING = 10.0f;
public:
void addToast(const std::string& title, const std::string& text, ToastType type, float duration = 3.0f) {
@ -37,56 +39,101 @@ public:
return;
}
ImGuiIO& io = ImGui::GetIO();
ImVec2 viewport_pos = ImGui::GetMainViewport()->Pos;
ImVec2 viewport_size = ImGui::GetMainViewport()->Size;
ImVec2 window_pos = ImVec2(viewport_pos.x + viewport_size.x - 10.0f, viewport_pos.y + 10.0f);
ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, ImVec2(1.0f, 0.0f));
// Get the main viewport work area (excludes menu bar, status bar, etc.)
ImGuiViewport* viewport = ImGui::GetMainViewport();
ImVec2 work_pos = viewport->WorkPos;
ImVec2 work_size = viewport->WorkSize;
ImGui::SetNextWindowBgAlpha(0.75f);
if (ImGui::Begin("##ToastWindow", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing)) {
// Position in top-right corner of the work area
ImVec2 window_pos = ImVec2(
work_pos.x + work_size.x - TOAST_PADDING,
work_pos.y + TOAST_PADDING
);
ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, ImVec2(1.0f, 0.0f));
ImGui::SetNextWindowSize(ImVec2(TOAST_WIDTH, 0), ImGuiCond_Always);
ImGui::SetNextWindowBgAlpha(0.90f);
// Add NoNav to prevent interfering with other windows
ImGuiWindowFlags window_flags =
ImGuiWindowFlags_NoDecoration |
ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoSavedSettings |
ImGuiWindowFlags_NoFocusOnAppearing |
ImGuiWindowFlags_NoNav |
ImGuiWindowFlags_AlwaysAutoResize;
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(12, 12));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8, 8));
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 6.0f);
if (ImGui::Begin("##ToastWindow", nullptr, window_flags)) {
auto now = std::chrono::steady_clock::now();
auto it = toasts.begin();
while (it != toasts.end()) {
auto elapsed = std::chrono::duration<float>(now - it->startTime).count();
if (elapsed > it->duration) {
it = toasts.erase(it);
continue;
}
// Calculate fade out effect in the last 0.5 seconds
float alpha = 1.0f;
if (elapsed > it->duration - 0.5f) {
alpha = (it->duration - elapsed) / 0.5f;
}
ImGui::PushID(it->title.c_str());
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, alpha);
ImVec4 color;
const char* icon;
switch (it->type) {
case Success:
color = ImVec4(0.18f, 0.80f, 0.44f, 1.0f);
icon = ICON_FA_CHECK_CIRCLE; // Font Awesome 5 success icon (check-circle)
icon = ICON_FA_CHECK_CIRCLE;
break;
case Warning:
color = ImVec4(1.0f, 0.84f, 0.0f, 1.0f);
icon = ICON_FA_EXCLAMATION_TRIANGLE; // Font Awesome 5 warning icon (exclamation-triangle)
icon = ICON_FA_EXCLAMATION_TRIANGLE;
break;
case Error:
color = ImVec4(0.94f, 0.31f, 0.31f, 1.0f);
icon = ICON_FA_TIMES_CIRCLE; // Font Awesome 5 error icon (times-circle)
icon = ICON_FA_TIMES_CIRCLE;
break;
}
// Draw icon and title on the same line
ImGui::PushStyleColor(ImGuiCol_Text, color);
ImGui::Text("%s", icon);
ImGui::PopStyleColor();
ImGui::SameLine();
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[0]); // Use default font for title
ImGui::TextUnformatted(it->title.c_str());
ImGui::TextWrapped("%s", it->text.c_str());
ImGui::PopFont();
// Draw message text with wrapping
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + TOAST_WIDTH - 24.0f);
ImGui::TextUnformatted(it->text.c_str());
ImGui::PopTextWrapPos();
ImGui::PopStyleVar(); // Alpha
// Add separator between toasts if not the last one
if (std::next(it) != toasts.end()) {
ImGui::Separator();
}
ImGui::PopID();
++it;
}
ImGui::End();
}
ImGui::PopStyleVar(3); // WindowPadding, ItemSpacing, WindowRounding
}
};

View file

@ -46,7 +46,7 @@ MainWindow::MainWindow(ILogger& logger, EventBus& eventBus, AppController& appCo
, 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())
, m_libraryWindow(appController, appController.GetLibraryManager(), appController.GetNodesFactory(), eventBus)
, m_projectPropertiesDialog(appController, appController.GetResourceManager())
{
CloseProject();
@ -96,7 +96,7 @@ MainWindow::MainWindow(ILogger& logger, EventBus& eventBus, AppController& appCo
});
m_eventBus.Subscribe<ModuleEvent>([this](const ModuleEvent &event) {
if (event.GetType() == ModuleEvent::Type::Opened) {
if (event.GetType() == ModuleEvent::Type::Open) {
OpenModule(event.GetUuid());
} else if (event.GetType() == ModuleEvent::Type::Closed) {
CloseModule();
@ -327,6 +327,7 @@ void MainWindow::NewModule()
void MainWindow::SaveModule()
{
m_moduleEditorWindow.SaveNodesToProject();
m_appController.SaveModule();
m_logger.Log("Modules saved");
m_toastNotifier.addToast("Module", "Module saved", ToastType::Success);
@ -334,7 +335,7 @@ void MainWindow::SaveModule()
void MainWindow::OpenModule(const std::string &uuid)
{
auto module = m_appController.GetCurrentModule();
auto module = m_appController.OpenModule(uuid);
if (module)
{
m_moduleEditorWindow.Load(module);

View file

@ -103,54 +103,141 @@ void NodeEditorWindow::Load(std::shared_ptr<StoryProject> story)
{
m_story = story;
if (m_story)
if (!m_story)
{
try {
BaseNodeWidget::InitId();
InitializeProject();
auto [node_begin, node_end] = m_story->Nodes(m_currentPage->Uuid());
int i = 0;
for (auto it = node_begin; it != node_end; ++it)
{
auto n = m_widgetFactory.CreateNodeWidget((*it)->GetType(), m_manager, (*it));
if (n)
{
n->Initialize();
// n->SetOutputs(m_story->OutputsCount((*it)->GetId())); // il faut que les noeuds aient une bonne taille de outputs avant de créer les liens
// m_currentPage->AddNode(n);
}
else
{
throw std::logic_error(std::string("No registered model with name ") + (*it)->GetType());
std::cout << "Cannot load null story" << std::endl;
return;
}
std::cout << "Created " << ++i << " node" << std::endl;
}
auto [link_begin, link_end] = m_story->Links(m_currentPage->Uuid());
for (auto it = link_begin; it != link_end; ++it)
try
{
// CreateLink(*it,
// GetInputPin((*it)->inNodeId, (*it)->inPortIndex),
// GetOutputPin((*it)->outNodeId, (*it)->outPortIndex));
// Clear existing pages
m_pages.clear();
m_currentPage.reset();
// Load all pages from the project
auto [nodesBegin, nodesEnd] = m_story->Nodes(m_story->MainUuid());
auto [linksBegin, linksEnd] = m_story->Links(m_story->MainUuid());
// Create the main page
auto page = std::make_shared<NodeEditorPage>(m_story->MainUuid(), "Main");
m_pages.push_back(page);
m_currentPage = page;
// Map to store node UUID -> ImNodeFlow UID mapping
std::map<std::string, ImFlow::NodeUID> nodeUidMap;
// 1. Load all nodes from the project into ImNodeFlow
for (auto it = nodesBegin; it != nodesEnd; ++it)
{
auto baseNode = *it;
if (!baseNode)
continue;
// Create the widget for this node
auto widget = m_widgetFactory.CreateNodeWidget(
baseNode->GetType(),
m_manager,
baseNode
);
if (!widget)
{
std::cout << "Failed to create widget for node type: "
<< baseNode->GetType() << std::endl;
continue;
}
// Initialize the widget
widget->Initialize();
// Create a NodeDelegate in ImNodeFlow
ImVec2 nodePos(baseNode->GetX(), baseNode->GetY());
auto delegate = page->mINF.addNode<NodeDelegate>(nodePos);
// Link the delegate with the widget
delegate->SetWidget(widget);
// Store the mapping between project node UUID and ImNodeFlow UID
nodeUidMap[baseNode->GetId()] = delegate->getUID();
std::cout << "Loaded node: " << baseNode->GetType()
<< " at (" << nodePos.x << ", " << nodePos.y << ")" << std::endl;
}
// 2. Load all connections/links
for (auto it = linksBegin; it != linksEnd; ++it)
{
auto connection = *it;
if (!connection)
continue;
// Find the source and target nodes in ImNodeFlow
auto sourceUidIt = nodeUidMap.find(connection->outNodeId);
auto targetUidIt = nodeUidMap.find(connection->inNodeId);
if (sourceUidIt == nodeUidMap.end() || targetUidIt == nodeUidMap.end())
{
std::cout << "Warning: Cannot create link - node not found" << std::endl;
continue;
}
// Get the ImNodeFlow nodes
auto& nodes = page->mINF.getNodes();
auto sourceNodeIt = nodes.find(sourceUidIt->second);
auto targetNodeIt = nodes.find(targetUidIt->second);
if (sourceNodeIt == nodes.end() || targetNodeIt == nodes.end())
{
std::cout << "Warning: Node UID not found in ImNodeFlow" << std::endl;
continue;
}
auto sourceNode = sourceNodeIt->second;
auto targetNode = targetNodeIt->second;
// Get the pins from the nodes
// Output pin from source node
auto& sourcePins = sourceNode->getOuts();
if (connection->outPortIndex >= static_cast<int>(sourcePins.size()))
{
std::cout << "Warning: Invalid output port index: "
<< connection->outPortIndex << std::endl;
continue;
}
auto* sourcePin = sourcePins[connection->outPortIndex].get();
// Input pin from target node
auto& targetPins = targetNode->getIns();
if (connection->inPortIndex >= static_cast<int>(targetPins.size()))
{
std::cout << "Warning: Invalid input port index: "
<< connection->inPortIndex << std::endl;
continue;
}
auto* targetPin = targetPins[connection->inPortIndex].get();
// Create the link in ImNodeFlow
if (sourcePin && targetPin)
{
targetPin->createLink(sourcePin);
std::cout << "Created link: " << connection->outNodeId
<< "[" << connection->outPortIndex << "] -> "
<< connection->inNodeId
<< "[" << connection->inPortIndex << "]" << std::endl;
}
}
m_loaded = true;
std::cout << "Loaded " << nodeUidMap.size() << " nodes successfully" << std::endl;
}
catch(std::exception &e)
{
std::cout << "(NodeEditorWindow::Load) " << e.what() << std::endl;
std::cout << "(NodeEditorWindow::Load) Exception: " << e.what() << std::endl;
m_loaded = false;
}
}
// std::cout << "Loaded " << m_currentPage->m_nodes.size() << " nodes, " << m_currentPage->m_links.size() << " links" << std::endl;
}
void NodeEditorWindow::SaveNodePositions()
{
@ -158,28 +245,140 @@ void NodeEditorWindow::SaveNodePositions()
void NodeEditorWindow::SaveNodesToProject()
{
if (!m_story)
{
std::cout << "Cannot save: no story project loaded" << std::endl;
return;
}
// Clear current project structure
m_story->Clear();
// Pour toutes les pages
for (const auto& page : m_pages)
{
// Clear current project nodes and links
m_story->Clear();
// Create the page in the project
auto currentPage = m_story->CreatePage(page->Uuid());
// On récupère les noeuds de la page
for (const auto& node : page->GetNodes())
// 1. Save all nodes with their updated positions
for (auto &nodeEntry : page->mINF.getNodes())
{
// On les ajoute au projet
// currentPage->AddNode(node);
auto delegate = dynamic_cast<NodeDelegate*>(nodeEntry.second.get());
if (!delegate)
continue;
auto widget = delegate->GetWidget();
if (!widget)
continue;
auto baseNode = widget->Base();
if (!baseNode)
continue;
// Update node position from ImNodeFlow
ImVec2 nodePos = nodeEntry.second->getPos();
baseNode->SetPosition(nodePos.x, nodePos.y);
// Add node to project
m_story->AddNode(currentPage->Uuid(), baseNode);
std::cout << "Saved node: " << baseNode->GetId()
<< " at (" << nodePos.x << ", " << nodePos.y << ")" << std::endl;
}
// On récupère tous les liens de la page
for (const auto& link : page->GetLinks())
// 2. Save all links/connections
const auto& links = page->mINF.getLinks();
for (const auto& weakLink : links)
{
// On les ajoute au projet
// currentPage->AddLink(link);
auto link = weakLink.lock();
if (!link)
continue;
// Get left (source) and right (target) pins
auto* leftPin = link->left();
auto* rightPin = link->right();
if (!leftPin || !rightPin)
continue;
// Get the nodes that own these pins
auto* leftNode = leftPin->getParent();
auto* rightNode = rightPin->getParent();
if (!leftNode || !rightNode)
continue;
// Cast to NodeDelegate to get the widget
auto* leftDelegate = dynamic_cast<NodeDelegate*>(leftNode);
auto* rightDelegate = dynamic_cast<NodeDelegate*>(rightNode);
if (!leftDelegate || !rightDelegate)
continue;
auto leftWidget = leftDelegate->GetWidget();
auto rightWidget = rightDelegate->GetWidget();
if (!leftWidget || !rightWidget)
continue;
// Get the base nodes (model)
auto leftBaseNode = leftWidget->Base();
auto rightBaseNode = rightWidget->Base();
if (!leftBaseNode || !rightBaseNode)
continue;
// Find the pin indices
int leftPinIndex = -1;
int rightPinIndex = -1;
// Find output pin index on left node
const auto& leftOuts = leftNode->getOuts();
for (size_t i = 0; i < leftOuts.size(); ++i)
{
if (leftOuts[i].get() == leftPin)
{
leftPinIndex = static_cast<int>(i);
break;
}
}
// Find input pin index on right node
const auto& rightIns = rightNode->getIns();
for (size_t i = 0; i < rightIns.size(); ++i)
{
if (rightIns[i].get() == rightPin)
{
rightPinIndex = static_cast<int>(i);
break;
}
}
if (leftPinIndex < 0 || rightPinIndex < 0)
{
std::cout << "Warning: Could not find pin indices for connection" << std::endl;
continue;
}
// Create the connection object
auto connection = std::make_shared<Connection>();
connection->outNodeId = leftBaseNode->GetId();
connection->outPortIndex = leftPinIndex;
connection->inNodeId = rightBaseNode->GetId();
connection->inPortIndex = rightPinIndex;
// Add connection to project
m_story->AddConnection(currentPage->Uuid(), connection);
std::cout << "Saved connection: " << connection->outNodeId
<< "[" << connection->outPortIndex << "] -> "
<< connection->inNodeId
<< "[" << connection->inPortIndex << "]" << std::endl;
}
}
std::cout << "SaveNodesToProject completed successfully" << std::endl;
}
void NodeEditorWindow::OpenFunction(const std::string &uuid, const std::string &name)

View file

@ -9,6 +9,8 @@
#include "gui.h"
#include "ImGuiFileDialog.h"
#include "all_events.h"
typedef int (*xfer_callback_t)(void *clientp, curl_off_t dltotal, curl_off_t dlnow,
curl_off_t ultotal, curl_off_t ulnow);
@ -50,11 +52,12 @@ void download_file(CURL *curl,
}
LibraryWindow::LibraryWindow(IStoryManager &project, LibraryManager &library, NodesFactory &nodesFactory)
LibraryWindow::LibraryWindow(IStoryManager &project, LibraryManager &library, NodesFactory &nodesFactory, EventBus& eventBus)
: WindowBase("Library Manager")
, m_storyManager(project)
, m_libraryManager(library)
, m_nodesFactory(nodesFactory)
, m_eventBus(eventBus)
{
m_downloadThread = std::thread( std::bind(&LibraryWindow::DownloadThread, this) );
@ -678,8 +681,7 @@ void LibraryWindow::Draw()
ImGui::PushID(module.uuid.c_str());
if (ImGui::SmallButton("Open"))
{
// Open the module in the editor
m_storyManager.OpenModule(module.uuid);
m_eventBus.Emit(std::make_shared<ModuleEvent>(ModuleEvent::Type::Open, module.uuid));
}
ImGui::PopID();
}

View file

@ -7,6 +7,7 @@
#include "thread_safe_queue.h"
#include "downloader.h"
#include "nodes_factory.h"
#include "event_bus.h"
#include <curl/curl.h>
@ -65,7 +66,7 @@ struct TransferProgress {
class LibraryWindow : public WindowBase
{
public:
LibraryWindow(IStoryManager &project, LibraryManager &library, NodesFactory &nodesFactory);
LibraryWindow(IStoryManager &project, LibraryManager &library, NodesFactory &nodesFactory, EventBus& eventBus);
void Initialize();
virtual void Draw() override;
@ -75,6 +76,7 @@ private:
IStoryManager &m_storyManager;
LibraryManager &m_libraryManager;
NodesFactory &m_nodesFactory;
EventBus &m_eventBus;
Downloader m_downloader;
CURL *m_curl;