diff --git a/ImGuiVisitor.cpp b/ImGuiVisitor.cpp index 576a4a6..f69cda1 100644 --- a/ImGuiVisitor.cpp +++ b/ImGuiVisitor.cpp @@ -270,11 +270,11 @@ void ImGuiVisitor::visit (Source& s) void ImGuiVisitor::visit (MediaSource& s) { if ( s.mediaplayer()->duration() == GST_CLOCK_TIME_NONE) { - ImGui::Text("Image"); + ImGui::Text("Image File"); } else { - ImGui::Text("Video"); - if (ImGui::Button("Open Media Player", ImVec2(IMGUI_RIGHT_ALIGN, 0)) ) + ImGui::Text("Video File"); + if ( ImGui::Button("Open Media Player", ImVec2(IMGUI_RIGHT_ALIGN, 0)) ) Settings::application.media_player = true; } ImGuiToolkit::ButtonOpenUrl( SystemToolkit::path_filename(s.path()).c_str(), ImVec2(IMGUI_RIGHT_ALIGN, 0) ); @@ -282,22 +282,25 @@ void ImGuiVisitor::visit (MediaSource& s) void ImGuiVisitor::visit (SessionSource& s) { -// ImGui::Button("Expand", ImVec2(IMGUI_RIGHT_ALIGN, 0)); - ImGui::Text("Session"); - if (ImGui::Button("Make Current", ImVec2(IMGUI_RIGHT_ALIGN, 0)) ) + ImGui::Text("Session File"); + if ( ImGui::Button("Make Current", ImVec2(IMGUI_RIGHT_ALIGN, 0)) ) Mixer::manager().set( s.detach() ); + if ( ImGui::Button( ICON_FA_FILE_IMPORT " Merge", ImVec2(IMGUI_RIGHT_ALIGN, 0)) ) + Mixer::manager().merge( s.detach() ); + ImGuiToolkit::ButtonOpenUrl( SystemToolkit::path_filename(s.path()).c_str(), ImVec2(IMGUI_RIGHT_ALIGN, 0) ); } void ImGuiVisitor::visit (RenderSource& s) { -// ImGui::Button("Expand", ImVec2(IMGUI_RIGHT_ALIGN, 0)); - ImGui::Text("Render"); + ImGui::Text("Rendering Output"); } void ImGuiVisitor::visit (CloneSource& s) { -// ImGui::Button("Expand", ImVec2(IMGUI_RIGHT_ALIGN, 0)); ImGui::Text("Clone of %s", s.origin()->name().c_str()); + std::string label = "Select " + s.origin()->name(); + if ( ImGui::Button(label.c_str(), ImVec2(IMGUI_RIGHT_ALIGN, 0)) ) + Mixer::manager().setCurrentSource(s.origin()); } diff --git a/Mixer.cpp b/Mixer.cpp index 1331e66..5a8d321 100644 --- a/Mixer.cpp +++ b/Mixer.cpp @@ -51,6 +51,30 @@ static void loadSession(const std::string& filename, Session *session) sessionThreadActive_ = false; } +static std::atomic sessionImportRequested_ = false; +static void importSession(const std::string& filename, Session *session) +{ + while (sessionThreadActive_) + std::this_thread::sleep_for( std::chrono::milliseconds(50)); + sessionThreadActive_ = true; + + // actual loading of xml file + SessionCreator creator( session ); + + if (creator.load(filename)) { + // cosmetics load ok + sessionImportRequested_ = true; + + Log::Notify("Session %s loaded. %d source(s) imported.", filename.c_str(), session->numSource()); + } + else { + // error loading + Log::Warning("Failed to import Session file %s.", filename.c_str()); + } + + sessionThreadActive_ = false; +} + // static multithreaded session saving static void saveSession(const std::string& filename, Session *session) { @@ -149,6 +173,12 @@ void Mixer::update() } } + if (sessionImportRequested_) { + sessionImportRequested_ = false; + merge(back_session_); + back_session_ = nullptr; + } + // compute dt if (update_time_ == GST_CLOCK_TIME_NONE) update_time_ = gst_util_get_timestamp (); @@ -451,6 +481,29 @@ void Mixer::open(const std::string& filename) std::thread (loadSession, filename, back_session_).detach(); } +void Mixer::import(const std::string& filename) +{ + if (back_session_) + delete back_session_; + + // create empty session + back_session_ = new Session; + + // launch a thread to load the session into back_session + std::thread (importSession, filename, back_session_).detach(); +} + +void Mixer::merge(Session *session) +{ + if (session) { + + for ( Source *s = session->popSource(); s != nullptr; s = session->popSource()) + insertSource(s); + + delete session; + } +} + void Mixer::swap() { if (!back_session_) diff --git a/Mixer.h b/Mixer.h index 4ce5f8d..b0f1238 100644 --- a/Mixer.h +++ b/Mixer.h @@ -65,8 +65,8 @@ public: void save(); void saveas(const std::string& filename); void open(const std::string& filename); - void import(const std::string& filename) {} - void import(Session *s) {} + void import(const std::string& filename); + void merge(Session *s); void set(Session *s); protected: diff --git a/Session.cpp b/Session.cpp index 1ece749..697816b 100644 --- a/Session.cpp +++ b/Session.cpp @@ -95,6 +95,24 @@ SourceList::iterator Session::deleteSource(Source *s) return its; } +Source *Session::popSource() +{ + Source *s = nullptr; + + SourceList::iterator its = sources_.begin(); + if (its != sources_.end()) + { + s = *its; + + // remove Node from the rendering scene + render_.scene.ws()->detatch( s->group(View::RENDERING) ); + + // erase the source from the update list & get next element + sources_.erase(its); + } + + return s; +} void Session::setResolution(glm::vec3 resolution) { @@ -146,6 +164,11 @@ uint Session::numSource() const return sources_.size(); } +bool Session::empty() const +{ + return sources_.empty(); +} + int Session::index(SourceList::iterator it) const { int index = -1; diff --git a/Session.h b/Session.h index df6b9c1..cd804d1 100644 --- a/Session.h +++ b/Session.h @@ -11,32 +11,43 @@ public: Session(); ~Session(); - // add or remove sources + // add given source into the session SourceList::iterator addSource (Source *s); + + // delete the source s from the session SourceList::iterator deleteSource (Source *s); + // get ptr to front most source and remove it from the session + // Does not delete the source + Source *popSource(); + // management of list of sources + bool empty() const; + uint numSource() const; SourceList::iterator begin (); SourceList::iterator end (); SourceList::iterator find (int index); - int index (SourceList::iterator it) const; SourceList::iterator find (Source *s); SourceList::iterator find (std::string name); SourceList::iterator find (Node *node); - uint numSource() const; + int index (SourceList::iterator it) const; - // update all sources and return the list of source which failed + // update all sources and mark sources which failed void update (float dt); + + // return the last source which failed Source *failedSource() { return failedSource_; } - // result of render + // get frame result of render inline FrameBuffer *frame () const { return render_.frame(); } + + // configure rendering resolution void setResolution(glm::vec3 resolution); // configuration for group nodes of views inline Group *config (View::Mode m) const { return config_.at(m); } - // name of file containing this session + // name of file containing this session (for transfer) void setFilename(const std::string &filename) { filename_ = filename; } std::string filename() const { return filename_; } diff --git a/UserInterfaceManager.cpp b/UserInterfaceManager.cpp index 2faa686..37e018c 100644 --- a/UserInterfaceManager.cpp +++ b/UserInterfaceManager.cpp @@ -60,6 +60,7 @@ void ShowAbout(bool* p_open); // static objects for multithreaded file dialog static std::atomic fileDialogPending_ = false; static std::atomic sessionFileDialogLoadFinished_ = false; +static std::atomic sessionFileDialogImport_ = false; static std::atomic sessionFileDialogSaveFinished_ = false; static std::string sessionFileDialogFilename_ = ""; @@ -395,19 +396,22 @@ void UserInterface::NewFrame() // handle FileDialog if (sessionFileDialogLoadFinished_) { sessionFileDialogLoadFinished_ = false; - fileDialogPending_ = false; if (!sessionFileDialogFilename_.empty()) { - Mixer::manager().open(sessionFileDialogFilename_); + if (sessionFileDialogImport_) + Mixer::manager().import(sessionFileDialogFilename_); + else + Mixer::manager().open(sessionFileDialogFilename_); Settings::application.recentSessions.path = SystemToolkit::path_filename(sessionFileDialogFilename_); } + fileDialogPending_ = false; } if (sessionFileDialogSaveFinished_) { sessionFileDialogSaveFinished_ = false; - fileDialogPending_ = false; if (!sessionFileDialogFilename_.empty()) { Mixer::manager().saveas(sessionFileDialogFilename_); Settings::application.recentSessions.path = SystemToolkit::path_filename(sessionFileDialogFilename_); } + fileDialogPending_ = false; } // overlay to ensure file dialog is modal @@ -485,8 +489,26 @@ void UserInterface::Terminate() void UserInterface::showMenuFile() { + if (ImGui::MenuItem( ICON_FA_FILE " New", "Ctrl+W")) { + Mixer::manager().clear(); + navigator.hidePannel(); + } + ImGui::SetNextItemWidth( ImGui::GetContentRegionAvail().x ); + ImGui::Combo("##AR", &Settings::application.framebuffer_ar, FrameBuffer::aspect_ratio_name, IM_ARRAYSIZE(FrameBuffer::aspect_ratio_name) ); + ImGui::SetNextItemWidth( ImGui::GetContentRegionAvail().x ); + ImGui::Combo("##HEIGHT", &Settings::application.framebuffer_h, FrameBuffer::resolution_name, IM_ARRAYSIZE(FrameBuffer::resolution_name) ); + + ImGui::Separator(); + if (ImGui::MenuItem( ICON_FA_FILE_UPLOAD " Open", "Ctrl+O")) { // launch file dialog to open a session file + sessionFileDialogImport_ = false; + std::thread (SessionFileDialogOpen, Settings::application.recentSessions.path).detach(); + navigator.hidePannel(); + } + if (ImGui::MenuItem( ICON_FA_FILE_EXPORT " Import")) { + // launch file dialog to open a session file + sessionFileDialogImport_ = true; std::thread (SessionFileDialogOpen, Settings::application.recentSessions.path).detach(); navigator.hidePannel(); } @@ -497,23 +519,11 @@ void UserInterface::showMenuFile() Mixer::manager().save(); navigator.hidePannel(); } - if (ImGui::MenuItem( ICON_FA_FOLDER_OPEN " Save as")) { + if (ImGui::MenuItem( ICON_FA_SAVE " Save as")) { std::thread (SessionFileDialogSave, Settings::application.recentSessions.path).detach(); navigator.hidePannel(); } - ImGui::Separator(); - - if (ImGui::MenuItem( ICON_FA_FILE " New", "Ctrl+W")) { - Mixer::manager().clear(); - navigator.hidePannel(); - } - ImGui::SetNextItemWidth( ImGui::GetContentRegionAvail().x ); - ImGui::Combo("##AR", &Settings::application.framebuffer_ar, FrameBuffer::aspect_ratio_name, IM_ARRAYSIZE(FrameBuffer::aspect_ratio_name) ); - ImGui::SetNextItemWidth( ImGui::GetContentRegionAvail().x ); - ImGui::Combo("##HEIGHT", &Settings::application.framebuffer_h, FrameBuffer::resolution_name, IM_ARRAYSIZE(FrameBuffer::resolution_name) ); - - ImGui::Separator(); if (ImGui::MenuItem( ICON_FA_POWER_OFF " Quit", "Ctrl+Q")) { Rendering::manager().Close();