mirror of
https://github.com/brunoherbelin/vimix.git
synced 2026-06-16 04:27:23 +02:00
Draft implementation of Snapshots, with saving and UI
This commit is contained in:
+52
-21
@@ -1,5 +1,6 @@
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
#include "Log.h"
|
||||
#include "View.h"
|
||||
@@ -18,25 +19,45 @@
|
||||
#define ACTION_DEBUG
|
||||
#endif
|
||||
|
||||
#define HISTORY_NODE(i) std::to_string(i).insert(0, "H").c_str()
|
||||
#define SNAPSHOT_NODE(i) std::to_string(i).insert(0, "S").c_str()
|
||||
|
||||
using namespace tinyxml2;
|
||||
|
||||
Action::Action(): history_step_(0), history_max_step_(0)
|
||||
{
|
||||
}
|
||||
|
||||
void Action::clear()
|
||||
void Action::init(const std::string &xml)
|
||||
{
|
||||
// clean the history
|
||||
history_doc_.Clear();
|
||||
history_step_ = 0;
|
||||
history_max_step_ = 0;
|
||||
// start fresh
|
||||
store("Session start");
|
||||
|
||||
// clean the snapshots
|
||||
snapshots_doc_.Clear();
|
||||
snapshots_.clear();
|
||||
|
||||
// start fresh
|
||||
store("Session start");
|
||||
if ( !xml.empty() ) {
|
||||
if ( XMLResultError( snapshots_doc_.Parse( xml.c_str() ) ))
|
||||
Log::Info("Failed to load snapshots");
|
||||
else
|
||||
{
|
||||
const XMLElement* N = snapshots_doc_.RootElement();
|
||||
for( ; N ; N=N->NextSiblingElement()) {
|
||||
|
||||
char c;
|
||||
u_int64_t id = 0;
|
||||
std::istringstream nodename( N->Name() );
|
||||
nodename >> c >> id;
|
||||
snapshots_.push_back(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Action::store(const std::string &label)
|
||||
@@ -47,19 +68,17 @@ void Action::store(const std::string &label)
|
||||
|
||||
// incremental naming of history nodes
|
||||
history_step_++;
|
||||
std::string nodename = "H" + std::to_string(history_step_);
|
||||
|
||||
// erase future
|
||||
for (uint e = history_step_; e <= history_max_step_; e++) {
|
||||
std::string name = "H" + std::to_string(e);
|
||||
XMLElement *node = history_doc_.FirstChildElement( name.c_str() );
|
||||
XMLElement *node = history_doc_.FirstChildElement( HISTORY_NODE(e) );
|
||||
if ( node )
|
||||
history_doc_.DeleteChild(node);
|
||||
}
|
||||
history_max_step_ = history_step_;
|
||||
|
||||
// create history node
|
||||
XMLElement *sessionNode = history_doc_.NewElement( nodename.c_str() );
|
||||
XMLElement *sessionNode = history_doc_.NewElement( HISTORY_NODE(history_step_) );
|
||||
history_doc_.InsertEndChild(sessionNode);
|
||||
// label describes the action
|
||||
sessionNode->SetAttribute("label", label.c_str());
|
||||
@@ -76,7 +95,7 @@ void Action::store(const std::string &label)
|
||||
|
||||
// debug
|
||||
#ifdef ACTION_DEBUG
|
||||
Log::Info("Action stored %s '%s'", nodename.c_str(), label.c_str());
|
||||
Log::Info("Action stored %d '%s'", history_step_, label.c_str());
|
||||
// XMLSaveDoc(&xmlDoc_, "/home/bhbn/history.xml");
|
||||
#endif
|
||||
}
|
||||
@@ -117,8 +136,7 @@ std::string Action::label(uint s) const
|
||||
std::string l = "";
|
||||
|
||||
if (s > 0 && s <= history_max_step_) {
|
||||
std::string nodename = "H" + std::to_string(s);
|
||||
const XMLElement *sessionNode = history_doc_.FirstChildElement( nodename.c_str() );
|
||||
const XMLElement *sessionNode = history_doc_.FirstChildElement( HISTORY_NODE(s));
|
||||
l = sessionNode->Attribute("label");
|
||||
}
|
||||
return l;
|
||||
@@ -131,8 +149,7 @@ void Action::restore(uint target)
|
||||
|
||||
// get history node of target step
|
||||
history_step_ = CLAMP(target, 1, history_max_step_);
|
||||
std::string nodename = "H" + std::to_string(history_step_);
|
||||
XMLElement *sessionNode = history_doc_.FirstChildElement( nodename.c_str() );
|
||||
XMLElement *sessionNode = history_doc_.FirstChildElement( HISTORY_NODE(history_step_) );
|
||||
|
||||
if (sessionNode) {
|
||||
|
||||
@@ -156,13 +173,15 @@ void Action::snapshot(const std::string &label)
|
||||
if (locked_ || label.empty())
|
||||
return;
|
||||
|
||||
// create snapshot id
|
||||
u_int64_t id = GlmToolkit::uniqueId();
|
||||
snapshots_.push_back(id);
|
||||
|
||||
// create history node
|
||||
XMLElement *sessionNode = snapshots_doc_.NewElement( std::to_string(id).c_str() );
|
||||
// create snapshot node
|
||||
XMLElement *sessionNode = snapshots_doc_.NewElement( SNAPSHOT_NODE(id) );
|
||||
snapshots_doc_.InsertEndChild(sessionNode);
|
||||
// label describes the action
|
||||
|
||||
// label describes the snapshot
|
||||
sessionNode->SetAttribute("label", label.c_str());
|
||||
|
||||
// get session to operate on
|
||||
@@ -173,17 +192,29 @@ void Action::snapshot(const std::string &label)
|
||||
for (auto iter = se->begin(); iter != se->end(); iter++, sv.setRoot(sessionNode) )
|
||||
(*iter)->accept(sv);
|
||||
|
||||
// TODO: copy action history instead?
|
||||
|
||||
// debug
|
||||
#ifdef ACTION_DEBUG
|
||||
Log::Info("Snapshot stored %s '%s'", std::to_string(id).c_str(), label.c_str());
|
||||
Log::Info("Snapshot stored %d '%s'", id, label.c_str());
|
||||
// XMLSaveDoc(&xmlDoc_, "/home/bhbn/history.xml");
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string Action::label(uint64_t s) const
|
||||
const char *Action::snapshotsDescription()
|
||||
{
|
||||
// get compact string
|
||||
XMLPrinter xmlPrint;
|
||||
snapshots_doc_.Print( &xmlPrint );
|
||||
|
||||
return xmlPrint.CStr();
|
||||
}
|
||||
|
||||
|
||||
std::string Action::label(uint64_t snapshotid) const
|
||||
{
|
||||
std::string l = "";
|
||||
const XMLElement *sessionNode = snapshots_doc_.FirstChildElement( std::to_string(s).c_str() );
|
||||
const XMLElement *sessionNode = snapshots_doc_.FirstChildElement( SNAPSHOT_NODE(snapshotid) );
|
||||
|
||||
if (sessionNode) {
|
||||
l = sessionNode->Attribute("label");
|
||||
@@ -194,7 +225,7 @@ std::string Action::label(uint64_t s) const
|
||||
void Action::setLabel (uint64_t snapshotid, const std::string &label)
|
||||
{
|
||||
// get history node of target
|
||||
XMLElement *sessionNode = snapshots_doc_.FirstChildElement( std::to_string(snapshotid).c_str() );
|
||||
XMLElement *sessionNode = snapshots_doc_.FirstChildElement( SNAPSHOT_NODE(snapshotid) );
|
||||
|
||||
if (sessionNode) {
|
||||
sessionNode->SetAttribute("label", label.c_str());
|
||||
@@ -204,7 +235,7 @@ void Action::setLabel (uint64_t snapshotid, const std::string &label)
|
||||
void Action::remove(uint64_t snapshotid)
|
||||
{
|
||||
// get history node of target
|
||||
XMLElement *sessionNode = snapshots_doc_.FirstChildElement( std::to_string(snapshotid).c_str() );
|
||||
XMLElement *sessionNode = snapshots_doc_.FirstChildElement( SNAPSHOT_NODE(snapshotid) );
|
||||
|
||||
if (sessionNode) {
|
||||
snapshots_doc_.DeleteChild( sessionNode );
|
||||
@@ -218,7 +249,7 @@ void Action::restore(uint64_t snapshotid)
|
||||
locked_ = true;
|
||||
|
||||
// get history node of target
|
||||
XMLElement *sessionNode = snapshots_doc_.FirstChildElement( std::to_string(snapshotid).c_str() );
|
||||
XMLElement *sessionNode = snapshots_doc_.FirstChildElement( SNAPSHOT_NODE(snapshotid) );
|
||||
|
||||
if (sessionNode) {
|
||||
// actually restore
|
||||
|
||||
+10
-5
@@ -23,9 +23,10 @@ public:
|
||||
static Action _instance;
|
||||
return _instance;
|
||||
}
|
||||
void init(const std::string &xml = "");
|
||||
|
||||
// UNDO History
|
||||
void store(const std::string &label);
|
||||
void clear();
|
||||
void undo();
|
||||
void redo();
|
||||
void stepTo(uint target);
|
||||
@@ -34,23 +35,27 @@ public:
|
||||
inline uint max() const { return history_max_step_; }
|
||||
std::string label(uint s) const;
|
||||
|
||||
// Snapshots
|
||||
void snapshot(const std::string &label);
|
||||
|
||||
inline std::list<uint64_t> snapshots() const { return snapshots_; }
|
||||
std::string label(uint64_t s) const;
|
||||
void restore(uint64_t snapshotid);
|
||||
void remove (uint64_t snapshotid);
|
||||
|
||||
std::string label(uint64_t snapshotid) const;
|
||||
void setLabel (uint64_t snapshotid, const std::string &label);
|
||||
|
||||
private:
|
||||
const char *snapshotsDescription();
|
||||
|
||||
void restore(uint target);
|
||||
// inline const tinyxml2::XMLElement *snapshotsRoot() const { return snapshots_doc_.RootElement(); }
|
||||
|
||||
private:
|
||||
|
||||
tinyxml2::XMLDocument history_doc_;
|
||||
uint history_step_;
|
||||
uint history_max_step_;
|
||||
std::atomic<bool> locked_;
|
||||
|
||||
void restore(uint target);
|
||||
|
||||
tinyxml2::XMLDocument snapshots_doc_;
|
||||
std::list<uint64_t> snapshots_;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "Mixer.h"
|
||||
#include "defines.h"
|
||||
#include "Source.h"
|
||||
#include "Settings.h"
|
||||
#include "PickingVisitor.h"
|
||||
#include "DrawVisitor.h"
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "Mixer.h"
|
||||
#include "defines.h"
|
||||
#include "Source.h"
|
||||
#include "Settings.h"
|
||||
#include "Decorations.h"
|
||||
#include "UserInterfaceManager.h"
|
||||
|
||||
@@ -1164,7 +1164,7 @@ void Mixer::swap()
|
||||
back_session_ = nullptr;
|
||||
|
||||
// reset History manager
|
||||
Action::manager().clear();
|
||||
Action::manager().init( session_->snapshots() );
|
||||
|
||||
// notification
|
||||
Log::Notify("Session %s loaded. %d source(s) created.", session_->filename().c_str(), session_->numSource());
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "Mixer.h"
|
||||
#include "defines.h"
|
||||
#include "Source.h"
|
||||
#include "Settings.h"
|
||||
#include "Decorations.h"
|
||||
#include "UserInterfaceManager.h"
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "defines.h"
|
||||
#include "Source.h"
|
||||
#include "Settings.h"
|
||||
#include "FrameBuffer.h"
|
||||
#include "Session.h"
|
||||
@@ -16,7 +17,7 @@ SessionNote::SessionNote(const std::string &t, bool l, int s): label(std::to_str
|
||||
{
|
||||
}
|
||||
|
||||
Session::Session() : failedSource_(nullptr), active_(true), fading_target_(0.f), filename_("")
|
||||
Session::Session() : active_(true), filename_(""), failedSource_(nullptr), snapshots_(""), fading_target_(0.f)
|
||||
{
|
||||
config_[View::RENDERING] = new Group;
|
||||
config_[View::RENDERING]->scale_ = glm::vec3(0.f);
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "SourceList.h"
|
||||
#include "RenderView.h"
|
||||
#include "Source.h"
|
||||
|
||||
class FrameGrabber;
|
||||
class MixingGroup;
|
||||
@@ -21,6 +21,16 @@ struct SessionNote
|
||||
SessionNote(const std::string &t = "", bool l = false, int s = 0);
|
||||
};
|
||||
|
||||
struct SessionSnapshot
|
||||
{
|
||||
uint64_t id;
|
||||
std::string label;
|
||||
std::string xml;
|
||||
|
||||
SessionSnapshot(const std::string &l, const std::string &desc);
|
||||
};
|
||||
|
||||
|
||||
class Session
|
||||
{
|
||||
public:
|
||||
@@ -110,13 +120,15 @@ public:
|
||||
std::list<MixingGroup *>::iterator deleteMixingGroup (std::list<MixingGroup *>::iterator g);
|
||||
|
||||
// snapshots
|
||||
|
||||
void setSnapshots (const std::string &xml) { snapshots_ = xml; }
|
||||
std::string snapshots () const { return snapshots_; }
|
||||
|
||||
// lock and unlock access (e.g. while saving)
|
||||
void lock ();
|
||||
void unlock ();
|
||||
|
||||
protected:
|
||||
bool active_;
|
||||
RenderView render_;
|
||||
std::string filename_;
|
||||
Source *failedSource_;
|
||||
@@ -125,7 +137,7 @@ protected:
|
||||
std::list<SessionNote> notes_;
|
||||
std::list<MixingGroup *> mixing_groups_;
|
||||
std::map<View::Mode, Group*> config_;
|
||||
bool active_;
|
||||
std::string snapshots_;
|
||||
std::list<FrameGrabber *> grabbers_;
|
||||
float fading_target_;
|
||||
std::mutex access_;
|
||||
|
||||
@@ -100,6 +100,10 @@ void SessionCreator::load(const std::string& filename)
|
||||
for (auto group_it = groups.begin(); group_it != groups.end(); group_it++)
|
||||
session_->link( *group_it );
|
||||
|
||||
// load snapshots
|
||||
loadSnapshots( xmlDoc_.FirstChildElement("Snapshots") );
|
||||
|
||||
// load notes
|
||||
loadNotes( xmlDoc_.FirstChildElement("Notes") );
|
||||
|
||||
// all good
|
||||
@@ -119,6 +123,15 @@ void SessionCreator::loadConfig(XMLElement *viewsNode)
|
||||
}
|
||||
}
|
||||
|
||||
void SessionCreator::loadSnapshots(XMLElement *snapshotsNode)
|
||||
{
|
||||
if (snapshotsNode != nullptr && session_ != nullptr) {
|
||||
|
||||
std::string text = std::string ( snapshotsNode->GetText() );
|
||||
session_->setSnapshots( text );
|
||||
}
|
||||
}
|
||||
|
||||
void SessionCreator::loadNotes(XMLElement *notesNode)
|
||||
{
|
||||
if (notesNode != nullptr && session_ != nullptr) {
|
||||
|
||||
@@ -79,6 +79,7 @@ class SessionCreator : public SessionLoader {
|
||||
|
||||
void loadConfig(tinyxml2::XMLElement *viewsNode);
|
||||
void loadNotes(tinyxml2::XMLElement *notesNode);
|
||||
void loadSnapshots(tinyxml2::XMLElement *snapshotNode);
|
||||
|
||||
public:
|
||||
SessionCreator(int recursion = 0);
|
||||
|
||||
+13
-1
@@ -16,6 +16,7 @@
|
||||
#include "MediaPlayer.h"
|
||||
#include "MixingGroup.h"
|
||||
#include "SystemToolkit.h"
|
||||
#include "ActionManager.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <locale>
|
||||
@@ -73,7 +74,17 @@ bool SessionVisitor::saveSession(const std::string& filename, Session *session)
|
||||
views->InsertEndChild(render);
|
||||
}
|
||||
|
||||
// 3. optional notes
|
||||
// 3. snapshots
|
||||
XMLElement *snapshots = xmlDoc.NewElement("Snapshots");
|
||||
// const XMLElement* N = Action::manager().snapshotsRoot();
|
||||
// for( ; N ; N=N->NextSiblingElement())
|
||||
// snapshots->InsertEndChild( N->DeepClone( &xmlDoc ));
|
||||
|
||||
XMLText *text = xmlDoc.NewText( Action::manager().snapshotsDescription() );
|
||||
snapshots->InsertEndChild( text );
|
||||
xmlDoc.InsertEndChild(snapshots);
|
||||
|
||||
// 4. optional notes
|
||||
XMLElement *notes = xmlDoc.NewElement("Notes");
|
||||
xmlDoc.InsertEndChild(notes);
|
||||
for (auto nit = session->beginNotes(); nit != session->endNotes(); ++nit) {
|
||||
@@ -94,6 +105,7 @@ bool SessionVisitor::saveSession(const std::string& filename, Session *session)
|
||||
notes->InsertEndChild(note);
|
||||
}
|
||||
|
||||
|
||||
// save file to disk
|
||||
return ( XMLSaveDoc(&xmlDoc, filename) );
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "defines.h"
|
||||
#include "Mixer.h"
|
||||
#include "Source.h"
|
||||
#include "Settings.h"
|
||||
#include "Resource.h"
|
||||
#include "PickingVisitor.h"
|
||||
|
||||
@@ -257,6 +257,9 @@ void UserInterface::handleKeyboard()
|
||||
FrameGrabbing::manager().add(fg);
|
||||
}
|
||||
}
|
||||
else if (ImGui::IsKeyPressed( GLFW_KEY_Y )) {
|
||||
Action::manager().snapshot( SystemToolkit::date_time_string() );
|
||||
}
|
||||
else if (ImGui::IsKeyPressed( GLFW_KEY_Z )) {
|
||||
if (shift_modifier_active)
|
||||
Action::manager().redo();
|
||||
@@ -286,6 +289,7 @@ void UserInterface::handleKeyboard()
|
||||
else if (ImGui::IsKeyPressed( GLFW_KEY_N ) && shift_modifier_active) {
|
||||
Mixer::manager().session()->addNote();
|
||||
}
|
||||
|
||||
}
|
||||
// No CTRL modifier
|
||||
else {
|
||||
@@ -802,7 +806,7 @@ void UserInterface::showMenuEdit()
|
||||
if ( ImGui::MenuItem( ICON_FA_REDO " Redo", CTRL_MOD "Shift+Z") )
|
||||
Action::manager().redo();
|
||||
if ( ImGui::MenuItem( ICON_FA_STAR "+ Snapshot", CTRL_MOD "Y") )
|
||||
Action::manager().redo();
|
||||
Action::manager().snapshot( SystemToolkit::date_time_string() );
|
||||
}
|
||||
|
||||
void UserInterface::showMenuFile()
|
||||
@@ -3191,7 +3195,6 @@ void Navigator::RenderMainPannelVimix()
|
||||
// right buttons
|
||||
ImGui::SetCursorPos( ImVec2( pannel_width_ IMGUI_RIGHT_ALIGN, pos_top.y ));
|
||||
if ( ImGuiToolkit::IconButton( ICON_FA_STAR "+")) {
|
||||
// snapshots.push_back( SystemToolkit::date_time_string() );
|
||||
Action::manager().snapshot( SystemToolkit::date_time_string() );
|
||||
}
|
||||
// // active list element : delete snapshot button
|
||||
|
||||
Reference in New Issue
Block a user