From 7634e62054b90a1e0550fdd01edfe9d83e58bccb Mon Sep 17 00:00:00 2001 From: brunoherbelin Date: Sat, 9 May 2020 19:20:15 +0200 Subject: [PATCH] Recent session files, saved in Settings and restored on start. --- Mixer.cpp | 62 ++++------------ Mixer.h | 4 +- Settings.cpp | 153 ++++++++++++++++++++++++++++----------- Settings.h | 23 +++++- UserInterfaceManager.cpp | 30 ++++++-- UserInterfaceManager.h | 1 - defines.h | 1 + 7 files changed, 176 insertions(+), 98 deletions(-) diff --git a/Mixer.cpp b/Mixer.cpp index 71f86d5..7fcbc44 100644 --- a/Mixer.cpp +++ b/Mixer.cpp @@ -106,6 +106,12 @@ Mixer::Mixer() : session_(nullptr), back_session_(nullptr), current_view_(nullpt // this initializes with a new empty session newSession(); + // auto load if Settings ask to + if ( Settings::application.recentSessions.automatic ) { + if ( Settings::application.recentSessions.filenames.size() > 0 ) + open( Settings::application.recentSessions.filenames.back() ); + } + // this initializes with the current view setCurrentView( (View::Mode) Settings::application.current_view ); } @@ -115,13 +121,17 @@ void Mixer::update() { // swap front and back sessions when loading is finished if (sessionLoadFinished_) { + // finished loading, swap front and back sessions swap(); + // done sessionFilename_ = sessionThreadFilename_; sessionLoadFinished_ = false; + Settings::application.recentSessions.push(sessionFilename_); } if (sessionSaveFinished_) { sessionFilename_ = sessionThreadFilename_; sessionSaveFinished_ = false; + Settings::application.recentSessions.push(sessionFilename_); } // compute dt @@ -176,13 +186,7 @@ void Mixer::insertSource(Source *s) } void Mixer::deleteSource(Source *s) { -// SessionVisitor visit; -// geometry_.scene.accept(visit); -// visit.doc()->SaveFile("./geombefore.xml"); -// SessionVisitor visitm; -// mixing_.scene.accept(visitm); -// visitm.doc()->SaveFile("./mixbefore.xml"); - + // in case.. unsetCurrentSource(); // remove source Nodes from views @@ -191,13 +195,6 @@ void Mixer::deleteSource(Source *s) // delete source session_->deleteSource(s); - -// SessionVisitor visit2; -// geometry_.scene.accept(visit2); -// visit2.doc()->SaveFile("./geomafter.xml"); -// SessionVisitor visit2m; -// mixing_.scene.accept(visit2m); -// visit2m.doc()->SaveFile("./mixmafter.xml"); } void Mixer::renameSource(Source *s, const std::string &newname) @@ -334,39 +331,6 @@ void Mixer::saveas(const std::string& filename) // launch a thread to save the session std::thread (saveSession, filename, session_).detach(); -// XMLDocument xmlDoc; - -// XMLElement *version = xmlDoc.NewElement(APP_NAME); -// version->SetAttribute("major", XML_VERSION_MAJOR); -// version->SetAttribute("minor", XML_VERSION_MINOR); -// xmlDoc.InsertEndChild(version); - -// // block: list of sources -// XMLElement *session = xmlDoc.NewElement("Session"); -// xmlDoc.InsertEndChild(session); -// SourceList::iterator iter; -// for (iter = session_->begin(); iter != session_->end(); iter++) -// { -// SessionVisitor sv(&xmlDoc, session); -// // source visitor -// (*iter)->accept(sv); -// } - -// // block: config of views -// XMLElement *views = xmlDoc.NewElement("Views"); -// xmlDoc.InsertEndChild(views); -// { -// XMLElement *mixing = xmlDoc.NewElement( "Mixing" ); -// mixing->InsertEndChild( SessionVisitor::NodeToXML(*mixing_.scene.root(), &xmlDoc)); -// views->InsertEndChild(mixing); - -// XMLElement *geometry = xmlDoc.NewElement( "Geometry" ); -// geometry->InsertEndChild( SessionVisitor::NodeToXML(*geometry_.scene.root(), &xmlDoc)); -// views->InsertEndChild(geometry); -// } - -// // save file -// XMLSaveDoc(&xmlDoc, filename); } void Mixer::open(const std::string& filename) @@ -419,6 +383,10 @@ void Mixer::swap() // reset timer update_time_ = GST_CLOCK_TIME_NONE; + + // delete back + delete back_session_; + back_session_ = nullptr; } diff --git a/Mixer.h b/Mixer.h index 3625a21..fd463f6 100644 --- a/Mixer.h +++ b/Mixer.h @@ -68,10 +68,12 @@ public: protected: Session *session_; - std::string sessionFilename_; Session *back_session_; void swap(); +// void validateFilename(const std::string& filename); + std::string sessionFilename_; + void insertSource(Source *s); void setCurrentSource(SourceList::iterator it); diff --git a/Settings.cpp b/Settings.cpp index cc27ad4..0a420f1 100644 --- a/Settings.cpp +++ b/Settings.cpp @@ -1,3 +1,4 @@ +#include #include using namespace std; @@ -61,7 +62,7 @@ void Settings::Save() applicationNode->SetAttribute("toolbox", application.toolbox); pRoot->InsertEndChild(applicationNode); - // block: views + // bloc views { XMLElement *viewsNode = xmlDoc.NewElement( "Views" ); viewsNode->SetAttribute("current", application.current_view); @@ -88,6 +89,37 @@ void Settings::Save() pRoot->InsertEndChild(viewsNode); } + // bloc history + { + XMLElement *recent = xmlDoc.NewElement( "Recent" ); + + XMLElement *recentsession = xmlDoc.NewElement( "Session" ); + recentsession->SetAttribute("auto", application.recentSessions.automatic); + for(auto it = application.recentSessions.filenames.begin(); + it != application.recentSessions.filenames.end(); it++) { + XMLElement *fileNode = xmlDoc.NewElement("path"); + XMLText *text = xmlDoc.NewText( (*it).c_str() ); + fileNode->InsertEndChild( text ); + recentsession->InsertEndChild(fileNode); + }; + recent->InsertEndChild(recentsession); + + XMLElement *recentmedia = xmlDoc.NewElement( "Media" ); + for(auto it = application.recentMedia.filenames.begin(); + it != application.recentMedia.filenames.end(); it++) { + + XMLElement *fileNode = xmlDoc.NewElement("uri"); + XMLText *text = xmlDoc.NewText( (*it).c_str() ); + fileNode->InsertEndChild( text ); + recentmedia->InsertEndChild(fileNode); + } + recent->InsertEndChild(recentmedia); + + pRoot->InsertEndChild(recent); + } + + + // First save : create filename if (settingsFilename.empty()) settingsFilename = SystemToolkit::settings_prepend_path(APP_SETTINGS); @@ -116,32 +148,9 @@ void Settings::Load() // different root name return; - // block: windows - { - application.windows.clear(); // trash existing list - - XMLElement * pElement = pRoot->FirstChildElement("Windows"); - if (pElement == nullptr) return; - - XMLElement* windowNode = pElement->FirstChildElement("Window"); - for( ; windowNode ; windowNode=windowNode->NextSiblingElement()) - { - const char *pName = windowNode->Attribute("name"); - Settings::WindowConfig w(pName); - - windowNode->QueryIntAttribute("x", &w.x); // If this fails, original value is left as-is - windowNode->QueryIntAttribute("y", &w.y); - windowNode->QueryIntAttribute("w", &w.w); - windowNode->QueryIntAttribute("h", &w.h); - windowNode->QueryBoolAttribute("f", &w.fullscreen); - - application.windows.push_back(w); - } - } - - XMLElement * pElement = pRoot->FirstChildElement("Application"); - if (pElement == nullptr) return; - pElement->QueryFloatAttribute("scale", &application.scale); + XMLElement * pElement = pRoot->FirstChildElement("Application"); + if (pElement == nullptr) return; + pElement->QueryFloatAttribute("scale", &application.scale); pElement->QueryIntAttribute("accent_color", &application.accent_color); pElement->QueryBoolAttribute("preview", &application.preview); pElement->QueryBoolAttribute("media_player", &application.media_player); @@ -151,32 +160,90 @@ void Settings::Load() pElement->QueryBoolAttribute("toolbox", &application.toolbox); pElement->QueryIntAttribute("stats_corner", &application.stats_corner); - // block: views + // bloc windows + { + application.windows.clear(); // trash existing list + + XMLElement * pElement = pRoot->FirstChildElement("Windows"); + if (pElement) + { + XMLElement* windowNode = pElement->FirstChildElement("Window"); + for( ; windowNode ; windowNode=windowNode->NextSiblingElement()) + { + const char *pName = windowNode->Attribute("name"); + Settings::WindowConfig w(pName); + + windowNode->QueryIntAttribute("x", &w.x); // If this fails, original value is left as-is + windowNode->QueryIntAttribute("y", &w.y); + windowNode->QueryIntAttribute("w", &w.w); + windowNode->QueryIntAttribute("h", &w.h); + windowNode->QueryBoolAttribute("f", &w.fullscreen); + + application.windows.push_back(w); + } + } + } + + // bloc views { application.views.clear(); // trash existing list XMLElement * pElement = pRoot->FirstChildElement("Views"); - if (pElement == nullptr) return; - - pElement->QueryIntAttribute("current", &application.current_view); - - XMLElement* viewNode = pElement->FirstChildElement("View"); - for( ; viewNode ; viewNode=viewNode->NextSiblingElement()) + if (pElement) { - int id = 0; - viewNode->QueryIntAttribute("id", &id); - application.views[id].name = viewNode->Attribute("name"); + pElement->QueryIntAttribute("current", &application.current_view); - XMLElement* scaleNode = viewNode->FirstChildElement("default_scale"); - tinyxml2::XMLElementToGLM( scaleNode->FirstChildElement("vec3"), - application.views[id].default_scale); + XMLElement* viewNode = pElement->FirstChildElement("View"); + for( ; viewNode ; viewNode=viewNode->NextSiblingElement()) + { + int id = 0; + viewNode->QueryIntAttribute("id", &id); + application.views[id].name = viewNode->Attribute("name"); - XMLElement* translationNode = viewNode->FirstChildElement("default_translation"); - tinyxml2::XMLElementToGLM( translationNode->FirstChildElement("vec3"), - application.views[id].default_translation); + XMLElement* scaleNode = viewNode->FirstChildElement("default_scale"); + tinyxml2::XMLElementToGLM( scaleNode->FirstChildElement("vec3"), + application.views[id].default_scale); + XMLElement* translationNode = viewNode->FirstChildElement("default_translation"); + tinyxml2::XMLElementToGLM( translationNode->FirstChildElement("vec3"), + application.views[id].default_translation); + + } + } + + } + + // bloc history of recent + { + XMLElement * pElement = pRoot->FirstChildElement("Recent"); + if (pElement) + { + // recent session filenames + XMLElement * pSession = pElement->FirstChildElement("Session"); + if (pSession) + { + pSession->QueryBoolAttribute("auto", &application.recentSessions.automatic); + application.recentSessions.filenames.clear(); + XMLElement* path = pSession->FirstChildElement("path"); + for( ; path ; path = path->NextSiblingElement()) + { + application.recentSessions.push( std::string (path->GetText()) ); + } + } + // recent media uri + XMLElement * pMedia = pElement->FirstChildElement("Media"); + if (pMedia) + { + application.recentMedia.filenames.clear(); + XMLElement* path = pMedia->FirstChildElement("path"); + for( ; path ; path = path->NextSiblingElement()) + { + application.recentMedia.push( std::string (path->GetText()) ); + } + } } } + } diff --git a/Settings.h b/Settings.h index 238d8b4..b13a185 100644 --- a/Settings.h +++ b/Settings.h @@ -6,6 +6,7 @@ #include #include #include +#include #include namespace Settings { @@ -33,6 +34,22 @@ struct ViewConfig }; +struct History +{ + std::list filenames; + bool automatic; + + History() { + automatic = false; + } + void push(std::string filename) { + filenames.remove(filename); + filenames.push_front(filename); + if (filenames.size() > MAX_RECENT_HISTORY) + filenames.pop_back(); + } +}; + struct Application { // Verification @@ -54,9 +71,13 @@ struct Application std::map views; // multiple windows handling - // TODO: maybe keep map of multiple windows, widn id=0 for main window + // TODO: manage other windows std::vector windows; + // recent files histories + History recentSessions; + History recentMedia; + Application() : name(APP_NAME){ scale = 1.f; accent_color = 0; diff --git a/UserInterfaceManager.cpp b/UserInterfaceManager.cpp index a432a3d..326c408 100644 --- a/UserInterfaceManager.cpp +++ b/UserInterfaceManager.cpp @@ -2,6 +2,7 @@ #include #include #include +#include // ImGui #include "imgui.h" @@ -100,6 +101,10 @@ static void FileDialogSave(std::string path) else { FileDialogFilename_ = std::string( save_file_name ); + // check extension + std::string extension = FileDialogFilename_.substr(FileDialogFilename_.find_last_of(".") + 1); + if (extension != "vmx") + FileDialogFilename_ += ".vmx"; } FileDialogSaveFinished_ = true; @@ -186,14 +191,16 @@ void UserInterface::handleKeyboard() } else if (ImGui::IsKeyPressed( GLFW_KEY_O )) { // Open session + std::thread (FileDialogOpen, "./").detach(); + navigator.hidePannel(); } else if (ImGui::IsKeyPressed( GLFW_KEY_S )) { // Save Session - std::cerr <<" Save File " << std::endl; + Mixer::manager().save(); } else if (ImGui::IsKeyPressed( GLFW_KEY_W )) { // New Session - std::cerr <<" Close File " << std::endl; + Mixer::manager().newSession(); } else if (ImGui::IsKeyPressed( GLFW_KEY_L )) { // Logs @@ -1035,10 +1042,23 @@ void Navigator::RenderMainPannel() ImGui::EndMenu(); } ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); - static int recent_session = 0; - if ( ImGui::Combo("Recent", &recent_session, "Select\0") ) { - + // combo box with list of recent session files from Settings + static bool recentselected = false; + recentselected = false; + if (ImGui::BeginCombo("Recent", "Select")) + { + std::for_each(Settings::application.recentSessions.filenames.begin(), + Settings::application.recentSessions.filenames.end(), [](std::string& filename) { + if (ImGui::Selectable( filename.substr( filename.size() - 40 ).c_str() )) { + Mixer::manager().open( filename ); + recentselected = true; + } + }); + ImGui::EndCombo(); } + if (recentselected) + hidePannel(); + ImGuiToolkit::ButtonSwitch( "Load most recent on start", &Settings::application.recentSessions.automatic); ImGui::Text(" "); ImGui::Text("Windows"); diff --git a/UserInterfaceManager.h b/UserInterfaceManager.h index 32f5313..181b7e3 100644 --- a/UserInterfaceManager.h +++ b/UserInterfaceManager.h @@ -79,7 +79,6 @@ class UserInterface // } FileDialogStatus; // FileDialogStatus filestatus_; // std::string filename_; -// std::thread filethread_; // void startOpenFileDialog(); // Private Constructor diff --git a/defines.h b/defines.h index 87b7542..f52ba05 100644 --- a/defines.h +++ b/defines.h @@ -8,6 +8,7 @@ #define APP_VERSION_MINOR 1 #define XML_VERSION_MAJOR 0 #define XML_VERSION_MINOR 1 +#define MAX_RECENT_HISTORY 10 #define MINI(a, b) (((a) < (b)) ? (a) : (b)) #define MAXI(a, b) (((a) > (b)) ? (a) : (b))