mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-05 23:40:02 +01:00
First working implementation of ActionManager, but incomplete.
This commit is contained in:
@@ -1,28 +1,163 @@
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include "Log.h"
|
||||
#include "View.h"
|
||||
#include "Mixer.h"
|
||||
#include "tinyxml2Toolkit.h"
|
||||
#include "SessionVisitor.h"
|
||||
#include "SessionCreator.h"
|
||||
|
||||
#include "ActionManager.h"
|
||||
|
||||
Action::Action()
|
||||
#ifndef NDEBUG
|
||||
#define ACTION_DEBUG
|
||||
#endif
|
||||
|
||||
using namespace tinyxml2;
|
||||
|
||||
Action::Action(): step_(0), max_step_(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Action::clear()
|
||||
{
|
||||
// clean the history
|
||||
xmlDoc_.Clear();
|
||||
step_ = 0;
|
||||
max_step_ = 0;
|
||||
|
||||
// start fresh
|
||||
store("Session start");
|
||||
}
|
||||
|
||||
void Action::capture()
|
||||
void Action::store(const std::string &label, int id)
|
||||
{
|
||||
// ignore if locked or if no label is given
|
||||
if (locked_ || label.empty())
|
||||
return;
|
||||
|
||||
// incremental naming of history nodes
|
||||
step_++;
|
||||
std::string nodename = "H" + std::to_string(step_);
|
||||
|
||||
// erase future
|
||||
for (uint e = step_; e <= max_step_; e++) {
|
||||
std::string name = "H" + std::to_string(e);
|
||||
XMLElement *node = xmlDoc_.FirstChildElement( name.c_str() );
|
||||
if ( node )
|
||||
xmlDoc_.DeleteChild(node);
|
||||
}
|
||||
max_step_ = step_;
|
||||
|
||||
// create history node
|
||||
XMLElement *sessionNode = xmlDoc_.NewElement( nodename.c_str() );
|
||||
xmlDoc_.InsertEndChild(sessionNode);
|
||||
// label describes the action
|
||||
sessionNode->SetAttribute("label", label.c_str());
|
||||
// id indicates which object was modified
|
||||
sessionNode->SetAttribute("id", id);
|
||||
|
||||
// get session to operate on
|
||||
Session *se = Mixer::manager().session();
|
||||
|
||||
// save all sources using source visitor
|
||||
SessionVisitor sv(&xmlDoc_, sessionNode);
|
||||
for (auto iter = se->begin(); iter != se->end(); iter++, sv.setRoot(sessionNode) )
|
||||
(*iter)->accept(sv);
|
||||
|
||||
// debug
|
||||
#ifdef ACTION_DEBUG
|
||||
Log::Info("Action stored %s '%s'", nodename.c_str(), label.c_str());
|
||||
// XMLSaveDoc(&xmlDoc_, "/home/bhbn/history.xml");
|
||||
#endif
|
||||
}
|
||||
|
||||
void Action::undo()
|
||||
{
|
||||
if (step_ <= 1)
|
||||
return;
|
||||
|
||||
// what id was modified to get to this step ?
|
||||
// get history node of current step
|
||||
std::string nodename = "H" + std::to_string(step_);
|
||||
XMLElement *sessionNode = xmlDoc_.FirstChildElement( nodename.c_str() );
|
||||
int id = -1;
|
||||
sessionNode->QueryIntAttribute("id", &id);
|
||||
|
||||
restore( step_ - 1, id);
|
||||
}
|
||||
|
||||
void Action::redo()
|
||||
{
|
||||
if (step_ >= max_step_)
|
||||
return;
|
||||
|
||||
// what id to modify to go to next step ?
|
||||
std::string nodename = "H" + std::to_string(step_ + 1);
|
||||
XMLElement *sessionNode = xmlDoc_.FirstChildElement( nodename.c_str() );
|
||||
int id = -1;
|
||||
sessionNode->QueryIntAttribute("id", &id);
|
||||
|
||||
restore( step_ + 1, id);
|
||||
}
|
||||
|
||||
|
||||
void Action::stepTo(uint target)
|
||||
{
|
||||
// going to target step
|
||||
}
|
||||
|
||||
void Action::restore(uint target, int id)
|
||||
{
|
||||
// lock
|
||||
locked_ = true;
|
||||
|
||||
// get history node of target step
|
||||
step_ = target;
|
||||
std::string nodename = "H" + std::to_string(step_);
|
||||
XMLElement *sessionNode = xmlDoc_.FirstChildElement( nodename.c_str() );
|
||||
|
||||
#ifdef ACTION_DEBUG
|
||||
Log::Info("Restore %s '%s'", nodename.c_str(), sessionNode->Attribute("label"));
|
||||
#endif
|
||||
|
||||
// sessionsources contains ids of all sources currently in the session
|
||||
std::list<int> sessionsources = Mixer::manager().session()->getIdList();
|
||||
|
||||
// load history status:
|
||||
// - if a source exists, its attributes are updated
|
||||
// - if a source does not exists (in session), it is created in session
|
||||
SessionLoader loader( Mixer::manager().session() );
|
||||
loader.load( sessionNode );
|
||||
|
||||
// loadersources contains ids of all sources generated by loader
|
||||
std::list<int> loadersources = loader.getIdList();
|
||||
|
||||
// remove intersect of both lists (sources were updated)
|
||||
for( auto lsit = loadersources.begin(); lsit != loadersources.end(); ){
|
||||
auto ssit = std::find(sessionsources.begin(), sessionsources.end(), (*lsit));
|
||||
if ( ssit != sessionsources.end() ) {
|
||||
lsit = loadersources.erase(lsit);
|
||||
sessionsources.erase(ssit);
|
||||
}
|
||||
else
|
||||
lsit++;
|
||||
}
|
||||
// remaining ids in list sessionsources : to remove
|
||||
while ( !sessionsources.empty() ){
|
||||
Source *s = Mixer::manager().findSource( sessionsources.front() );
|
||||
Mixer::manager().detach( s );
|
||||
Mixer::manager().session()->deleteSource( s );
|
||||
sessionsources.pop_front();
|
||||
}
|
||||
// remaining ids in list loadersources : to add
|
||||
while ( !loadersources.empty() ){
|
||||
Mixer::manager().attach( Mixer::manager().findSource( loadersources.front() ) );
|
||||
loadersources.pop_front();
|
||||
}
|
||||
|
||||
// free
|
||||
locked_ = false;
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
#define ACTIONMANAGER_H
|
||||
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include <tinyxml2.h>
|
||||
|
||||
class Action
|
||||
{
|
||||
// Private Constructor
|
||||
@@ -18,14 +22,21 @@ public:
|
||||
return _instance;
|
||||
}
|
||||
|
||||
void clear();
|
||||
void capture();
|
||||
void store(const std::string &label, int id = -1);
|
||||
|
||||
void clear();
|
||||
void undo();
|
||||
void redo();
|
||||
void stepTo(uint target);
|
||||
|
||||
private:
|
||||
|
||||
void restore(uint target, int id);
|
||||
|
||||
tinyxml2::XMLDocument xmlDoc_;
|
||||
uint step_;
|
||||
uint max_step_;
|
||||
std::atomic<bool> locked_;
|
||||
};
|
||||
|
||||
#endif // ACTIONMANAGER_H
|
||||
|
||||
55
Mixer.cpp
55
Mixer.cpp
@@ -25,6 +25,7 @@ using namespace tinyxml2;
|
||||
#include "PatternSource.h"
|
||||
#include "DeviceSource.h"
|
||||
#include "StreamSource.h"
|
||||
#include "ActionManager.h"
|
||||
|
||||
#include "Mixer.h"
|
||||
|
||||
@@ -53,13 +54,10 @@ static void saveSession(const std::string& filename, Session *session)
|
||||
// 1. list of sources
|
||||
XMLElement *sessionNode = xmlDoc.NewElement("Session");
|
||||
xmlDoc.InsertEndChild(sessionNode);
|
||||
SourceList::iterator iter;
|
||||
for (iter = session->begin(); iter != session->end(); iter++)
|
||||
{
|
||||
SessionVisitor sv(&xmlDoc, sessionNode);
|
||||
for (auto iter = session->begin(); iter != session->end(); iter++, sv.setRoot(sessionNode) )
|
||||
// source visitor
|
||||
(*iter)->accept(sv);
|
||||
}
|
||||
|
||||
// 2. config of views
|
||||
XMLElement *views = xmlDoc.NewElement("Views");
|
||||
@@ -338,7 +336,7 @@ void Mixer::insertSource(Source *s, View::Mode m)
|
||||
{
|
||||
if ( s != nullptr )
|
||||
{
|
||||
// Add source to Session
|
||||
// Add source to Session (ignored if source already in)
|
||||
SourceList::iterator sit = session_->addSource(s);
|
||||
|
||||
// set a default depth to the new source
|
||||
@@ -348,9 +346,10 @@ void Mixer::insertSource(Source *s, View::Mode m)
|
||||
mixing_.setAlpha(s);
|
||||
|
||||
// add sources Nodes to all views
|
||||
mixing_.scene.ws()->attach(s->group(View::MIXING));
|
||||
geometry_.scene.ws()->attach(s->group(View::GEOMETRY));
|
||||
layer_.scene.ws()->attach(s->group(View::LAYER));
|
||||
attach(s);
|
||||
|
||||
// new state in history manager
|
||||
Action::manager().store(std::string("Insert ")+s->name());
|
||||
|
||||
// if requested to show the source in a given view
|
||||
// (known to work for View::MIXING et TRANSITION: other views untested)
|
||||
@@ -371,12 +370,6 @@ void Mixer::deleteSource(Source *s)
|
||||
{
|
||||
if ( s != nullptr )
|
||||
{
|
||||
// in case it was the current source...
|
||||
unsetCurrentSource();
|
||||
|
||||
// in case it was selected..
|
||||
selection().remove(s);
|
||||
|
||||
// keep name for log
|
||||
std::string name = s->name();
|
||||
|
||||
@@ -386,6 +379,9 @@ void Mixer::deleteSource(Source *s)
|
||||
// delete source
|
||||
session_->deleteSource(s);
|
||||
|
||||
// new state in history manager
|
||||
Action::manager().store(std::string("Delete ")+name);
|
||||
|
||||
// log
|
||||
Log::Notify("Source %s deleted.", name.c_str());
|
||||
}
|
||||
@@ -402,17 +398,31 @@ void Mixer::deleteSource(Source *s)
|
||||
|
||||
void Mixer::attach(Source *s)
|
||||
{
|
||||
if ( s != nullptr )
|
||||
{
|
||||
// force update
|
||||
s->touch();
|
||||
// attach to views
|
||||
mixing_.scene.ws()->attach( s->group(View::MIXING) );
|
||||
geometry_.scene.ws()->attach( s->group(View::GEOMETRY) );
|
||||
layer_.scene.ws()->attach( s->group(View::LAYER) );
|
||||
}
|
||||
}
|
||||
|
||||
void Mixer::detach(Source *s)
|
||||
{
|
||||
if ( s != nullptr )
|
||||
{
|
||||
// in case it was the current source...
|
||||
unsetCurrentSource();
|
||||
// in case it was selected..
|
||||
selection().remove(s);
|
||||
// detach from views
|
||||
mixing_.scene.ws()->detatch( s->group(View::MIXING) );
|
||||
geometry_.scene.ws()->detatch( s->group(View::GEOMETRY) );
|
||||
layer_.scene.ws()->detatch( s->group(View::LAYER) );
|
||||
transition_.scene.ws()->detatch( s->group(View::TRANSITION) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -522,6 +532,7 @@ Source * Mixer::findSource (Node *node)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
Source * Mixer::findSource (std::string namesource)
|
||||
{
|
||||
SourceList::iterator it = session_->find(namesource);
|
||||
@@ -530,6 +541,15 @@ Source * Mixer::findSource (std::string namesource)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Source * Mixer::findSource (int id)
|
||||
{
|
||||
SourceList::iterator it = session_->find(id);
|
||||
if (it != session_->end())
|
||||
return *it;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void Mixer::setCurrentSource(int id)
|
||||
{
|
||||
setCurrentSource( session_->find(id) );
|
||||
@@ -557,8 +577,9 @@ void Mixer::setCurrentIndex(int index)
|
||||
|
||||
void Mixer::setCurrentNext()
|
||||
{
|
||||
SourceList::iterator it = current_source_;
|
||||
if (session_->numSource() > 0) {
|
||||
|
||||
SourceList::iterator it = current_source_;
|
||||
it++;
|
||||
|
||||
if (it == session_->end()) {
|
||||
@@ -566,6 +587,7 @@ void Mixer::setCurrentNext()
|
||||
}
|
||||
|
||||
setCurrentSource( it );
|
||||
}
|
||||
}
|
||||
|
||||
void Mixer::unsetCurrentSource()
|
||||
@@ -786,6 +808,9 @@ void Mixer::swap()
|
||||
garbage_.push_back(back_session_);
|
||||
back_session_ = nullptr;
|
||||
|
||||
// reset History manager
|
||||
Action::manager().clear();
|
||||
|
||||
// notification
|
||||
Log::Notify("Session %s loaded. %d source(s) created.", session_->filename().c_str(), session_->numSource());
|
||||
}
|
||||
|
||||
5
Mixer.h
5
Mixer.h
@@ -47,6 +47,8 @@ public:
|
||||
void addSource (Source *s);
|
||||
void deleteSource (Source *s);
|
||||
void renameSource (Source *s, const std::string &newname);
|
||||
void attach (Source *s);
|
||||
void detach (Source *s);
|
||||
void deleteSelection();
|
||||
|
||||
// current source
|
||||
@@ -64,6 +66,7 @@ public:
|
||||
// browsing into sources
|
||||
Source * findSource (Node *node);
|
||||
Source * findSource (std::string name);
|
||||
Source * findSource (int id);
|
||||
|
||||
// management of view
|
||||
View *view (View::Mode m = View::INVALID);
|
||||
@@ -98,8 +101,6 @@ protected:
|
||||
SourceList candidate_sources_;
|
||||
SourceList stash_;
|
||||
void insertSource(Source *s, View::Mode m = View::INVALID);
|
||||
void attach(Source *s);
|
||||
void detach(Source *s);
|
||||
|
||||
void setCurrentSource(SourceList::iterator it);
|
||||
SourceList::iterator current_source_;
|
||||
|
||||
10
Session.cpp
10
Session.cpp
@@ -250,6 +250,16 @@ uint Session::numSource() const
|
||||
return sources_.size();
|
||||
}
|
||||
|
||||
std::list<int> Session::getIdList() const
|
||||
{
|
||||
std::list<int> idlist;
|
||||
|
||||
for( auto sit = sources_.begin(); sit != sources_.end(); sit++)
|
||||
idlist.push_back( (*sit)->id() );
|
||||
|
||||
return idlist;
|
||||
}
|
||||
|
||||
bool Session::empty() const
|
||||
{
|
||||
return sources_.empty();
|
||||
|
||||
@@ -38,7 +38,9 @@ public:
|
||||
SourceList::iterator find (Source *s);
|
||||
SourceList::iterator find (std::string name);
|
||||
SourceList::iterator find (Node *node);
|
||||
|
||||
SourceList::iterator find (int id);
|
||||
std::list<int> getIdList() const;
|
||||
|
||||
SourceList::iterator at (int index);
|
||||
int index (SourceList::iterator it) const;
|
||||
|
||||
@@ -67,14 +67,16 @@ void SessionCreator::load(const std::string& filename)
|
||||
return;
|
||||
}
|
||||
|
||||
// session file seems legit, create a session
|
||||
session_ = new Session;
|
||||
|
||||
// ok, ready to read sources
|
||||
// ready to read sources
|
||||
SessionLoader::load( xmlDoc_.FirstChildElement("Session") );
|
||||
|
||||
// load optionnal config
|
||||
loadConfig( xmlDoc_.FirstChildElement("Views") );
|
||||
|
||||
// all good
|
||||
session_->setFilename(filename);
|
||||
}
|
||||
|
||||
@@ -100,17 +102,15 @@ void SessionLoader::load(XMLElement *sessionNode)
|
||||
{
|
||||
if (sessionNode != nullptr && session_ != nullptr) {
|
||||
|
||||
int counter = 0;
|
||||
XMLElement* sourceNode = sessionNode->FirstChildElement("Source");
|
||||
for( ; sourceNode ; sourceNode = sourceNode->NextSiblingElement())
|
||||
{
|
||||
xmlCurrent_ = sourceNode;
|
||||
counter++;
|
||||
|
||||
// source to load
|
||||
Source *load_source = nullptr;
|
||||
|
||||
// check if a source with same id exists
|
||||
// check if a source with the given id exists in the session
|
||||
int id__ = -1;
|
||||
xmlCurrent_->QueryIntAttribute("id", &id__);
|
||||
SourceList::iterator sit = session_->find(id__);
|
||||
@@ -137,48 +137,75 @@ void SessionLoader::load(XMLElement *sessionNode)
|
||||
load_source = new DeviceSource;
|
||||
}
|
||||
|
||||
// avoid non recognized types
|
||||
// skip failed (including clones)
|
||||
if (!load_source)
|
||||
continue;
|
||||
|
||||
// add source to session
|
||||
session_->addSource(load_source);
|
||||
id__ = load_source->id();
|
||||
}
|
||||
// get reference to the existing source
|
||||
else
|
||||
load_source = *sit;
|
||||
|
||||
// apply config to source
|
||||
load_source->accept(*this);
|
||||
// remember
|
||||
sources_id_.push_back( id__ );
|
||||
}
|
||||
|
||||
// create clones after all sources to potentially clone have been created
|
||||
// create clones after all sources, to be able to clone a source created above
|
||||
sourceNode = sessionNode->FirstChildElement("Source");
|
||||
for( ; sourceNode ; sourceNode = sourceNode->NextSiblingElement())
|
||||
{
|
||||
xmlCurrent_ = sourceNode;
|
||||
counter++;
|
||||
|
||||
// verify type of node
|
||||
const char *pType = xmlCurrent_->Attribute("type");
|
||||
if (!pType)
|
||||
continue;
|
||||
|
||||
if ( std::string(pType) == "CloneSource") {
|
||||
|
||||
// clone to load
|
||||
Source *clone_source = nullptr;
|
||||
|
||||
// check if a source with same id exists
|
||||
int id__ = -1;
|
||||
xmlCurrent_->QueryIntAttribute("id", &id__);
|
||||
SourceList::iterator sit = session_->find(id__);
|
||||
|
||||
// no source clone with this id exists
|
||||
if ( sit == session_->end() ) {
|
||||
|
||||
XMLElement* originNode = xmlCurrent_->FirstChildElement("origin");
|
||||
if (originNode) {
|
||||
std::string sourcename = std::string ( originNode->GetText() );
|
||||
SourceList::iterator origin = session_->find(sourcename);
|
||||
if (origin != session_->end()) {
|
||||
CloneSource *new_clone_source = (*origin)->clone();
|
||||
new_clone_source->accept(*this);
|
||||
session_->addSource(new_clone_source);
|
||||
// create a new source of type Clone
|
||||
clone_source = (*origin)->clone();
|
||||
}
|
||||
}
|
||||
// skip failed
|
||||
if (!clone_source)
|
||||
continue;
|
||||
|
||||
// add source to session
|
||||
session_->addSource(clone_source);
|
||||
id__ = clone_source->id();
|
||||
}
|
||||
else
|
||||
clone_source = *sit;
|
||||
|
||||
// apply config to source
|
||||
clone_source->accept(*this);
|
||||
// remember
|
||||
sources_id_.push_back( id__ );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
Log::Warning("Session seems empty.");
|
||||
}
|
||||
|
||||
|
||||
@@ -209,11 +236,14 @@ void SessionLoader::visit(Node &n)
|
||||
void SessionLoader::visit(MediaPlayer &n)
|
||||
{
|
||||
XMLElement* mediaplayerNode = xmlCurrent_->FirstChildElement("MediaPlayer");
|
||||
int id__ = -1;
|
||||
mediaplayerNode->QueryIntAttribute("id", &id__);
|
||||
|
||||
if (mediaplayerNode) {
|
||||
// timeline
|
||||
XMLElement *timelineelement = mediaplayerNode->FirstChildElement("Timeline");
|
||||
if (timelineelement) {
|
||||
Timeline tl;
|
||||
Timeline tl = *(n.timeline());
|
||||
XMLElement *gapselement = timelineelement->FirstChildElement("Gaps");
|
||||
if (gapselement) {
|
||||
XMLElement* gap = gapselement->FirstChildElement("Interval");
|
||||
@@ -233,17 +263,23 @@ void SessionLoader::visit(MediaPlayer &n)
|
||||
}
|
||||
n.setTimeline(tl);
|
||||
}
|
||||
// playing properties
|
||||
|
||||
// change play status only if different id (e.g. new media player)
|
||||
if ( n.id() != id__ ) {
|
||||
|
||||
double speed = 1.0;
|
||||
mediaplayerNode->QueryDoubleAttribute("speed", &speed);
|
||||
n.setPlaySpeed(speed);
|
||||
|
||||
int loop = 1;
|
||||
mediaplayerNode->QueryIntAttribute("loop", &loop);
|
||||
n.setLoop( (MediaPlayer::LoopMode) loop);
|
||||
|
||||
bool play = true;
|
||||
mediaplayerNode->QueryBoolAttribute("play", &play);
|
||||
n.play(play);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SessionLoader::visit(Shader &n)
|
||||
@@ -337,6 +373,8 @@ void SessionLoader::visit (MediaSource& s)
|
||||
XMLElement* uriNode = xmlCurrent_->FirstChildElement("uri");
|
||||
if (uriNode) {
|
||||
std::string uri = std::string ( uriNode->GetText() );
|
||||
// load only new files
|
||||
if ( uri != s.path() )
|
||||
s.setPath(uri);
|
||||
}
|
||||
|
||||
@@ -350,6 +388,8 @@ void SessionLoader::visit (SessionSource& s)
|
||||
XMLElement* pathNode = xmlCurrent_->FirstChildElement("path");
|
||||
if (pathNode) {
|
||||
std::string path = std::string ( pathNode->GetText() );
|
||||
// load only new files
|
||||
if ( path != s.path() )
|
||||
s.load(path);
|
||||
}
|
||||
|
||||
@@ -357,19 +397,24 @@ void SessionLoader::visit (SessionSource& s)
|
||||
|
||||
void SessionLoader::visit (PatternSource& s)
|
||||
{
|
||||
uint p = xmlCurrent_->UnsignedAttribute("pattern");
|
||||
uint t = xmlCurrent_->UnsignedAttribute("pattern");
|
||||
|
||||
glm::ivec2 resolution(800, 600);
|
||||
XMLElement* res = xmlCurrent_->FirstChildElement("resolution");
|
||||
if (res)
|
||||
tinyxml2::XMLElementToGLM( res->FirstChildElement("ivec2"), resolution);
|
||||
|
||||
s.setPattern(p, resolution);
|
||||
// change only if different pattern
|
||||
if ( t != s.pattern()->type() )
|
||||
s.setPattern(t, resolution);
|
||||
}
|
||||
|
||||
void SessionLoader::visit (DeviceSource& s)
|
||||
{
|
||||
const char *devname = xmlCurrent_->Attribute("device");
|
||||
std::string devname = std::string ( xmlCurrent_->Attribute("device") );
|
||||
|
||||
// change only if different device
|
||||
if ( devname != s.device() )
|
||||
s.setDevice(devname);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef SESSIONCREATOR_H
|
||||
#define SESSIONCREATOR_H
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "Visitor.h"
|
||||
#include <tinyxml2.h>
|
||||
|
||||
@@ -14,6 +16,7 @@ public:
|
||||
inline Session *session() const { return session_; }
|
||||
|
||||
void load(tinyxml2::XMLElement *sessionNode);
|
||||
inline std::list<int> getIdList() const { return sources_id_; }
|
||||
|
||||
// Elements of Scene
|
||||
void visit(Node& n) override;
|
||||
@@ -37,18 +40,19 @@ public:
|
||||
void visit(ImageShader& n) override;
|
||||
void visit(ImageProcessingShader& n) override;
|
||||
|
||||
// Sources
|
||||
void visit (Source& s) override;
|
||||
void visit (MediaSource& s) override;
|
||||
void visit (SessionSource& s) override;
|
||||
void visit (PatternSource& s) override;
|
||||
void visit (DeviceSource& s) override;
|
||||
|
||||
static void XMLToNode(tinyxml2::XMLElement *xml, Node &n);
|
||||
|
||||
protected:
|
||||
tinyxml2::XMLElement *xmlCurrent_;
|
||||
Session *session_;
|
||||
std::list<int> sources_id_;
|
||||
|
||||
static void XMLToNode(tinyxml2::XMLElement *xml, Node &n);
|
||||
};
|
||||
|
||||
class SessionCreator : public SessionLoader {
|
||||
|
||||
@@ -16,6 +16,7 @@ public:
|
||||
bool recursive = false);
|
||||
|
||||
inline tinyxml2::XMLDocument *doc() const { return xmlDoc_; }
|
||||
inline void setRoot(tinyxml2::XMLElement *root) { xmlCurrent_ = root; }
|
||||
|
||||
// Elements of Scene
|
||||
void visit(Scene& n) override;
|
||||
@@ -39,6 +40,7 @@ public:
|
||||
void visit(ImageShader& n) override;
|
||||
void visit(ImageProcessingShader& n) override;
|
||||
|
||||
// Sources
|
||||
void visit (Source& s) override;
|
||||
void visit (MediaSource& s) override;
|
||||
void visit (SessionSource& s) override;
|
||||
|
||||
@@ -33,11 +33,13 @@ using namespace std;
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include <stb_image_write.h>
|
||||
|
||||
#include "UserInterfaceManager.h"
|
||||
|
||||
#include "defines.h"
|
||||
#include "Log.h"
|
||||
#include "SystemToolkit.h"
|
||||
#include "UserInterfaceManager.h"
|
||||
#include "RenderingManager.h"
|
||||
#include "ActionManager.h"
|
||||
#include "Resource.h"
|
||||
#include "FileDialog.h"
|
||||
#include "Settings.h"
|
||||
@@ -289,6 +291,12 @@ void UserInterface::handleKeyboard()
|
||||
else
|
||||
Mixer::manager().session()->addRecorder(new VideoRecorder);
|
||||
}
|
||||
else if (ImGui::IsKeyPressed( GLFW_KEY_Z )) {
|
||||
if (shift_modifier_active)
|
||||
Action::manager().redo();
|
||||
else
|
||||
Action::manager().undo();
|
||||
}
|
||||
|
||||
}
|
||||
// No CTRL modifier
|
||||
|
||||
33
View.cpp
33
View.cpp
@@ -28,6 +28,7 @@
|
||||
#include "Mixer.h"
|
||||
#include "UserInterfaceManager.h"
|
||||
#include "UpdateCallback.h"
|
||||
#include "ActionManager.h"
|
||||
#include "Log.h"
|
||||
|
||||
|
||||
@@ -67,6 +68,7 @@ void View::update(float dt)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
View::Cursor View::drag (glm::vec2 from, glm::vec2 to)
|
||||
{
|
||||
static glm::vec3 start_translation = glm::vec3(0.f);
|
||||
@@ -110,6 +112,8 @@ std::pair<Node *, glm::vec2> View::pick(glm::vec2 P)
|
||||
|
||||
void View::initiate()
|
||||
{
|
||||
current_action_ = "";
|
||||
current_id_ = -1;
|
||||
for (auto sit = Mixer::manager().session()->begin();
|
||||
sit != Mixer::manager().session()->end(); sit++){
|
||||
|
||||
@@ -117,6 +121,13 @@ void View::initiate()
|
||||
}
|
||||
}
|
||||
|
||||
void View::terminate()
|
||||
{
|
||||
Action::manager().store(current_action_, current_id_);
|
||||
current_action_ = "";
|
||||
current_id_ = -1;
|
||||
}
|
||||
|
||||
void View::recenter()
|
||||
{
|
||||
// restore default view
|
||||
@@ -462,6 +473,7 @@ View::Cursor MixingView::grab (Source *s, glm::vec2 from, glm::vec2 to, std::pai
|
||||
// s->group(mode_)->translation_.y = s->group(mode_)->translation_.x * s->stored_status_->translation_.y / s->stored_status_->translation_.x;
|
||||
// }
|
||||
|
||||
|
||||
// // trying to enter stash
|
||||
// if ( glm::distance( glm::vec2(s->group(mode_)->translation_), glm::vec2(stashCircle_->translation_)) < stashCircle_->scale_.x) {
|
||||
|
||||
@@ -484,11 +496,15 @@ View::Cursor MixingView::grab (Source *s, glm::vec2 from, glm::vec2 to, std::pai
|
||||
std::ostringstream info;
|
||||
if (s->active())
|
||||
info << "Alpha " << std::fixed << std::setprecision(3) << s->blendingShader()->color.a;
|
||||
else if ( Mixer::manager().concealed(s) )
|
||||
info << "Stashed";
|
||||
// else if ( Mixer::manager().concealed(s) )
|
||||
// info << "Stashed";
|
||||
else
|
||||
info << "Inactive";
|
||||
|
||||
// store action in history
|
||||
current_action_ = s->name() + " " + info.str();
|
||||
current_id_ = s->id();
|
||||
|
||||
return Cursor(Cursor_ResizeAll, info.str() );
|
||||
}
|
||||
|
||||
@@ -959,6 +975,7 @@ View::Cursor GeometryView::grab (Source *s, glm::vec2 from, glm::vec2 to, std::p
|
||||
ret.type = corner.x * corner.y > 0.f ? Cursor_ResizeNESW : Cursor_ResizeNWSE;
|
||||
info << "Size " << std::fixed << std::setprecision(3) << sourceNode->scale_.x;
|
||||
info << " x " << sourceNode->scale_.y;
|
||||
|
||||
}
|
||||
// picking on the BORDER RESIZING handles left or right
|
||||
else if ( pick.first == s->handle_[Handles::RESIZE_H] ) {
|
||||
@@ -1156,6 +1173,11 @@ View::Cursor GeometryView::grab (Source *s, glm::vec2 from, glm::vec2 to, std::p
|
||||
// request update
|
||||
s->touch();
|
||||
|
||||
// store action in history
|
||||
current_action_ = s->name() + " " + info.str();
|
||||
current_id_ = s->id();
|
||||
|
||||
// update cursor
|
||||
ret.info = info.str();
|
||||
return ret;
|
||||
}
|
||||
@@ -1163,6 +1185,8 @@ View::Cursor GeometryView::grab (Source *s, glm::vec2 from, glm::vec2 to, std::p
|
||||
|
||||
void GeometryView::terminate()
|
||||
{
|
||||
View::terminate();
|
||||
|
||||
// hide all overlays
|
||||
overlay_position_->visible_ = false;
|
||||
overlay_position_cross_->visible_ = false;
|
||||
@@ -1329,6 +1353,11 @@ View::Cursor LayerView::grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair
|
||||
|
||||
std::ostringstream info;
|
||||
info << "Depth " << std::fixed << std::setprecision(2) << d;
|
||||
|
||||
// store action in history
|
||||
current_action_ = s->name() + " " + info.str();
|
||||
current_id_ = s->id();
|
||||
|
||||
return Cursor(Cursor_ResizeNESW, info.str() );
|
||||
}
|
||||
|
||||
|
||||
4
View.h
4
View.h
@@ -63,7 +63,7 @@ public:
|
||||
|
||||
// grab a source provided a start and an end point in screen coordinates and the picking point
|
||||
virtual void initiate();
|
||||
virtual void terminate() {}
|
||||
virtual void terminate();
|
||||
virtual Cursor grab (Source*, glm::vec2, glm::vec2, std::pair<Node *, glm::vec2>) {
|
||||
return Cursor();
|
||||
}
|
||||
@@ -84,6 +84,8 @@ protected:
|
||||
virtual void restoreSettings();
|
||||
virtual void saveSettings();
|
||||
|
||||
std::string current_action_;
|
||||
int current_id_;
|
||||
Mode mode_;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user