Convert Snapshots into Versions of session

Added auto-snapshot on save to have an Iterative Saving mode, and change terminology of 'snapshots' to 'versions' management.
This commit is contained in:
Bruno Herbelin
2021-11-23 22:47:44 +01:00
parent ed7627af6f
commit 5ac7887360
8 changed files with 99 additions and 78 deletions

View File

@@ -202,7 +202,7 @@ void Action::restore(uint target)
void Action::snapshot(const std::string &label)
void Action::snapshot(const std::string &label, bool threaded)
{
// ignore if locked
if (locked_)
@@ -217,8 +217,11 @@ void Action::snapshot(const std::string &label)
Session *se = Mixer::manager().session();
se->snapshots()->keys_.push_back(id);
// threaded capture state of current session
std::thread(captureMixerSession, se->snapshots()->xmlDoc_, SNAPSHOT_NODE(id), snap_label).detach();
if (threaded)
// threaded capture state of current session
std::thread(captureMixerSession, se->snapshots()->xmlDoc_, SNAPSHOT_NODE(id), snap_label).detach();
else
captureMixerSession(se->snapshots()->xmlDoc_, SNAPSHOT_NODE(id), snap_label);
#ifdef ACTION_DEBUG
Log::Info("Snapshot stored %d '%s'", id, snap_label.c_str());
@@ -321,6 +324,12 @@ FrameBufferImage *Action::thumbnail(uint64_t snapshotid) const
return img;
}
void Action::clearSnapshots()
{
Session *se = Mixer::manager().session();
se->snapshots()->keys_.clear();
}
void Action::remove(uint64_t snapshotid)
{
if (snapshotid > 0)

View File

@@ -39,8 +39,8 @@ public:
FrameBufferImage *thumbnail (uint s) const;
// Snapshots
void snapshot (const std::string &label = "");
void snapshot (const std::string &label = "", bool threaded = false);
void clearSnapshots ();
std::list<uint64_t> snapshots () const;
uint64_t currentSnapshot () const { return snapshot_id_; }

View File

@@ -62,8 +62,12 @@ const std::chrono::milliseconds timeout_ = std::chrono::milliseconds(4);
// static multithreaded session saving
static void saveSession(const std::string& filename, Session *session)
static void saveSession(const std::string& filename, Session *session, bool with_version)
{
// capture a snapshot of current version if requested
if (with_version)
Action::manager().snapshot( SystemToolkit::date_time_string());
// lock access while saving
session->lock();
@@ -971,13 +975,13 @@ View *Mixer::view(View::Mode m)
}
}
void Mixer::save()
void Mixer::save(bool with_version)
{
if (!session_->filename().empty())
saveas(session_->filename());
saveas(session_->filename(), with_version);
}
void Mixer::saveas(const std::string& filename)
void Mixer::saveas(const std::string& filename, bool with_version)
{
// optional copy of views config
session_->config(View::MIXING)->copyTransform( mixing_.scene.root() );
@@ -986,7 +990,7 @@ void Mixer::saveas(const std::string& filename)
session_->config(View::TEXTURE)->copyTransform( appearance_.scene.root() );
// launch a thread to save the session
std::thread (saveSession, filename, session_).detach();
std::thread (saveSession, filename, session_, with_version).detach();
}
void Mixer::load(const std::string& filename)

View File

@@ -99,8 +99,8 @@ public:
// manipulate, load and save sessions
inline Session *session () const { return session_; }
void clear ();
void save ();
void saveas (const std::string& filename);
void save (bool with_version = false);
void saveas (const std::string& filename, bool with_version = false);
void load (const std::string& filename);
void import (const std::string& filename);
void import (SessionSource *source);

View File

