mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-11 18:34:58 +01:00
Snapshots in Action manager
This commit is contained in:
@@ -10,6 +10,7 @@
|
|||||||
#include "SessionVisitor.h"
|
#include "SessionVisitor.h"
|
||||||
#include "SessionCreator.h"
|
#include "SessionCreator.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
|
#include "GlmToolkit.h"
|
||||||
|
|
||||||
#include "ActionManager.h"
|
#include "ActionManager.h"
|
||||||
|
|
||||||
@@ -19,16 +20,20 @@
|
|||||||
|
|
||||||
using namespace tinyxml2;
|
using namespace tinyxml2;
|
||||||
|
|
||||||
Action::Action(): step_(0), max_step_(0)
|
Action::Action(): history_step_(0), history_max_step_(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Action::clear()
|
void Action::clear()
|
||||||
{
|
{
|
||||||
// clean the history
|
// clean the history
|
||||||
xmlDoc_.Clear();
|
history_doc_.Clear();
|
||||||
step_ = 0;
|
history_step_ = 0;
|
||||||
max_step_ = 0;
|
history_max_step_ = 0;
|
||||||
|
|
||||||
|
// clean the snapshots
|
||||||
|
snapshots_doc_.Clear();
|
||||||
|
snapshots_.clear();
|
||||||
|
|
||||||
// start fresh
|
// start fresh
|
||||||
store("Session start");
|
store("Session start");
|
||||||
@@ -41,21 +46,21 @@ void Action::store(const std::string &label)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// incremental naming of history nodes
|
// incremental naming of history nodes
|
||||||
step_++;
|
history_step_++;
|
||||||
std::string nodename = "H" + std::to_string(step_);
|
std::string nodename = "H" + std::to_string(history_step_);
|
||||||
|
|
||||||
// erase future
|
// erase future
|
||||||
for (uint e = step_; e <= max_step_; e++) {
|
for (uint e = history_step_; e <= history_max_step_; e++) {
|
||||||
std::string name = "H" + std::to_string(e);
|
std::string name = "H" + std::to_string(e);
|
||||||
XMLElement *node = xmlDoc_.FirstChildElement( name.c_str() );
|
XMLElement *node = history_doc_.FirstChildElement( name.c_str() );
|
||||||
if ( node )
|
if ( node )
|
||||||
xmlDoc_.DeleteChild(node);
|
history_doc_.DeleteChild(node);
|
||||||
}
|
}
|
||||||
max_step_ = step_;
|
history_max_step_ = history_step_;
|
||||||
|
|
||||||
// create history node
|
// create history node
|
||||||
XMLElement *sessionNode = xmlDoc_.NewElement( nodename.c_str() );
|
XMLElement *sessionNode = history_doc_.NewElement( nodename.c_str() );
|
||||||
xmlDoc_.InsertEndChild(sessionNode);
|
history_doc_.InsertEndChild(sessionNode);
|
||||||
// label describes the action
|
// label describes the action
|
||||||
sessionNode->SetAttribute("label", label.c_str());
|
sessionNode->SetAttribute("label", label.c_str());
|
||||||
// view indicates the view when this action occured
|
// view indicates the view when this action occured
|
||||||
@@ -65,7 +70,7 @@ void Action::store(const std::string &label)
|
|||||||
Session *se = Mixer::manager().session();
|
Session *se = Mixer::manager().session();
|
||||||
|
|
||||||
// save all sources using source visitor
|
// save all sources using source visitor
|
||||||
SessionVisitor sv(&xmlDoc_, sessionNode);
|
SessionVisitor sv(&history_doc_, sessionNode);
|
||||||
for (auto iter = se->begin(); iter != se->end(); iter++, sv.setRoot(sessionNode) )
|
for (auto iter = se->begin(); iter != se->end(); iter++, sv.setRoot(sessionNode) )
|
||||||
(*iter)->accept(sv);
|
(*iter)->accept(sv);
|
||||||
|
|
||||||
@@ -79,31 +84,31 @@ void Action::store(const std::string &label)
|
|||||||
void Action::undo()
|
void Action::undo()
|
||||||
{
|
{
|
||||||
// not possible to go to 1 -1 = 0
|
// not possible to go to 1 -1 = 0
|
||||||
if (step_ <= 1)
|
if (history_step_ <= 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// restore always changes step_ to step_ - 1
|
// restore always changes step_ to step_ - 1
|
||||||
restore( step_ - 1);
|
restore( history_step_ - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Action::redo()
|
void Action::redo()
|
||||||
{
|
{
|
||||||
// not possible to go to max_step_ + 1
|
// not possible to go to max_step_ + 1
|
||||||
if (step_ >= max_step_)
|
if (history_step_ >= history_max_step_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// restore always changes step_ to step_ + 1
|
// restore always changes step_ to step_ + 1
|
||||||
restore( step_ + 1);
|
restore( history_step_ + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Action::stepTo(uint target)
|
void Action::stepTo(uint target)
|
||||||
{
|
{
|
||||||
// get reasonable target
|
// get reasonable target
|
||||||
uint t = CLAMP(target, 1, max_step_);
|
uint t = CLAMP(target, 1, history_max_step_);
|
||||||
|
|
||||||
// ignore t == step_
|
// ignore t == step_
|
||||||
if (t != step_)
|
if (t != history_step_)
|
||||||
restore(t);
|
restore(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,9 +116,9 @@ std::string Action::label(uint s) const
|
|||||||
{
|
{
|
||||||
std::string l = "";
|
std::string l = "";
|
||||||
|
|
||||||
if (s > 0 && s <= max_step_) {
|
if (s > 0 && s <= history_max_step_) {
|
||||||
std::string nodename = "H" + std::to_string(s);
|
std::string nodename = "H" + std::to_string(s);
|
||||||
const XMLElement *sessionNode = xmlDoc_.FirstChildElement( nodename.c_str() );
|
const XMLElement *sessionNode = history_doc_.FirstChildElement( nodename.c_str() );
|
||||||
l = sessionNode->Attribute("label");
|
l = sessionNode->Attribute("label");
|
||||||
}
|
}
|
||||||
return l;
|
return l;
|
||||||
@@ -125,100 +130,102 @@ void Action::restore(uint target)
|
|||||||
locked_ = true;
|
locked_ = true;
|
||||||
|
|
||||||
// get history node of target step
|
// get history node of target step
|
||||||
step_ = CLAMP(target, 1, max_step_);
|
history_step_ = CLAMP(target, 1, history_max_step_);
|
||||||
std::string nodename = "H" + std::to_string(step_);
|
std::string nodename = "H" + std::to_string(history_step_);
|
||||||
XMLElement *sessionNode = xmlDoc_.FirstChildElement( nodename.c_str() );
|
XMLElement *sessionNode = history_doc_.FirstChildElement( nodename.c_str() );
|
||||||
|
|
||||||
// ask view to refresh, and switch to action view if user prefers
|
if (sessionNode) {
|
||||||
int view = Settings::application.current_view ;
|
|
||||||
if (Settings::application.action_history_follow_view)
|
|
||||||
sessionNode->QueryIntAttribute("view", &view);
|
|
||||||
Mixer::manager().setView( (View::Mode) view);
|
|
||||||
|
|
||||||
#ifdef ACTION_DEBUG
|
// ask view to refresh, and switch to action view if user prefers
|
||||||
Log::Info("Restore %s '%s' ", nodename.c_str(), sessionNode->Attribute("label"));
|
int view = Settings::application.current_view ;
|
||||||
#endif
|
if (Settings::application.action_history_follow_view)
|
||||||
|
sessionNode->QueryIntAttribute("view", &view);
|
||||||
|
Mixer::manager().setView( (View::Mode) view);
|
||||||
|
|
||||||
//
|
// actually restore
|
||||||
// compare source lists
|
Mixer::manager().restore(sessionNode);
|
||||||
//
|
}
|
||||||
|
|
||||||
// we operate on the current session
|
// free
|
||||||
Session *se = Mixer::manager().session();
|
locked_ = false;
|
||||||
if (se == nullptr)
|
}
|
||||||
return;
|
|
||||||
|
void Action::snapshot(const std::string &label)
|
||||||
// sessionsources contains list of ids of all sources currently in the session (before loading)
|
{
|
||||||
SourceIdList session_sources = se->getIdList();
|
// ignore if locked or if no label is given
|
||||||
// for( auto it = sessionsources.begin(); it != sessionsources.end(); it++)
|
if (locked_ || label.empty())
|
||||||
// Log::Info("sessionsources id %s", std::to_string(*it).c_str());
|
return;
|
||||||
|
|
||||||
// load history status:
|
u_int64_t id = GlmToolkit::uniqueId();
|
||||||
// - if a source exists, its attributes are updated, and that's all
|
snapshots_.push_back(id);
|
||||||
// - if a source does not exists (in current session), it is created inside the session
|
|
||||||
SessionLoader loader( se );
|
// create history node
|
||||||
loader.load( sessionNode );
|
XMLElement *sessionNode = snapshots_doc_.NewElement( std::to_string(id).c_str() );
|
||||||
|
snapshots_doc_.InsertEndChild(sessionNode);
|
||||||
// loaded_sources contains map of xml ids of all sources treated by loader
|
// label describes the action
|
||||||
std::map< uint64_t, Source* > loaded_sources = loader.getSources();
|
sessionNode->SetAttribute("label", label.c_str());
|
||||||
|
|
||||||
// remove intersect of both lists (sources were updated by SessionLoader)
|
// get session to operate on
|
||||||
for( auto lsit = loaded_sources.begin(); lsit != loaded_sources.end(); ){
|
Session *se = Mixer::manager().session();
|
||||||
auto ssit = std::find(session_sources.begin(), session_sources.end(), (*lsit).first);
|
|
||||||
if ( ssit != session_sources.end() ) {
|
// save all sources using source visitor
|
||||||
lsit = loaded_sources.erase(lsit);
|
SessionVisitor sv(&snapshots_doc_, sessionNode);
|
||||||
session_sources.erase(ssit);
|
for (auto iter = se->begin(); iter != se->end(); iter++, sv.setRoot(sessionNode) )
|
||||||
}
|
(*iter)->accept(sv);
|
||||||
else
|
|
||||||
lsit++;
|
// debug
|
||||||
}
|
#ifdef ACTION_DEBUG
|
||||||
|
Log::Info("Snapshot stored %s '%s'", std::to_string(id).c_str(), label.c_str());
|
||||||
// remaining ids in list sessionsources : to remove
|
// XMLSaveDoc(&xmlDoc_, "/home/bhbn/history.xml");
|
||||||
while ( !session_sources.empty() ){
|
#endif
|
||||||
Source *s = Mixer::manager().findSource( session_sources.front() );
|
}
|
||||||
if (s!=nullptr) {
|
|
||||||
#ifdef ACTION_DEBUG
|
std::string Action::label(uint64_t s) const
|
||||||
Log::Info("Delete id %s\n", std::to_string(session_sources.front() ).c_str());
|
{
|
||||||
#endif
|
std::string l = "";
|
||||||
// remove the source from the mixer
|
const XMLElement *sessionNode = snapshots_doc_.FirstChildElement( std::to_string(s).c_str() );
|
||||||
Mixer::manager().detach( s );
|
|
||||||
// delete source from session
|
if (sessionNode) {
|
||||||
se->deleteSource( s );
|
l = sessionNode->Attribute("label");
|
||||||
}
|
}
|
||||||
session_sources.pop_front();
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
// remaining sources in list loaded_sources : to add
|
void Action::setLabel (uint64_t snapshotid, const std::string &label)
|
||||||
for ( auto lsit = loaded_sources.begin(); lsit != loaded_sources.end(); lsit++)
|
{
|
||||||
{
|
// get history node of target
|
||||||
#ifdef ACTION_DEBUG
|
XMLElement *sessionNode = snapshots_doc_.FirstChildElement( std::to_string(snapshotid).c_str() );
|
||||||
Log::Info("Recreate id %s to %s\n", std::to_string((*lsit).first).c_str(), std::to_string((*lsit).second->id()).c_str());
|
|
||||||
#endif
|
if (sessionNode) {
|
||||||
// attach created source
|
sessionNode->SetAttribute("label", label.c_str());
|
||||||
Mixer::manager().attach( (*lsit).second );
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
void Action::remove(uint64_t snapshotid)
|
||||||
//
|
{
|
||||||
// compare mixing groups
|
// get history node of target
|
||||||
//
|
XMLElement *sessionNode = snapshots_doc_.FirstChildElement( std::to_string(snapshotid).c_str() );
|
||||||
|
|
||||||
// Get the list of mixing groups in the xml loader
|
if (sessionNode) {
|
||||||
std::list< SourceList > loadergroups = loader.getMixingGroups();
|
snapshots_doc_.DeleteChild( sessionNode );
|
||||||
|
snapshots_.remove(snapshotid);
|
||||||
// clear all session groups
|
}
|
||||||
auto group_iter = se->beginMixingGroup();
|
}
|
||||||
while ( group_iter != se->endMixingGroup() )
|
|
||||||
group_iter = se->deleteMixingGroup(group_iter);
|
void Action::restore(uint64_t snapshotid)
|
||||||
|
{
|
||||||
// apply all changes creating or modifying groups in the session
|
// lock
|
||||||
// (after this, new groups are created and existing groups are adjusted)
|
locked_ = true;
|
||||||
for (auto group_loader_it = loadergroups.begin(); group_loader_it != loadergroups.end(); group_loader_it++) {
|
|
||||||
se->link( *group_loader_it, Mixer::manager().view(View::MIXING)->scene.fg() );
|
// get history node of target
|
||||||
|
XMLElement *sessionNode = snapshots_doc_.FirstChildElement( std::to_string(snapshotid).c_str() );
|
||||||
|
|
||||||
|
if (sessionNode) {
|
||||||
|
// actually restore
|
||||||
|
Mixer::manager().restore(sessionNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// free
|
// free
|
||||||
locked_ = false;
|
locked_ = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
#ifndef ACTIONMANAGER_H
|
#ifndef ACTIONMANAGER_H
|
||||||
#define ACTIONMANAGER_H
|
#define ACTIONMANAGER_H
|
||||||
|
|
||||||
|
#include <list>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
#include <tinyxml2.h>
|
#include <tinyxml2.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Action
|
class Action
|
||||||
{
|
{
|
||||||
// Private Constructor
|
// Private Constructor
|
||||||
@@ -23,25 +25,36 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void store(const std::string &label);
|
void store(const std::string &label);
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
void undo();
|
void undo();
|
||||||
void redo();
|
void redo();
|
||||||
void stepTo(uint target);
|
void stepTo(uint target);
|
||||||
|
|
||||||
inline uint current() const { return step_; }
|
inline uint current() const { return history_step_; }
|
||||||
inline uint max() const { return max_step_; }
|
inline uint max() const { return history_max_step_; }
|
||||||
|
|
||||||
std::string label(uint s) const;
|
std::string label(uint s) const;
|
||||||
|
|
||||||
|
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);
|
||||||
|
void setLabel (uint64_t snapshotid, const std::string &label);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void restore(uint target);
|
void restore(uint target);
|
||||||
|
|
||||||
tinyxml2::XMLDocument xmlDoc_;
|
tinyxml2::XMLDocument history_doc_;
|
||||||
uint step_;
|
uint history_step_;
|
||||||
uint max_step_;
|
uint history_max_step_;
|
||||||
std::atomic<bool> locked_;
|
std::atomic<bool> locked_;
|
||||||
|
|
||||||
|
|
||||||
|
tinyxml2::XMLDocument snapshots_doc_;
|
||||||
|
std::list<uint64_t> snapshots_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
78
Mixer.cpp
78
Mixer.cpp
@@ -1241,3 +1241,81 @@ void Mixer::paste(const std::string& clipboard)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Mixer::restore(tinyxml2::XMLElement *sessionNode)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// source lists
|
||||||
|
//
|
||||||
|
|
||||||
|
// sessionsources contains list of ids of all sources currently in the session (before loading)
|
||||||
|
SourceIdList session_sources = session_->getIdList();
|
||||||
|
// for( auto it = sessionsources.begin(); it != sessionsources.end(); it++)
|
||||||
|
// Log::Info("sessionsources id %s", std::to_string(*it).c_str());
|
||||||
|
|
||||||
|
// load history status:
|
||||||
|
// - if a source exists, its attributes are updated, and that's all
|
||||||
|
// - if a source does not exists (in current session), it is created inside the session
|
||||||
|
SessionLoader loader( session_ );
|
||||||
|
loader.load( sessionNode );
|
||||||
|
|
||||||
|
// loaded_sources contains map of xml ids of all sources treated by loader
|
||||||
|
std::map< uint64_t, Source* > loaded_sources = loader.getSources();
|
||||||
|
|
||||||
|
// remove intersect of both lists (sources were updated by SessionLoader)
|
||||||
|
for( auto lsit = loaded_sources.begin(); lsit != loaded_sources.end(); ){
|
||||||
|
auto ssit = std::find(session_sources.begin(), session_sources.end(), (*lsit).first);
|
||||||
|
if ( ssit != session_sources.end() ) {
|
||||||
|
lsit = loaded_sources.erase(lsit);
|
||||||
|
session_sources.erase(ssit);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
lsit++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remaining ids in list sessionsources : to remove
|
||||||
|
while ( !session_sources.empty() ){
|
||||||
|
Source *s = Mixer::manager().findSource( session_sources.front() );
|
||||||
|
if (s!=nullptr) {
|
||||||
|
#ifdef ACTION_DEBUG
|
||||||
|
Log::Info("Delete id %s\n", std::to_string(session_sources.front() ).c_str());
|
||||||
|
#endif
|
||||||
|
// remove the source from the mixer
|
||||||
|
detach( s );
|
||||||
|
// delete source from session
|
||||||
|
session_->deleteSource( s );
|
||||||
|
}
|
||||||
|
session_sources.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
|
// remaining sources in list loaded_sources : to add
|
||||||
|
for ( auto lsit = loaded_sources.begin(); lsit != loaded_sources.end(); lsit++)
|
||||||
|
{
|
||||||
|
#ifdef ACTION_DEBUG
|
||||||
|
Log::Info("Recreate id %s to %s\n", std::to_string((*lsit).first).c_str(), std::to_string((*lsit).second->id()).c_str());
|
||||||
|
#endif
|
||||||
|
// attach created source
|
||||||
|
attach( (*lsit).second );
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// mixing groups
|
||||||
|
//
|
||||||
|
|
||||||
|
// Get the list of mixing groups in the xml loader
|
||||||
|
std::list< SourceList > loadergroups = loader.getMixingGroups();
|
||||||
|
|
||||||
|
// clear all session groups
|
||||||
|
auto group_iter = session_->beginMixingGroup();
|
||||||
|
while ( group_iter != session_->endMixingGroup() )
|
||||||
|
group_iter = session_->deleteMixingGroup(group_iter);
|
||||||
|
|
||||||
|
// apply all changes creating or modifying groups in the session
|
||||||
|
// (after this, new groups are created and existing groups are adjusted)
|
||||||
|
for (auto group_loader_it = loadergroups.begin(); group_loader_it != loadergroups.end(); group_loader_it++)
|
||||||
|
session_->link( *group_loader_it, view(View::MIXING)->scene.fg() );
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
5
Mixer.h
5
Mixer.h
@@ -9,6 +9,10 @@
|
|||||||
#include "Session.h"
|
#include "Session.h"
|
||||||
#include "Selection.h"
|
#include "Selection.h"
|
||||||
|
|
||||||
|
namespace tinyxml2 {
|
||||||
|
class XMLElement;
|
||||||
|
}
|
||||||
|
|
||||||
class SessionSource;
|
class SessionSource;
|
||||||
|
|
||||||
class Mixer
|
class Mixer
|
||||||
@@ -108,6 +112,7 @@ public:
|
|||||||
|
|
||||||
// create sources if clipboard contains well-formed xml text
|
// create sources if clipboard contains well-formed xml text
|
||||||
void paste (const std::string& clipboard);
|
void paste (const std::string& clipboard);
|
||||||
|
void restore(tinyxml2::XMLElement *sessionNode);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
|||||||
@@ -3099,10 +3099,7 @@ void Navigator::RenderMainPannelVimix()
|
|||||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||||
ImGui::ListBoxHeader("##UndoHistory", CLAMP(Action::manager().max(), 4, 8));
|
ImGui::ListBoxHeader("##UndoHistory", CLAMP(Action::manager().max(), 4, 8));
|
||||||
for (uint i = Action::manager().max(); i > 0; --i) {
|
for (uint i = Action::manager().max(); i > 0; --i) {
|
||||||
|
if (ImGui::Selectable( Action::manager().label(i).c_str(), i == Action::manager().current(), ImGuiSelectableFlags_AllowDoubleClick )) {
|
||||||
std::string step_label_ = Action::manager().label(i);
|
|
||||||
bool enable = i == Action::manager().current();
|
|
||||||
if (ImGui::Selectable( step_label_.c_str(), &enable, ImGuiSelectableFlags_AllowDoubleClick )) {
|
|
||||||
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
|
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
|
||||||
Action::manager().stepTo(i);
|
Action::manager().stepTo(i);
|
||||||
}
|
}
|
||||||
@@ -3132,31 +3129,32 @@ void Navigator::RenderMainPannelVimix()
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
static std::list<std::string> snapshots;
|
std::list<uint64_t> snapshots = Action::manager().snapshots();
|
||||||
static std::list<std::string>::iterator current_snapshot = snapshots.end();
|
static uint64_t current_snapshot = 0;
|
||||||
|
|
||||||
pos_top = ImGui::GetCursorPos();
|
pos_top = ImGui::GetCursorPos();
|
||||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||||
ImGui::ListBoxHeader("##Snapshots", CLAMP(snapshots.size(), 4, 8));
|
ImGui::ListBoxHeader("##Snapshots", CLAMP(snapshots.size(), 4, 8));
|
||||||
|
|
||||||
ImVec2 size = ImVec2( ImGui::GetContentRegionAvailWidth(), ImGui::GetTextLineHeight() );
|
ImVec2 size = ImVec2( ImGui::GetContentRegionAvailWidth(), ImGui::GetTextLineHeight() );
|
||||||
for (auto ait = snapshots.begin(); ait != snapshots.end(); ++ait)
|
for (auto snapit = snapshots.begin(); snapit != snapshots.end(); ++snapit)
|
||||||
{
|
{
|
||||||
// size of items
|
// size of items
|
||||||
ImVec2 s = size;
|
ImVec2 s = size;
|
||||||
if ( current_snapshot == ait )
|
if ( current_snapshot == *snapit )
|
||||||
s.x -= ImGui::GetTextLineHeightWithSpacing();
|
s.x -= ImGui::GetTextLineHeightWithSpacing();
|
||||||
// entry
|
// entry
|
||||||
if (ImGui::Selectable( ait->c_str(), current_snapshot == ait, ImGuiSelectableFlags_AllowDoubleClick, s )) {
|
if (ImGui::Selectable( Action::manager().label(*snapit).c_str(), current_snapshot == *snapit, ImGuiSelectableFlags_AllowDoubleClick, s )) {
|
||||||
// current list item
|
// current list item
|
||||||
current_snapshot = ait;
|
current_snapshot = *snapit;
|
||||||
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
|
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
|
||||||
// trigger snapshot
|
// trigger snapshot
|
||||||
// current_snapshot = snapshots.end();
|
// current_snapshot = snapshots.end();
|
||||||
|
Action::manager().restore(current_snapshot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// context menu
|
// context menu
|
||||||
if ( current_snapshot == ait ) {
|
if ( current_snapshot == *snapit ) {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if ( ImGuiToolkit::IconButton( ICON_FA_CHEVRON_DOWN ) )
|
if ( ImGuiToolkit::IconButton( ICON_FA_CHEVRON_DOWN ) )
|
||||||
ImGui::OpenPopup( "MenuSnapshot" );
|
ImGui::OpenPopup( "MenuSnapshot" );
|
||||||
@@ -3167,16 +3165,22 @@ void Navigator::RenderMainPannelVimix()
|
|||||||
if (ImGui::BeginPopup( "MenuSnapshot" ))
|
if (ImGui::BeginPopup( "MenuSnapshot" ))
|
||||||
{
|
{
|
||||||
if (ImGui::Selectable( " " ICON_FA_ANGLE_DOUBLE_RIGHT " Apply", false, 0, size )) {
|
if (ImGui::Selectable( " " ICON_FA_ANGLE_DOUBLE_RIGHT " Apply", false, 0, size )) {
|
||||||
// current_snapshot = snapshots.end();
|
Action::manager().restore(current_snapshot);
|
||||||
|
current_snapshot = 0;
|
||||||
}
|
}
|
||||||
if (ImGui::Selectable( ICON_FA_STAR "_ Remove", false, 0, size )) {
|
if (ImGui::Selectable( ICON_FA_STAR "_ Remove", false, 0, size )) {
|
||||||
snapshots.erase(current_snapshot);
|
|
||||||
current_snapshot = snapshots.end();
|
|
||||||
|
Action::manager().remove(current_snapshot);
|
||||||
|
current_snapshot = 0;
|
||||||
}
|
}
|
||||||
ImGui::TextDisabled("Rename");
|
ImGui::TextDisabled("Rename");
|
||||||
ImGui::SetNextItemWidth(size.x);
|
ImGui::SetNextItemWidth(size.x);
|
||||||
if ( current_snapshot != snapshots.end() ) {
|
if ( current_snapshot > 0 ) {
|
||||||
ImGuiToolkit::InputText("##Rename", &(*current_snapshot) );
|
static std::string label;
|
||||||
|
label = Action::manager().label(current_snapshot);
|
||||||
|
if ( ImGuiToolkit::InputText("##Rename", &label ) )
|
||||||
|
Action::manager().setLabel(current_snapshot, label);
|
||||||
}
|
}
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
}
|
}
|
||||||
@@ -3187,7 +3191,8 @@ void Navigator::RenderMainPannelVimix()
|
|||||||
// right buttons
|
// right buttons
|
||||||
ImGui::SetCursorPos( ImVec2( pannel_width_ IMGUI_RIGHT_ALIGN, pos_top.y ));
|
ImGui::SetCursorPos( ImVec2( pannel_width_ IMGUI_RIGHT_ALIGN, pos_top.y ));
|
||||||
if ( ImGuiToolkit::IconButton( ICON_FA_STAR "+")) {
|
if ( ImGuiToolkit::IconButton( ICON_FA_STAR "+")) {
|
||||||
snapshots.push_back( SystemToolkit::date_time_string() );
|
// snapshots.push_back( SystemToolkit::date_time_string() );
|
||||||
|
Action::manager().snapshot( SystemToolkit::date_time_string() );
|
||||||
}
|
}
|
||||||
// // active list element : delete snapshot button
|
// // active list element : delete snapshot button
|
||||||
// ImGui::SetCursorPos( ImVec2( pannel_width_ IMGUI_RIGHT_ALIGN, pos_bot.y - ImGui::GetFrameHeightWithSpacing()));
|
// ImGui::SetCursorPos( ImVec2( pannel_width_ IMGUI_RIGHT_ALIGN, pos_bot.y - ImGui::GetFrameHeightWithSpacing()));
|
||||||
|
|||||||
Reference in New Issue
Block a user