@@ -85,11 +85,11 @@ void Settings::Save(uint64_t runtime)
applicationNode->SetAttribute("scale", application.scale);
applicationNode->SetAttribute("accent_color", application.accent_color);
applicationNode->SetAttribute("smooth_transition", application.smooth_transition);
applicationNode->SetAttribute("smooth_snapshot", application.smooth_snapshot);
applicationNode->SetAttribute("save_snapshot", application.save_version_snapshot);
applicationNode->SetAttribute("smooth_cursor", application.smooth_cursor);
applicationNode->SetAttribute("action_history_follow_view", application.action_history_follow_view);
applicationNode->SetAttribute("accept_connections", application.accept_connections);
applicationNode->SetAttribute("pannel_history_mode", application.pannel_history_mode);
applicationNode->SetAttribute("pannel_history_mode", application.pannel_current_session_mode);
pRoot->InsertEndChild(applicationNode);
// Widgets
@@ -312,11 +312,11 @@ void Settings::Load()
applicationNode->QueryFloatAttribute("scale", &application.scale);
applicationNode->QueryIntAttribute("accent_color", &application.accent_color);
applicationNode->QueryBoolAttribute("smooth_transition", &application.smooth_transition);
applicationNode->QueryBoolAttribute("smooth_snapshot", &application.smooth_snapshot);
applicationNode->QueryBoolAttribute("save_snapshot", &application.save_version_snapshot);
applicationNode->QueryBoolAttribute("smooth_cursor", &application.smooth_cursor);
applicationNode->QueryBoolAttribute("action_history_follow_view", &application.action_history_follow_view);
applicationNode->QueryBoolAttribute("accept_connections", &application.accept_connections);
applicationNode->QueryIntAttribute("pannel_history_mode", &application.pannel_history_mode);
applicationNode->QueryIntAttribute("pannel_history_mode", &application.pannel_current_session_mode);
}
// Widgets

View File

@@ -203,12 +203,12 @@ struct Application
// Global settings Application interface
float scale;
int accent_color;
bool smooth_snapshot;
bool save_version_snapshot;
bool smooth_transition;
bool smooth_cursor;
bool action_history_follow_view;
int pannel_history_mode;
int pannel_current_session_mode;
// connection settings
bool accept_connections;
@@ -252,11 +252,11 @@ struct Application
scale = 1.f;
accent_color = 0;
smooth_transition = false;
smooth_snapshot = false;
save_version_snapshot = false;
smooth_cursor = false;
action_history_follow_view = false;
accept_connections = false;
pannel_history_mode = 0;
pannel_current_session_mode = 0;
current_view = 1;
current_workspace= 1;
brush = glm::vec3(0.5f, 0.1f, 0.f);

View File

@@ -249,11 +249,12 @@ void UserInterface::handleKeyboard()
selectOpenFilename();
}
else if (ImGui::IsKeyPressed( GLFW_KEY_S )) {
// Save Session
if (shift_modifier_active || Mixer::manager().session()->filename().empty())
// SHIFT + CTRL + S : save as
if (shift_modifier_active)
selectSaveFilename();
// CTRL + S : save (save as if necessary)
else
Mixer::manager().save();
saveOrSaveAs();
}
else if (ImGui::IsKeyPressed( GLFW_KEY_W )) {
// New Session
@@ -326,9 +327,6 @@ void UserInterface::handleKeyboard()
}
}
}
else if (ImGui::IsKeyPressed( GLFW_KEY_Y )) {
Action::manager().snapshot( "Snap" );
}
else if (ImGui::IsKeyPressed( GLFW_KEY_Z )) {
if (shift_modifier_active)
Action::manager().redo();
@@ -703,6 +701,20 @@ void UserInterface::handleMouse()
}
}
bool UserInterface::saveOrSaveAs(bool force_versioning)
{
bool finished = false;
if (Mixer::manager().session()->filename().empty())
selectSaveFilename();
else {
Mixer::manager().save(force_versioning || Settings::application.save_version_snapshot);
finished = true;
}
return finished;
}
void UserInterface::selectSaveFilename()
{
if (sessionsavedialog)
@@ -740,7 +752,7 @@ void UserInterface::NewFrame()
Mixer::manager().import(sessionimportdialog->path());
if (sessionsavedialog && sessionsavedialog->closed() && !sessionsavedialog->path().empty())
Mixer::manager().saveas(sessionsavedialog->path());
Mixer::manager().saveas(sessionsavedialog->path(), Settings::application.save_version_snapshot);
// overlay to ensure file dialog is modal
if (DialogToolkit::FileDialog::busy()){
@@ -839,7 +851,7 @@ void UserInterface::Render()
void UserInterface::Terminate()
{
if (Settings::application.recentSessions.save_on_exit)
Mixer::manager().save();
Mixer::manager().save(false);
// Cleanup
ImGui_ImplOpenGL3_Shutdown();
@@ -880,8 +892,6 @@ void UserInterface::showMenuEdit()
Action::manager().undo();
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().snapshot( "Snap" );
}
void UserInterface::showMenuFile()
@@ -910,12 +920,8 @@ void UserInterface::showMenuFile()
navigator.hidePannel();
}
if (ImGui::MenuItem( ICON_FA_FILE_DOWNLOAD " Save", CTRL_MOD "S")) {
if (Mixer::manager().session()->filename().empty())
selectSaveFilename();
else {
Mixer::manager().save();
if (saveOrSaveAs())
navigator.hidePannel();
}
}
if (ImGui::MenuItem( ICON_FA_FILE_DOWNLOAD " Save as", CTRL_MOD "Shift+S"))
selectSaveFilename();
@@ -4440,7 +4446,6 @@ void Navigator::RenderMainPannelVimix()
ImVec2 pos_bot = ImGui::GetCursorPos();
// Right side of the list: helper and options
ImGui::SetCursorPos( ImVec2( pannel_width_ IMGUI_RIGHT_ALIGN, pos_top.y));
if ( ImGuiToolkit::IconButton( ICON_FA_FILE " +" )) {
@@ -4464,20 +4469,20 @@ void Navigator::RenderMainPannelVimix()
// come back...
ImGui::SetCursorPos(pos_bot);
//
// Status
//
ImGuiToolkit::Spacing();
ImGui::Text("Current");
ImGui::Text("Current session");
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
ImGui::Combo("##SelectHistory", &Settings::application.pannel_history_mode,
ICON_FA_STAR " Snapshots\0" ICON_FA_HISTORY " Undo history\0" ICON_FA_FILE_ALT " Properties\0");
ImGui::Combo("##Selectpanelsession", &Settings::application.pannel_current_session_mode,
ICON_FA_CODE_BRANCH " Versions\0" ICON_FA_HISTORY " Undo history\0" ICON_FA_FILE_ALT " Properties\0");
pos_bot = ImGui::GetCursorPos();
//
// Current 2. PROPERTIES
//
if (Settings::application.pannel_history_mode > 1) {
if (Settings::application.pannel_current_session_mode > 1) {
std::string sessionfilename = Mixer::manager().session()->filename();
@@ -4583,7 +4588,7 @@ void Navigator::RenderMainPannelVimix()
if (_file_thumbnail.filled()) {
ImGui::BeginTooltip();
_file_thumbnail.Render(230);
ImGui::Text("Thumbnail will be used in\nthe sessions list above.");
ImGui::Text("Thumbnail used in the\nlist of Sessions above.");
ImGui::EndTooltip();
}
}
@@ -4610,12 +4615,21 @@ void Navigator::RenderMainPannelVimix()
//
// Current 1. UNDO History
//
else if (Settings::application.pannel_history_mode > 0) {
else if (Settings::application.pannel_current_session_mode > 0) {
static uint _over = 0;
static uint64_t _displayed_over = 0;
static bool _tooltip = 0;
ImGui::SameLine();
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.7);
if (ImGuiToolkit::IconButton( ICON_FA_BACKSPACE, "Clear undo")) {
Action::manager().init();
}
ImGui::PopStyleVar();
// come back...
ImGui::SetCursorPos(pos_bot);
pos_top = ImGui::GetCursorPos();
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if ( ImGui::ListBoxHeader("##UndoHistory", Action::manager().max(), CLAMP(Action::manager().max(), 4, 8)) ) {
@@ -4696,12 +4710,21 @@ void Navigator::RenderMainPannelVimix()
ImGuiToolkit::ToolTip("Show in view");
}
//
// Current 0. SNAPSHOTS
// Current 0. VERSIONS
//
else {
static uint64_t _over = 0;
static bool _tooltip = 0;
ImGui::SameLine();
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.7);
if (ImGuiToolkit::IconButton( ICON_FA_BACKSPACE, "Clear versions")) {
Action::manager().clearSnapshots();
}
ImGui::PopStyleVar();
// come back...
ImGui::SetCursorPos(pos_bot);
// list snapshots
std::list<uint64_t> snapshots = Action::manager().snapshots();
pos_top = ImGui::GetCursorPos();
@@ -4714,7 +4737,7 @@ void Navigator::RenderMainPannelVimix()
int count_over = 0;
ImVec2 size = ImVec2( ImGui::GetContentRegionAvailWidth(), ImGui::GetTextLineHeight() );
for (auto snapit = snapshots.begin(); snapit != snapshots.end(); ++snapit)
for (auto snapit = snapshots.rbegin(); snapit != snapshots.rend(); ++snapit)
{
// entry
ImVec2 pos = ImGui::GetCursorPos();
@@ -4780,7 +4803,7 @@ void Navigator::RenderMainPannelVimix()
if (ImGui::BeginPopup( "MenuSnapshot" ) && current > 0 )
{
_selected = current;
ImGui::TextDisabled("Edit snapshot");
ImGui::TextDisabled("Edit");
// snapshot editable label
ImGui::SetNextItemWidth(size.x);
if ( ImGuiToolkit::InputText("##Rename", &_snap_label ) )
@@ -4788,12 +4811,10 @@ void Navigator::RenderMainPannelVimix()
// snapshot thumbnail
_snap_thumbnail.Render(size.x);
// snapshot actions
if (ImGui::Selectable( " " ICON_FA_ANGLE_DOUBLE_RIGHT " Apply", false, 0, size ))
if (ImGui::Selectable( " " ICON_FA_ANGLE_DOUBLE_RIGHT " Restore", false, 0, size ))
Action::manager().restore();
if (ImGui::Selectable( ICON_FA_STAR "_ Remove", false, 0, size ))
if (ImGui::Selectable( ICON_FA_CODE_BRANCH "_ Remove", false, 0, size ))
Action::manager().remove();
if (ImGui::Selectable( ICON_FA_STAR "= Replace", false, 0, size ))
Action::manager().replace();
ImGui::EndPopup();
}
else
@@ -4813,36 +4834,22 @@ void Navigator::RenderMainPannelVimix()
// right buttons
ImGui::SetCursorPos( ImVec2( pannel_width_ IMGUI_RIGHT_ALIGN, pos_top.y ));
if ( ImGuiToolkit::IconButton( ICON_FA_STAR "+"))
Action::manager().snapshot( "Snap" );
if ( ImGuiToolkit::IconButton( ICON_FA_FILE_DOWNLOAD " +")) {
UserInterface::manager().saveOrSaveAs(true);
}
if (ImGui::IsItemHovered())
ImGuiToolkit::ToolTip("Take Snapshot ", CTRL_MOD "Y");
ImGuiToolkit::ToolTip("Save & Keep version");
ImGui::SetCursorPos( ImVec2( pannel_width_ IMGUI_RIGHT_ALIGN, pos_bot.y - ImGui::GetFrameHeightWithSpacing()));
ImGuiToolkit::HelpMarker("Snapshots keep a list of favorite\n"
"status of the current session.\n\n"
"Clic an item to preview or edit.\n"
"Double-clic to apply.\n");
// ImGui::SetCursorPos( ImVec2( pannel_width_ IMGUI_RIGHT_ALIGN, pos_bot.y - 2.f * ImGui::GetFrameHeightWithSpacing()));
// ImGuiToolkit::HelpMarker("Snapshots capture the state of the session.\n"
// "Double-clic on a snapshot to restore it.\n\n"
// ICON_FA_ROUTE " Enable interpolation to animate\n"
// "from current state to snapshot's state.");
// // toggle button for smooth interpolation
// ImGui::SetCursorPos( ImVec2( pannel_width_ IMGUI_RIGHT_ALIGN, pos_bot.y - ImGui::GetFrameHeightWithSpacing()) );
// ImGuiToolkit::ButtonToggle(ICON_FA_ROUTE, &Settings::application.smooth_snapshot);
// if (ImGui::IsItemHovered())
// ImGuiToolkit::ToolTip("Snapshot interpolation");
// if (Action::manager().currentSnapshot() > 0) {
// ImGui::SetCursorPos( pos_bot );
// int interpolation = static_cast<int> (Action::manager().interpolation() * 100.f);
// ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
// if ( ImGui::SliderInt("Animate", &interpolation, 0, 100, "%d %%") )
// Action::manager().interpolate( static_cast<float> ( interpolation ) * 0.01f );
// }
ImGui::SetCursorPos( ImVec2( pannel_width_ IMGUI_RIGHT_ALIGN, pos_bot.y - 2.f * ImGui::GetFrameHeightWithSpacing()));
ImGuiToolkit::HelpMarker("Previous versions of the session (latest on top).\n"
"Double-clic on a version to restore it.\n\n"
ICON_FA_CODE_BRANCH " Enable iterative saving to automatically\n"
"keep a version each time a session is saved.");
// toggle button for versioning
ImGui::SetCursorPos( ImVec2( pannel_width_ IMGUI_RIGHT_ALIGN, pos_bot.y - ImGui::GetFrameHeightWithSpacing()) );
ImGuiToolkit::ButtonToggle(" " ICON_FA_CODE_BRANCH " ", &Settings::application.save_version_snapshot);
if (ImGui::IsItemHovered())
ImGuiToolkit::ToolTip("Iterative saving");
ImGui::SetCursorPos( pos_bot );
}

View File

@@ -254,6 +254,7 @@ protected:
void showMenuFile();
void showMenuEdit();
bool saveOrSaveAs(bool force_versioning = false);
void selectSaveFilename();
void selectOpenFilename();