mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-11 18:34:58 +01:00
Reimplementation of SourceInputCallbacks into Session
Session should be the object holding the list of inputs parameters (e.g. synchrony) and the list of source callbacks. This also avoids mixing input when copying sources. Code could be improved but is operational.
This commit is contained in:
@@ -35,6 +35,7 @@
|
||||
#include "ActionManager.h"
|
||||
#include "SystemToolkit.h"
|
||||
#include "tinyxml2Toolkit.h"
|
||||
#include "Metronome.h"
|
||||
|
||||
#include "UserInterfaceManager.h"
|
||||
#include "RenderingManager.h"
|
||||
@@ -588,7 +589,7 @@ bool Control::receiveSourceAttribute(Source *target, const std::string &attribut
|
||||
else if ( attribute.compare(OSC_SOURCE_LOOM) == 0) {
|
||||
float x = 1.f;
|
||||
arguments >> x >> osc::EndMessage;
|
||||
target->call( new Loom(x), true );
|
||||
target->call( new Loom(x, 0.f), true );
|
||||
// this will require to send feedback status about source
|
||||
send_feedback = true;
|
||||
}
|
||||
@@ -608,13 +609,13 @@ bool Control::receiveSourceAttribute(Source *target, const std::string &attribut
|
||||
else if ( attribute.compare(OSC_SOURCE_GRAB) == 0) {
|
||||
float x = 0.f, y = 0.f;
|
||||
arguments >> x >> y >> osc::EndMessage;
|
||||
target->call( new Grab( x, y), true );
|
||||
target->call( new Grab( x, y, 0.f), true );
|
||||
}
|
||||
/// e.g. '/vimix/current/scale ff 10.0 2.2'
|
||||
else if ( attribute.compare(OSC_SOURCE_RESIZE) == 0) {
|
||||
float x = 0.f, y = 0.f;
|
||||
arguments >> x >> y >> osc::EndMessage;
|
||||
target->call( new Resize( x, y), true );
|
||||
target->call( new Resize( x, y, 0.f), true );
|
||||
}
|
||||
/// e.g. '/vimix/current/turn f 1.0'
|
||||
else if ( attribute.compare(OSC_SOURCE_TURN) == 0) {
|
||||
@@ -624,7 +625,7 @@ bool Control::receiveSourceAttribute(Source *target, const std::string &attribut
|
||||
arguments >> osc::EndMessage;
|
||||
else // ignore second argument
|
||||
arguments >> y >> osc::EndMessage;
|
||||
target->call( new Turn( x ), true );
|
||||
target->call( new Turn( x, 0.f), true );
|
||||
}
|
||||
/// e.g. '/vimix/current/reset'
|
||||
else if ( attribute.compare(OSC_SOURCE_RESET) == 0) {
|
||||
@@ -871,6 +872,7 @@ void Control::sendOutputStatus(const IpEndpointName &remoteEndpoint)
|
||||
socket.Send( p.Data(), p.Size() );
|
||||
}
|
||||
|
||||
|
||||
void Control::keyboardCalback(GLFWwindow* window, int key, int, int action, int mods)
|
||||
{
|
||||
if (UserInterface::manager().keyboardAvailable() && !mods )
|
||||
|
||||
@@ -102,6 +102,7 @@ public:
|
||||
|
||||
bool inputActive (uint id);
|
||||
float inputValue (uint id);
|
||||
float inputDelay (uint id);
|
||||
static std::string inputLabel(uint id);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -247,6 +247,23 @@ void Metronome::executeAtPhase( std::function<void()> f )
|
||||
std::thread( delay, f, timeToPhase() ).detach();
|
||||
}
|
||||
|
||||
float Metronome::timeToSync(Synchronicity sync)
|
||||
{
|
||||
float ret = 0.f;
|
||||
if ( sync > Metronome::SYNC_BEAT ) {
|
||||
// SYNC TO PHASE
|
||||
std::chrono::duration<float, std::milli> fp_ms = Metronome::manager().timeToPhase();
|
||||
ret = fp_ms.count();
|
||||
}
|
||||
else if ( sync > Metronome::SYNC_NONE ) {
|
||||
// SYNC TO BEAT
|
||||
std::chrono::duration<float, std::milli> fp_ms = Metronome::manager().timeToBeat();
|
||||
ret = fp_ms.count();
|
||||
}
|
||||
// SYNC NONE
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t Metronome::peers() const
|
||||
{
|
||||
return link_.numPeers();
|
||||
|
||||
@@ -54,6 +54,10 @@ public:
|
||||
std::chrono::microseconds timeToPhase();
|
||||
void executeAtPhase( std::function<void()> f );
|
||||
|
||||
// get time to sync, in milisecond
|
||||
float timeToSync(Synchronicity sync);
|
||||
|
||||
// get number of connected peers
|
||||
size_t peers () const;
|
||||
|
||||
};
|
||||
|
||||
217
Session.cpp
217
Session.cpp
@@ -31,6 +31,8 @@
|
||||
#include "SessionSource.h"
|
||||
#include "RenderSource.h"
|
||||
#include "MixingGroup.h"
|
||||
#include "ControlManager.h"
|
||||
#include "SourceCallback.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include "Session.h"
|
||||
@@ -62,6 +64,8 @@ Session::Session() : active_(true), activation_threshold_(MIXING_MIN_THRESHOLD),
|
||||
config_[View::TEXTURE]->scale_ = Settings::application.views[View::TEXTURE].default_scale;
|
||||
config_[View::TEXTURE]->translation_ = Settings::application.views[View::TEXTURE].default_translation;
|
||||
|
||||
input_sync_.resize(INPUT_MAX, Metronome::SYNC_NONE);
|
||||
|
||||
snapshots_.xmlDoc_ = new tinyxml2::XMLDocument;
|
||||
start_time_ = gst_util_get_timestamp ();
|
||||
}
|
||||
@@ -82,6 +86,15 @@ Session::~Session()
|
||||
it = deleteSource(*it);
|
||||
}
|
||||
|
||||
// delete all callbacks
|
||||
for (auto iter = input_callbacks_.begin(); iter != input_callbacks_.end();
|
||||
iter = input_callbacks_.erase(iter)) {
|
||||
if ( iter->second.model_ != nullptr)
|
||||
delete iter->second.model_;
|
||||
if ( iter->second.reverse_ != nullptr)
|
||||
delete iter->second.reverse_;
|
||||
}
|
||||
|
||||
delete config_[View::RENDERING];
|
||||
delete config_[View::GEOMETRY];
|
||||
delete config_[View::LAYER];
|
||||
@@ -114,6 +127,50 @@ void Session::update(float dt)
|
||||
if ( render_.frame() == nullptr )
|
||||
return;
|
||||
|
||||
// listen to inputs
|
||||
for (auto k = input_callbacks_.begin(); k != input_callbacks_.end(); ++k)
|
||||
{
|
||||
// get if the input is activated (e.g. key pressed)
|
||||
bool input_active = Control::manager().inputActive(k->first);
|
||||
|
||||
// get the callback model for each input
|
||||
if ( k->second.model_ != nullptr) {
|
||||
|
||||
// if the value referenced as pressed changed state
|
||||
// or repeat key if there is no reverse callback
|
||||
if ( input_active != k->second.active_ || k->second.reverse_ == nullptr) {
|
||||
|
||||
// ON PRESS
|
||||
if (input_active) {
|
||||
// delete the reverse if was not released
|
||||
if (k->second.reverse_ != nullptr)
|
||||
delete k->second.reverse_;
|
||||
|
||||
// generate a new callback from the model
|
||||
SourceCallback *C = k->second.model_->clone();
|
||||
// apply value multiplyer from input
|
||||
C->multiply( Control::manager().inputValue(k->first) );
|
||||
// add delay
|
||||
C->delay( Metronome::manager().timeToSync( (Metronome::Synchronicity) input_sync_[k->first] ) );
|
||||
// add callback to the source (force override)
|
||||
k->second.source_->call( C, true );
|
||||
// get the reverse if the callback, and remember it (can be null)
|
||||
k->second.reverse_ = C->reverse(k->second.source_);
|
||||
}
|
||||
// ON RELEASE
|
||||
else {
|
||||
// call the reverse (NB: invalid value tested in call)
|
||||
k->second.source_->call( k->second.reverse_, true );
|
||||
// do not keep reference to reverse: will be deleted when terminated
|
||||
k->second.reverse_ = nullptr;
|
||||
}
|
||||
|
||||
// remember state of callback
|
||||
k->second.active_ = input_active;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pre-render all sources
|
||||
failedSource_ = nullptr;
|
||||
bool ready = true;
|
||||
@@ -132,6 +189,8 @@ void Session::update(float dt)
|
||||
else {
|
||||
if ( !(*it)->ready() )
|
||||
ready = false;
|
||||
// set inputs
|
||||
|
||||
// update the source
|
||||
(*it)->setActive(activation_threshold_);
|
||||
(*it)->update(dt);
|
||||
@@ -640,3 +699,161 @@ std::string Session::save(const std::string& filename, Session *session, const s
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Session::assignSourceCallback(uint input, Source *source, SourceCallback *callback)
|
||||
{
|
||||
// find if this callback is already assigned
|
||||
auto k = input_callbacks_.begin();
|
||||
for (; k != input_callbacks_.end(); ++k)
|
||||
{
|
||||
// yes, then just change the source pointer
|
||||
if ( k->second.model_ == callback) {
|
||||
if (k->second.reverse_)
|
||||
delete k->second.reverse_;
|
||||
k->second.source_ = source;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if this callback is not assigned yet (looped until end)
|
||||
if ( k == input_callbacks_.end() ) {
|
||||
// create new entry
|
||||
std::multimap<uint, InputSourceCallback>::iterator added = input_callbacks_.emplace(input, InputSourceCallback() );
|
||||
added->second.model_ = callback;
|
||||
added->second.source_ = source;
|
||||
}
|
||||
}
|
||||
|
||||
void Session::swapSourceCallback(uint from, uint to)
|
||||
{
|
||||
std::multimap<uint, InputSourceCallback> swapped_callbacks_;
|
||||
|
||||
for (auto k = input_callbacks_.begin(); k != input_callbacks_.end(); ++k)
|
||||
{
|
||||
if ( k->first == from )
|
||||
swapped_callbacks_.emplace( to, k->second);
|
||||
else
|
||||
swapped_callbacks_.emplace( k->first, k->second);
|
||||
}
|
||||
|
||||
input_callbacks_.swap(swapped_callbacks_);
|
||||
}
|
||||
|
||||
void Session::copySourceCallback(uint from, uint to)
|
||||
{
|
||||
if ( input_callbacks_.count(from) > 0 ) {
|
||||
auto result = input_callbacks_.equal_range(from);
|
||||
for (auto it = result.first; it != result.second; ++it) {
|
||||
assignSourceCallback(to, it->second.source_, it->second.model_->clone() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::list< std::pair<Source *, SourceCallback *> > Session::getSourceCallbacks(uint input)
|
||||
{
|
||||
std::list< std::pair<Source *, SourceCallback*> > ret;
|
||||
|
||||
if ( input_callbacks_.count(input) > 0 ) {
|
||||
auto result = input_callbacks_.equal_range(input);
|
||||
for (auto it = result.first; it != result.second; ++it)
|
||||
ret.push_back( std::pair<Source *, SourceCallback*>(it->second.source_, it->second.model_) );
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Session::deleteSourceCallback(SourceCallback *callback)
|
||||
{
|
||||
for (auto k = input_callbacks_.begin(); k != input_callbacks_.end(); ++k)
|
||||
{
|
||||
if ( k->second.model_ == callback) {
|
||||
delete callback;
|
||||
if (k->second.reverse_)
|
||||
delete k->second.reverse_;
|
||||
input_callbacks_.erase(k);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Session::deleteSourceCallbacks(uint input)
|
||||
{
|
||||
for (auto k = input_callbacks_.begin(); k != input_callbacks_.end();)
|
||||
{
|
||||
if ( k->first == input) {
|
||||
if (k->second.model_)
|
||||
delete k->second.model_;
|
||||
if (k->second.reverse_)
|
||||
delete k->second.reverse_;
|
||||
input_callbacks_.erase(k);
|
||||
}
|
||||
else
|
||||
++k;
|
||||
}
|
||||
}
|
||||
|
||||
void Session::deleteSourceCallbacks(Source *source)
|
||||
{
|
||||
for (auto k = input_callbacks_.begin(); k != input_callbacks_.end();)
|
||||
{
|
||||
if ( k->second.source_ == source) {
|
||||
if (k->second.model_)
|
||||
delete k->second.model_;
|
||||
if (k->second.reverse_)
|
||||
delete k->second.reverse_;
|
||||
input_callbacks_.erase(k);
|
||||
}
|
||||
else
|
||||
++k;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Session::clearSourceCallbacks()
|
||||
{
|
||||
for (auto k = input_callbacks_.begin(); k != input_callbacks_.end(); )
|
||||
{
|
||||
if (k->second.model_)
|
||||
delete k->second.model_;
|
||||
if (k->second.reverse_)
|
||||
delete k->second.reverse_;
|
||||
|
||||
k = input_callbacks_.erase(k);
|
||||
}
|
||||
}
|
||||
|
||||
std::list<uint> Session::assignedInputs()
|
||||
{
|
||||
std::list<uint> inputs;
|
||||
|
||||
// fill with list of keys
|
||||
for(const auto& [key, value] : input_callbacks_) {
|
||||
inputs.push_back(key);
|
||||
}
|
||||
|
||||
// remove duplicates
|
||||
inputs.unique();
|
||||
|
||||
return inputs;
|
||||
}
|
||||
|
||||
bool Session::inputAssigned(uint input)
|
||||
{
|
||||
return input_callbacks_.find(input) != input_callbacks_.end();
|
||||
}
|
||||
|
||||
void Session::setInputSynchrony(uint input, Metronome::Synchronicity sync)
|
||||
{
|
||||
input_sync_[input] = sync;
|
||||
}
|
||||
|
||||
std::vector<Metronome::Synchronicity> Session::getInputSynchrony()
|
||||
{
|
||||
return input_sync_;
|
||||
}
|
||||
|
||||
Metronome::Synchronicity Session::inputSynchrony(uint input)
|
||||
{
|
||||
return input_sync_[input];
|
||||
}
|
||||
|
||||
|
||||
32
Session.h
32
Session.h
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "SourceList.h"
|
||||
#include "RenderView.h"
|
||||
#include "Metronome.h"
|
||||
|
||||
namespace tinyxml2 {
|
||||
class XMLDocument;
|
||||
@@ -151,6 +152,22 @@ public:
|
||||
void removeFromPlayGroup(size_t i, Source *s);
|
||||
std::vector<SourceIdList> getPlayGroups() { return play_groups_; }
|
||||
|
||||
// callbacks associated to inputs
|
||||
void assignSourceCallback(uint input, Source *source, SourceCallback *callback);
|
||||
std::list< std::pair<Source *, SourceCallback*> > getSourceCallbacks(uint input);
|
||||
void deleteSourceCallback (SourceCallback *callback);
|
||||
void deleteSourceCallbacks(Source *source);
|
||||
void deleteSourceCallbacks(uint input);
|
||||
void clearSourceCallbacks ();
|
||||
std::list<uint> assignedInputs();
|
||||
bool inputAssigned(uint input);
|
||||
void swapSourceCallback(uint from, uint to);
|
||||
void copySourceCallback(uint from, uint to);
|
||||
|
||||
void setInputSynchrony(uint input, Metronome::Synchronicity sync);
|
||||
std::vector<Metronome::Synchronicity> getInputSynchrony();
|
||||
Metronome::Synchronicity inputSynchrony(uint input);
|
||||
|
||||
protected:
|
||||
bool active_;
|
||||
float activation_threshold_;
|
||||
@@ -186,7 +203,20 @@ protected:
|
||||
};
|
||||
Fading fading_;
|
||||
|
||||
// std::map<uint64_t,
|
||||
struct InputSourceCallback {
|
||||
bool active_;
|
||||
SourceCallback *model_;
|
||||
SourceCallback *reverse_;
|
||||
Source *source_;
|
||||
InputSourceCallback() {
|
||||
active_ = false;
|
||||
model_ = nullptr;
|
||||
reverse_ = nullptr;
|
||||
source_ = nullptr;
|
||||
}
|
||||
};
|
||||
std::multimap<uint, InputSourceCallback> input_callbacks_;
|
||||
std::vector<Metronome::Synchronicity> input_sync_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -149,6 +149,9 @@ void SessionCreator::load(const std::string& filename)
|
||||
// load playlists
|
||||
loadPlayGroups( xmlDoc_.FirstChildElement("PlayGroups") );
|
||||
|
||||
// load input callbacks
|
||||
loadInputCallbacks( xmlDoc_.FirstChildElement("InputCallbacks") );
|
||||
|
||||
// thumbnail
|
||||
const XMLElement *thumbnailelement = sessionNode->FirstChildElement("Thumbnail");
|
||||
// if there is a user-defined thumbnail, get it
|
||||
@@ -193,6 +196,62 @@ void SessionCreator::loadSnapshots(XMLElement *snapshotsNode)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SessionCreator::loadInputCallbacks(tinyxml2::XMLElement *inputsNode)
|
||||
{
|
||||
if (inputsNode != nullptr && session_ != nullptr) {
|
||||
|
||||
// read all 'Callback' nodes
|
||||
xmlCurrent_ = inputsNode->FirstChildElement("Callback");
|
||||
for ( ; xmlCurrent_ ; xmlCurrent_ = xmlCurrent_->NextSiblingElement()) {
|
||||
// what key triggers the callback ?
|
||||
uint input = 0;
|
||||
xmlCurrent_->QueryUnsignedAttribute("input", &input);
|
||||
if (input > 0) {
|
||||
// what id is the source ?
|
||||
uint64_t id = 0;
|
||||
xmlCurrent_->QueryUnsigned64Attribute("id", &id);
|
||||
if (id > 0) {
|
||||
// what type is the callback ?
|
||||
uint type = 0;
|
||||
xmlCurrent_->QueryUnsignedAttribute("type", &type);
|
||||
// instanciate the callback of that type
|
||||
SourceCallback *loadedcallback = SourceCallback::create((SourceCallback::CallbackType)type);
|
||||
// successfully created a callback of saved type
|
||||
if (loadedcallback) {
|
||||
// apply specific parameters
|
||||
loadedcallback->accept(*this);
|
||||
// find the source with the given id
|
||||
SourceList::iterator sit = session_->find(id);
|
||||
if (sit != session_->end()) {
|
||||
// assign to source in session
|
||||
session_->assignSourceCallback(input, *sit, loadedcallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// read array of synchronyzation mode for all inputs (CSV)
|
||||
xmlCurrent_ = inputsNode->FirstChildElement("Synchrony");
|
||||
if (xmlCurrent_) {
|
||||
const char *text = xmlCurrent_->GetText();
|
||||
if (text) {
|
||||
std::istringstream iss(text);
|
||||
std::string token;
|
||||
uint i = 0;
|
||||
while(std::getline(iss, token, ';')) {
|
||||
if (token.compare("1") == 0)
|
||||
session_->setInputSynchrony(i, Metronome::SYNC_BEAT);
|
||||
else if (token.compare("2") == 0)
|
||||
session_->setInputSynchrony(i, Metronome::SYNC_PHASE);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SessionCreator::loadNotes(XMLElement *notesNode)
|
||||
{
|
||||
if (notesNode != nullptr && session_ != nullptr) {
|
||||
@@ -900,30 +959,6 @@ void SessionLoader::visit (Source& s)
|
||||
groups_sources_id_.push_back(idlist);
|
||||
}
|
||||
|
||||
XMLElement* callbacksNode = sourceNode->FirstChildElement("Callbacks");
|
||||
if (callbacksNode) {
|
||||
// Loop over 'Callback' nodes
|
||||
xmlCurrent_ = callbacksNode->FirstChildElement("Callback");
|
||||
for ( ; xmlCurrent_ ; xmlCurrent_ = xmlCurrent_->NextSiblingElement()) {
|
||||
// what key triggers the callback ?
|
||||
uint input = 0;
|
||||
xmlCurrent_->QueryUnsignedAttribute("input", &input);
|
||||
// what type is the callback ?
|
||||
uint type = 0;
|
||||
xmlCurrent_->QueryUnsignedAttribute("type", &type);
|
||||
// instanciate the callback of that type
|
||||
SourceCallback *loadedcallback = SourceCallback::create((SourceCallback::CallbackType)type);
|
||||
// successfully created a callback of saved type
|
||||
if (loadedcallback) {
|
||||
// apply specific parameters
|
||||
loadedcallback->accept(*this);
|
||||
// add callback to source
|
||||
s.addInputCallback(input, loadedcallback);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// restore current
|
||||
xmlCurrent_ = sourceNode;
|
||||
}
|
||||
|
||||
@@ -112,6 +112,7 @@ class SessionCreator : public SessionLoader {
|
||||
void loadNotes(tinyxml2::XMLElement *notesNode);
|
||||
void loadPlayGroups(tinyxml2::XMLElement *playlistsNode);
|
||||
void loadSnapshots(tinyxml2::XMLElement *snapshotNode);
|
||||
void loadInputCallbacks(tinyxml2::XMLElement *inputsNode);
|
||||
|
||||
public:
|
||||
SessionCreator(int recursion = 0);
|
||||
|
||||
@@ -110,6 +110,9 @@ bool SessionVisitor::saveSession(const std::string& filename, Session *session)
|
||||
// 5. optional playlists
|
||||
savePlayGroups( &xmlDoc, session );
|
||||
|
||||
// 5. optional playlists
|
||||
saveInputCallbacks( &xmlDoc, session );
|
||||
|
||||
// save file to disk
|
||||
return ( XMLSaveDoc(&xmlDoc, filename) );
|
||||
}
|
||||
@@ -202,6 +205,47 @@ void SessionVisitor::savePlayGroups(tinyxml2::XMLDocument *doc, Session *session
|
||||
}
|
||||
}
|
||||
|
||||
void SessionVisitor::saveInputCallbacks(tinyxml2::XMLDocument *doc, Session *session)
|
||||
{
|
||||
// invalid inputs
|
||||
if (doc != nullptr && session != nullptr)
|
||||
{
|
||||
// create node
|
||||
XMLElement *inputsNode = doc->NewElement("InputCallbacks");
|
||||
doc->InsertEndChild(inputsNode);
|
||||
|
||||
// list of inputs assigned in the session
|
||||
std::list<uint> inputs = session->assignedInputs();
|
||||
if (!inputs.empty()) {
|
||||
// loop over list of inputs
|
||||
for (auto i = inputs.begin(); i != inputs.end(); ++i) {
|
||||
// get all callbacks for this input
|
||||
auto result = session->getSourceCallbacks(*i);
|
||||
for (auto kit = result.cbegin(); kit != result.cend(); ++kit) {
|
||||
// create node for this callback
|
||||
XMLElement *cbNode = doc->NewElement("Callback");
|
||||
cbNode->SetAttribute("input", *i);
|
||||
cbNode->SetAttribute("id", kit->first->id());
|
||||
inputsNode->InsertEndChild(cbNode);
|
||||
// launch visitor to complete attributes
|
||||
SessionVisitor sv(doc, cbNode);
|
||||
kit->second->accept(sv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// save array of synchronyzation mode for all inputs (CSV)
|
||||
std::ostringstream oss;
|
||||
std::vector<Metronome::Synchronicity> synch = session->getInputSynchrony();
|
||||
for (auto token = synch.begin(); token != synch.end(); ++token)
|
||||
oss << (int) *token << ';';
|
||||
XMLElement *syncNode = doc->NewElement("Synchrony");
|
||||
XMLText *text = doc->NewText( oss.str().c_str() );
|
||||
syncNode->InsertEndChild(text);
|
||||
inputsNode->InsertEndChild(syncNode);
|
||||
}
|
||||
}
|
||||
|
||||
SessionVisitor::SessionVisitor(tinyxml2::XMLDocument *doc,
|
||||
tinyxml2::XMLElement *root,
|
||||
bool recursive) : Visitor(), recursive_(recursive), xmlCurrent_(root)
|
||||
@@ -580,22 +624,6 @@ void SessionVisitor::visit (Source& s)
|
||||
s.mixingGroup()->accept(*this);
|
||||
}
|
||||
|
||||
std::list<uint> inputs = s.callbackInputs();
|
||||
if (!inputs.empty()) {
|
||||
// list of callbacks
|
||||
XMLElement *callbackselement = xmlDoc_->NewElement( "Callbacks" );
|
||||
sourceNode->InsertEndChild(callbackselement);
|
||||
for (auto i = inputs.begin(); i != inputs.end(); ++i) {
|
||||
std::list<SourceCallback *> callbacks = s.inputCallbacks(*i);
|
||||
for (auto c = callbacks.begin(); c != callbacks.end(); ++c) {
|
||||
xmlCurrent_ = xmlDoc_->NewElement( "Callback" );
|
||||
callbackselement->InsertEndChild(xmlCurrent_);
|
||||
xmlCurrent_->SetAttribute("input", *i);
|
||||
(*c)->accept(*this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xmlCurrent_ = sourceNode; // parent for next visits (other subtypes of Source)
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ class SessionVisitor : public Visitor {
|
||||
static void saveSnapshots(tinyxml2::XMLDocument *doc, Session *session);
|
||||
static void saveNotes(tinyxml2::XMLDocument *doc, Session *session);
|
||||
static void savePlayGroups(tinyxml2::XMLDocument *doc, Session *session);
|
||||
static void saveInputCallbacks(tinyxml2::XMLDocument *doc, Session *session);
|
||||
|
||||
public:
|
||||
SessionVisitor(tinyxml2::XMLDocument *doc = nullptr,
|
||||
|
||||
131
Source.cpp
131
Source.cpp
@@ -34,6 +34,7 @@
|
||||
#include "BaseToolkit.h"
|
||||
#include "SystemToolkit.h"
|
||||
#include "MixingGroup.h"
|
||||
#include "Metronome.h"
|
||||
#include "ControlManager.h"
|
||||
#include "SourceCallback.h"
|
||||
|
||||
@@ -360,16 +361,6 @@ Source::~Source()
|
||||
delete callback;
|
||||
}
|
||||
access_callbacks_.unlock();
|
||||
|
||||
// clear and delete key_callbacks
|
||||
for (auto iter = input_callbacks_.begin(); iter != input_callbacks_.end();
|
||||
iter = input_callbacks_.erase(iter)) {
|
||||
if ( iter->second.model_ != nullptr)
|
||||
delete iter->second.model_;
|
||||
if ( iter->second.reverse_ != nullptr)
|
||||
delete iter->second.reverse_;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Source::setName (const std::string &name)
|
||||
@@ -678,125 +669,8 @@ void Source::call(SourceCallback *callback, bool override)
|
||||
|
||||
}
|
||||
|
||||
void Source::addInputCallback(uint input, SourceCallback *callback)
|
||||
{
|
||||
std::multimap<uint, InputCallback>::iterator added = input_callbacks_.emplace(input, InputCallback() );
|
||||
added->second.model_ = callback;
|
||||
}
|
||||
|
||||
void Source::swapInputCallback(uint from, uint to)
|
||||
{
|
||||
std::multimap<uint, InputCallback> swapped_callbacks_;
|
||||
|
||||
for (auto k = input_callbacks_.begin(); k != input_callbacks_.end(); ++k)
|
||||
{
|
||||
if ( k->first == from )
|
||||
swapped_callbacks_.emplace( to, k->second);
|
||||
else
|
||||
swapped_callbacks_.emplace( k->first, k->second);
|
||||
}
|
||||
|
||||
input_callbacks_.swap(swapped_callbacks_);
|
||||
}
|
||||
|
||||
|
||||
void Source::removeInputCallback(SourceCallback *callback)
|
||||
{
|
||||
for (auto k = input_callbacks_.begin(); k != input_callbacks_.end(); ++k)
|
||||
{
|
||||
if ( k->second.model_ == callback) {
|
||||
delete callback;
|
||||
if (k->second.reverse_)
|
||||
delete k->second.reverse_;
|
||||
input_callbacks_.erase(k);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Source::clearInputCallbacks()
|
||||
{
|
||||
for (auto k = input_callbacks_.begin(); k != input_callbacks_.end(); )
|
||||
{
|
||||
if (k->second.model_)
|
||||
delete k->second.model_;
|
||||
if (k->second.reverse_)
|
||||
delete k->second.reverse_;
|
||||
|
||||
k = input_callbacks_.erase(k);
|
||||
}
|
||||
}
|
||||
|
||||
std::list<SourceCallback *> Source::inputCallbacks(uint input)
|
||||
{
|
||||
std::list<SourceCallback *> ret;
|
||||
|
||||
if ( input_callbacks_.count(input) > 0 ) {
|
||||
auto result = input_callbacks_.equal_range(input);
|
||||
for (auto it = result.first; it != result.second; ++it)
|
||||
ret.push_back( it->second.model_ );
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
std::list<uint> Source::callbackInputs()
|
||||
{
|
||||
std::list<uint> inputs;
|
||||
|
||||
// fill with list of keys
|
||||
for(const auto& [key, value] : input_callbacks_) {
|
||||
inputs.push_back(key);
|
||||
}
|
||||
|
||||
// remove duplicates
|
||||
inputs.unique();
|
||||
|
||||
return inputs;
|
||||
}
|
||||
|
||||
void Source::updateCallbacks(float dt)
|
||||
{
|
||||
// add callbacks from listener
|
||||
for (auto k = input_callbacks_.begin(); k != input_callbacks_.end(); ++k)
|
||||
{
|
||||
// if the Reaction is valid
|
||||
if ( k->second.model_ != nullptr) {
|
||||
|
||||
bool activate = Control::manager().inputActive(k->first);
|
||||
|
||||
// if the value referenced as pressed changed state
|
||||
// or repeat key if there is no reverse callback
|
||||
if ( activate != k->second.active_ || k->second.reverse_ == nullptr) {
|
||||
|
||||
// ON PRESS
|
||||
if (activate) {
|
||||
// generate a new callback from the model
|
||||
SourceCallback *C = k->second.model_->clone();
|
||||
// apply value multiplyer from input
|
||||
C->multiply( Control::manager().inputValue(k->first) );
|
||||
// add callback to the source (force override)
|
||||
call( C, true );
|
||||
// delete the reverse if was not released
|
||||
if (k->second.reverse_ != nullptr)
|
||||
delete k->second.reverse_;
|
||||
// get the reverse if the callback, and remember it (can be null)
|
||||
k->second.reverse_ = C->reverse(this);
|
||||
}
|
||||
// ON RELEASE
|
||||
else {
|
||||
// call the reverse (NB: invalid value tested in call)
|
||||
call( k->second.reverse_, true );
|
||||
// do not keep reference to reverse: will be deleted when terminated
|
||||
k->second.reverse_ = nullptr;
|
||||
}
|
||||
|
||||
k->second.active_ = activate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// lock access to callbacks list
|
||||
access_callbacks_.lock();
|
||||
// call callback functions
|
||||
@@ -819,6 +693,7 @@ void Source::updateCallbacks(float dt)
|
||||
}
|
||||
// release access to callbacks list
|
||||
access_callbacks_.unlock();
|
||||
|
||||
}
|
||||
|
||||
CloneSource *Source::clone(uint64_t id)
|
||||
@@ -838,7 +713,7 @@ void Source::update(float dt)
|
||||
// if update is possible
|
||||
if (renderbuffer_ && mixingsurface_ && maskbuffer_)
|
||||
{
|
||||
// react to input and call active callbacks
|
||||
// call active callbacks
|
||||
updateCallbacks(dt);
|
||||
|
||||
// update nodes if needed
|
||||
|
||||
19
Source.h
19
Source.h
@@ -148,14 +148,6 @@ public:
|
||||
// add callback to each update
|
||||
void call(SourceCallback *callback, bool override = false);
|
||||
|
||||
// callbacks associated to keys
|
||||
void addInputCallback(uint input, SourceCallback *callback);
|
||||
void removeInputCallback(SourceCallback *callback);
|
||||
std::list<SourceCallback *> inputCallbacks(uint input);
|
||||
std::list<uint> callbackInputs();
|
||||
void swapInputCallback(uint from, uint to);
|
||||
void clearInputCallbacks();
|
||||
|
||||
// update mode
|
||||
inline bool active () const { return active_; }
|
||||
virtual void setActive (bool on);
|
||||
@@ -325,17 +317,6 @@ protected:
|
||||
// callbacks
|
||||
std::list<SourceCallback *> update_callbacks_;
|
||||
std::mutex access_callbacks_;
|
||||
struct InputCallback {
|
||||
bool active_;
|
||||
SourceCallback *model_;
|
||||
SourceCallback *reverse_;
|
||||
InputCallback() {
|
||||
active_ = false;
|
||||
model_ = nullptr;
|
||||
reverse_ = nullptr;
|
||||
}
|
||||
};
|
||||
std::multimap<uint, InputCallback> input_callbacks_;
|
||||
void updateCallbacks(float dt);
|
||||
|
||||
// clones
|
||||
|
||||
@@ -113,7 +113,7 @@ bool SourceCallback::overlap( SourceCallback *a, SourceCallback *b)
|
||||
return ret;
|
||||
}
|
||||
|
||||
SourceCallback::SourceCallback(): finished_(false), initialized_(false)
|
||||
SourceCallback::SourceCallback(): status_(PENDING), delay_(0.f), elapsed_(0.f)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -122,14 +122,39 @@ void SourceCallback::accept(Visitor& v)
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
void ResetGeometry::update(Source *s, float)
|
||||
void SourceCallback::update (Source *s, float dt)
|
||||
{
|
||||
if (s != nullptr) {
|
||||
// time passed
|
||||
elapsed_ += dt;
|
||||
// wait for delay to start
|
||||
if ( status_ == PENDING && elapsed_ > delay_ )
|
||||
status_ = READY;
|
||||
}
|
||||
// invalid
|
||||
else
|
||||
status_ = FINISHED;
|
||||
|
||||
}
|
||||
|
||||
void ResetGeometry::update(Source *s, float dt)
|
||||
{
|
||||
SourceCallback::update(s, dt);
|
||||
|
||||
if (s->locked())
|
||||
status_ = FINISHED;
|
||||
|
||||
// apply when ready
|
||||
if ( status_ == READY ){
|
||||
|
||||
s->group(View::GEOMETRY)->scale_ = glm::vec3(1.f);
|
||||
s->group(View::GEOMETRY)->rotation_.z = 0;
|
||||
s->group(View::GEOMETRY)->crop_ = glm::vec3(1.f);
|
||||
s->group(View::GEOMETRY)->translation_ = glm::vec3(0.f);
|
||||
s->touch();
|
||||
finished_ = true;
|
||||
|
||||
status_ = FINISHED;
|
||||
}
|
||||
}
|
||||
|
||||
SourceCallback *ResetGeometry::clone() const
|
||||
@@ -137,8 +162,9 @@ SourceCallback *ResetGeometry::clone() const
|
||||
return new ResetGeometry;
|
||||
}
|
||||
|
||||
|
||||
SetAlpha::SetAlpha(float alpha, float ms, bool revert) : SourceCallback(),
|
||||
duration_(ms), progress_(0.f), alpha_(alpha), bidirectional_(revert)
|
||||
duration_(ms), alpha_(alpha), bidirectional_(revert)
|
||||
{
|
||||
alpha_ = CLAMP(alpha_, 0.f, 1.f);
|
||||
start_ = glm::vec2();
|
||||
@@ -147,9 +173,13 @@ SetAlpha::SetAlpha(float alpha, float ms, bool revert) : SourceCallback(),
|
||||
|
||||
void SetAlpha::update(Source *s, float dt)
|
||||
{
|
||||
if (s && !s->locked()) {
|
||||
// set start position on first run or upon call of reset()
|
||||
if (!initialized_){
|
||||
SourceCallback::update(s, dt);
|
||||
|
||||
if (s->locked())
|
||||
status_ = FINISHED;
|
||||
|
||||
// set start position on first time it is ready
|
||||
if ( status_ == READY ){
|
||||
// initial mixing view position
|
||||
start_ = glm::vec2(s->group(View::MIXING)->translation_);
|
||||
|
||||
@@ -180,28 +210,27 @@ void SetAlpha::update(Source *s, float dt)
|
||||
} while (glm::abs(delta) > DELTA_ALPHA);
|
||||
}
|
||||
|
||||
initialized_ = true;
|
||||
status_ = ACTIVE;
|
||||
}
|
||||
|
||||
// time passed
|
||||
progress_ += dt;
|
||||
if ( status_ == ACTIVE ) {
|
||||
// time passed since start
|
||||
float progress = elapsed_ - delay_;
|
||||
|
||||
// perform movement
|
||||
if ( ABS(duration_) > 0.f)
|
||||
s->group(View::MIXING)->translation_ = glm::vec3(start_ + (progress_/duration_)*(target_ - start_), s->group(View::MIXING)->translation_.z);
|
||||
s->group(View::MIXING)->translation_ = glm::vec3(start_ + (progress/duration_)*(target_ - start_), s->group(View::MIXING)->translation_.z);
|
||||
|
||||
// time-out
|
||||
if ( progress_ > duration_ ) {
|
||||
if ( progress > duration_ ) {
|
||||
// apply alpha to target
|
||||
s->group(View::MIXING)->translation_ = glm::vec3(target_, s->group(View::MIXING)->translation_.z);
|
||||
// done
|
||||
finished_ = true;
|
||||
status_ = FINISHED;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
finished_ = true;
|
||||
}
|
||||
|
||||
void SetAlpha::multiply (float factor)
|
||||
{
|
||||
@@ -233,7 +262,7 @@ void Lock::update(Source *s, float)
|
||||
if (s)
|
||||
s->setLocked(lock_);
|
||||
|
||||
finished_ = true;
|
||||
status_ = FINISHED;
|
||||
}
|
||||
|
||||
SourceCallback *Lock::clone() const
|
||||
@@ -243,7 +272,7 @@ SourceCallback *Lock::clone() const
|
||||
|
||||
|
||||
Loom::Loom(float speed, float ms) : SourceCallback(),
|
||||
speed_(speed), duration_(ms), progress_(0.f)
|
||||
speed_(speed), duration_(ms)
|
||||
{
|
||||
pos_ = glm::vec2();
|
||||
step_ = glm::normalize(glm::vec2(1.f, 1.f)); // step in diagonal by default
|
||||
@@ -251,22 +280,24 @@ Loom::Loom(float speed, float ms) : SourceCallback(),
|
||||
|
||||
void Loom::update(Source *s, float dt)
|
||||
{
|
||||
if (s && !s->locked()) {
|
||||
// reset on first run or upon call of reset()
|
||||
if (!initialized_){
|
||||
// start animation
|
||||
progress_ = 0.f;
|
||||
SourceCallback::update(s, dt);
|
||||
|
||||
if (s->locked())
|
||||
status_ = FINISHED;
|
||||
|
||||
// set start on first time it is ready
|
||||
if ( status_ == READY ){
|
||||
// initial position
|
||||
pos_ = glm::vec2(s->group(View::MIXING)->translation_);
|
||||
// step in direction of source translation if possible
|
||||
if ( glm::length(pos_) > DELTA_ALPHA)
|
||||
step_ = glm::normalize(pos_);
|
||||
|
||||
initialized_ = true;
|
||||
status_ = ACTIVE;
|
||||
}
|
||||
|
||||
// time passed
|
||||
progress_ += dt;
|
||||
if ( status_ == ACTIVE ) {
|
||||
// time passed since start
|
||||
float progress = elapsed_ - delay_;
|
||||
|
||||
// move target by speed vector (in the direction of step_, amplitude of speed * time (in second))
|
||||
pos_ -= step_ * ( speed_ * dt * 0.001f );
|
||||
@@ -275,16 +306,15 @@ void Loom::update(Source *s, float dt)
|
||||
float l = glm::length( pos_ );
|
||||
if ( (l > 0.01f && speed_ > 0.f ) || (l < MIXING_MIN_THRESHOLD && speed_ < 0.f ) )
|
||||
s->group(View::MIXING)->translation_ = glm::vec3(pos_, s->group(View::MIXING)->translation_.z);
|
||||
else
|
||||
status_ = FINISHED;
|
||||
|
||||
// time-out
|
||||
if ( progress_ > duration_ ) {
|
||||
if ( progress > duration_ )
|
||||
// done
|
||||
finished_ = true;
|
||||
status_ = FINISHED;
|
||||
}
|
||||
}
|
||||
else
|
||||
finished_ = true;
|
||||
}
|
||||
|
||||
void Loom::multiply (float factor)
|
||||
{
|
||||
@@ -296,6 +326,11 @@ SourceCallback *Loom::clone() const
|
||||
return new Loom(speed_, duration_);
|
||||
}
|
||||
|
||||
SourceCallback *Loom::reverse(Source *) const
|
||||
{
|
||||
return new Loom(speed_, 0.f);
|
||||
}
|
||||
|
||||
void Loom::accept(Visitor& v)
|
||||
{
|
||||
SourceCallback::accept(v);
|
||||
@@ -303,42 +338,43 @@ void Loom::accept(Visitor& v)
|
||||
}
|
||||
|
||||
|
||||
|
||||
SetDepth::SetDepth(float target, float ms, bool revert) : SourceCallback(),
|
||||
duration_(ms), progress_(0.f), start_(0.f), target_(target), bidirectional_(revert)
|
||||
duration_(ms), start_(0.f), target_(target), bidirectional_(revert)
|
||||
{
|
||||
target_ = CLAMP(target_, MIN_DEPTH, MAX_DEPTH);
|
||||
}
|
||||
|
||||
void SetDepth::update(Source *s, float dt)
|
||||
{
|
||||
if (s && !s->locked()) {
|
||||
// set start position on first run or upon call of reset()
|
||||
if (!initialized_){
|
||||
SourceCallback::update(s, dt);
|
||||
|
||||
if (s->locked())
|
||||
status_ = FINISHED;
|
||||
|
||||
// set start position on first time it is ready
|
||||
if ( status_ == READY ){
|
||||
start_ = s->group(View::LAYER)->translation_.z;
|
||||
progress_ = 0.f;
|
||||
initialized_ = true;
|
||||
status_ = ACTIVE;
|
||||
}
|
||||
|
||||
// time passed
|
||||
progress_ += dt;
|
||||
if ( status_ == ACTIVE ) {
|
||||
// time passed since start
|
||||
float progress = elapsed_ - delay_;
|
||||
|
||||
// perform movement
|
||||
if ( ABS(duration_) > 0.f)
|
||||
s->group(View::LAYER)->translation_.z = start_ + (progress_/duration_) * (target_ - start_);
|
||||
s->group(View::LAYER)->translation_.z = start_ + (progress/duration_) * (target_ - start_);
|
||||
|
||||
// time-out
|
||||
if ( progress_ > duration_ ) {
|
||||
if ( progress > duration_ ) {
|
||||
// apply depth to target
|
||||
s->group(View::LAYER)->translation_.z = target_;
|
||||
// ensure reordering of view
|
||||
++View::need_deep_update_;
|
||||
// done
|
||||
finished_ = true;
|
||||
status_ = FINISHED;
|
||||
}
|
||||
}
|
||||
else
|
||||
finished_ = true;
|
||||
}
|
||||
|
||||
void SetDepth::multiply (float factor)
|
||||
@@ -366,14 +402,20 @@ Play::Play(bool on, bool revert) : SourceCallback(), play_(on), bidirectional_(r
|
||||
{
|
||||
}
|
||||
|
||||
void Play::update(Source *s, float)
|
||||
void Play::update(Source *s, float dt)
|
||||
{
|
||||
if (s && s->playing() != play_) {
|
||||
SourceCallback::update(s, dt);
|
||||
|
||||
// toggle play status when ready
|
||||
if ( status_ == READY ){
|
||||
|
||||
if (s->playing() != play_)
|
||||
// call play function
|
||||
s->play(play_);
|
||||
|
||||
status_ = FINISHED;
|
||||
}
|
||||
|
||||
finished_ = true;
|
||||
}
|
||||
|
||||
SourceCallback *Play::clone() const
|
||||
@@ -396,14 +438,18 @@ RePlay::RePlay() : SourceCallback()
|
||||
{
|
||||
}
|
||||
|
||||
void RePlay::update(Source *s, float)
|
||||
void RePlay::update(Source *s, float dt)
|
||||
{
|
||||
if (s) {
|
||||
SourceCallback::update(s, dt);
|
||||
|
||||
// apply when ready
|
||||
if ( status_ == READY ){
|
||||
|
||||
// call replay function
|
||||
s->replay();
|
||||
}
|
||||
|
||||
finished_ = true;
|
||||
status_ = FINISHED;
|
||||
}
|
||||
}
|
||||
|
||||
SourceCallback *RePlay::clone() const
|
||||
@@ -413,7 +459,7 @@ SourceCallback *RePlay::clone() const
|
||||
|
||||
|
||||
SetGeometry::SetGeometry(const Group *g, float ms, bool revert) : SourceCallback(),
|
||||
duration_(ms), progress_(0.f), bidirectional_(revert)
|
||||
duration_(ms), bidirectional_(revert)
|
||||
{
|
||||
setTarget(g);
|
||||
}
|
||||
@@ -432,20 +478,24 @@ void SetGeometry::setTarget (const Group *g)
|
||||
|
||||
void SetGeometry::update(Source *s, float dt)
|
||||
{
|
||||
if (s && !s->locked()) {
|
||||
// set start position on first run or upon call of reset()
|
||||
if (!initialized_){
|
||||
SourceCallback::update(s, dt);
|
||||
|
||||
if (s->locked())
|
||||
status_ = FINISHED;
|
||||
|
||||
// set start position on first time it is ready
|
||||
if ( status_ == READY ){
|
||||
start_.copyTransform(s->group(View::GEOMETRY));
|
||||
progress_ = 0.f;
|
||||
initialized_ = true;
|
||||
status_ = ACTIVE;
|
||||
}
|
||||
|
||||
// time passed
|
||||
progress_ += dt;
|
||||
if ( status_ == ACTIVE ) {
|
||||
// time passed since start
|
||||
float progress = elapsed_ - delay_;
|
||||
|
||||
// perform movement
|
||||
if ( ABS(duration_) > 0.f){
|
||||
float ratio = progress_ / duration_;
|
||||
float ratio = progress / duration_;
|
||||
Group intermediate;
|
||||
intermediate.translation_ = (1.f - ratio) * start_.translation_ + ratio * target_.translation_;
|
||||
intermediate.scale_ = (1.f - ratio) * start_.scale_ + ratio * target_.scale_;
|
||||
@@ -456,22 +506,19 @@ void SetGeometry::update(Source *s, float dt)
|
||||
}
|
||||
|
||||
// time-out
|
||||
if ( progress_ > duration_ ) {
|
||||
if ( progress > duration_ ) {
|
||||
// apply target
|
||||
s->group(View::GEOMETRY)->copyTransform(&target_);
|
||||
s->touch();
|
||||
// done
|
||||
finished_ = true;
|
||||
status_ = FINISHED;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
finished_ = true;
|
||||
}
|
||||
|
||||
void SetGeometry::multiply (float factor)
|
||||
{
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
SourceCallback *SetGeometry::clone() const
|
||||
@@ -493,38 +540,36 @@ void SetGeometry::accept(Visitor& v)
|
||||
|
||||
|
||||
Grab::Grab(float dx, float dy, float ms) : SourceCallback(),
|
||||
speed_(glm::vec2(dx, dy)), duration_(ms), progress_(0.f)
|
||||
speed_(glm::vec2(dx, dy)), duration_(ms)
|
||||
{
|
||||
}
|
||||
|
||||
void Grab::update(Source *s, float dt)
|
||||
{
|
||||
if (s && !s->locked()) {
|
||||
// reset on first run or upon call of reset()
|
||||
if (!initialized_){
|
||||
// start animation
|
||||
progress_ = 0.f;
|
||||
SourceCallback::update(s, dt);
|
||||
|
||||
if (s->locked())
|
||||
status_ = FINISHED;
|
||||
|
||||
// set start on first time it is ready
|
||||
if ( status_ == READY ) {
|
||||
// initial position
|
||||
start_ = glm::vec2(s->group(View::GEOMETRY)->translation_);
|
||||
initialized_ = true;
|
||||
pos_ = glm::vec2(s->group(View::GEOMETRY)->translation_);
|
||||
status_ = ACTIVE;
|
||||
}
|
||||
|
||||
// time passed
|
||||
progress_ += dt;
|
||||
if ( status_ == ACTIVE ) {
|
||||
|
||||
// move target by speed vector * time (in second)
|
||||
glm::vec2 pos = start_ + speed_ * ( dt * 0.001f);
|
||||
s->group(View::GEOMETRY)->translation_ = glm::vec3(pos, s->group(View::GEOMETRY)->translation_.z);
|
||||
pos_ += speed_ * ( dt * 0.001f);
|
||||
s->group(View::GEOMETRY)->translation_ = glm::vec3(pos_, s->group(View::GEOMETRY)->translation_.z);
|
||||
|
||||
// time-out
|
||||
if ( progress_ > duration_ ) {
|
||||
if ( (elapsed_ - delay_) > duration_ )
|
||||
// done
|
||||
finished_ = true;
|
||||
status_ = FINISHED;
|
||||
}
|
||||
}
|
||||
else
|
||||
finished_ = true;
|
||||
}
|
||||
|
||||
void Grab::multiply (float factor)
|
||||
{
|
||||
@@ -536,6 +581,11 @@ SourceCallback *Grab::clone() const
|
||||
return new Grab(speed_.x, speed_.y, duration_);
|
||||
}
|
||||
|
||||
SourceCallback *Grab::reverse(Source *) const
|
||||
{
|
||||
return new Grab(speed_.x, speed_.y, 0.f);
|
||||
}
|
||||
|
||||
void Grab::accept(Visitor& v)
|
||||
{
|
||||
SourceCallback::accept(v);
|
||||
@@ -543,38 +593,30 @@ void Grab::accept(Visitor& v)
|
||||
}
|
||||
|
||||
Resize::Resize(float dx, float dy, float ms) : SourceCallback(),
|
||||
speed_(glm::vec2(dx, dy)), duration_(ms), progress_(0.f)
|
||||
speed_(glm::vec2(dx, dy)), duration_(ms)
|
||||
{
|
||||
}
|
||||
|
||||
void Resize::update(Source *s, float dt)
|
||||
{
|
||||
if (s && !s->locked()) {
|
||||
// reset on first run or upon call of reset()
|
||||
if (!initialized_){
|
||||
// start animation
|
||||
progress_ = 0.f;
|
||||
// initial position
|
||||
start_ = glm::vec2(s->group(View::GEOMETRY)->scale_);
|
||||
initialized_ = true;
|
||||
}
|
||||
SourceCallback::update(s, dt);
|
||||
|
||||
// time passed
|
||||
progress_ += dt;
|
||||
if (s->locked())
|
||||
status_ = FINISHED;
|
||||
|
||||
if ( status_ == READY )
|
||||
status_ = ACTIVE;
|
||||
|
||||
if ( status_ == ACTIVE ) {
|
||||
// move target by speed vector * time (in second)
|
||||
glm::vec2 scale = start_ + speed_ * ( dt * 0.001f);
|
||||
glm::vec2 scale = glm::vec2(s->group(View::GEOMETRY)->scale_) + speed_ * ( dt * 0.001f );
|
||||
s->group(View::GEOMETRY)->scale_ = glm::vec3(scale, s->group(View::GEOMETRY)->scale_.z);
|
||||
|
||||
// time-out
|
||||
if ( progress_ > duration_ ) {
|
||||
// done
|
||||
finished_ = true;
|
||||
if ( (elapsed_ - delay_) > duration_ )
|
||||
status_ = FINISHED;
|
||||
}
|
||||
}
|
||||
else
|
||||
finished_ = true;
|
||||
}
|
||||
|
||||
void Resize::multiply (float factor)
|
||||
{
|
||||
@@ -586,6 +628,11 @@ SourceCallback *Resize::clone() const
|
||||
return new Resize(speed_.x, speed_.y, duration_);
|
||||
}
|
||||
|
||||
SourceCallback *Resize::reverse(Source *) const
|
||||
{
|
||||
return new Resize(speed_.x, speed_.y, 0.f);
|
||||
}
|
||||
|
||||
void Resize::accept(Visitor& v)
|
||||
{
|
||||
SourceCallback::accept(v);
|
||||
@@ -593,37 +640,36 @@ void Resize::accept(Visitor& v)
|
||||
}
|
||||
|
||||
Turn::Turn(float speed, float ms) : SourceCallback(),
|
||||
speed_(speed), duration_(ms), progress_(0.f)
|
||||
speed_(speed), duration_(ms)
|
||||
{
|
||||
}
|
||||
|
||||
void Turn::update(Source *s, float dt)
|
||||
{
|
||||
if (s && !s->locked()) {
|
||||
// reset on first run or upon call of reset()
|
||||
if (!initialized_){
|
||||
// start animation
|
||||
progress_ = 0.f;
|
||||
SourceCallback::update(s, dt);
|
||||
|
||||
if (s->locked())
|
||||
status_ = FINISHED;
|
||||
|
||||
// set start on first time it is ready
|
||||
if ( status_ == READY ){
|
||||
// initial position
|
||||
start_ = s->group(View::GEOMETRY)->rotation_.z;
|
||||
initialized_ = true;
|
||||
angle_ = s->group(View::GEOMETRY)->rotation_.z;
|
||||
status_ = ACTIVE;
|
||||
}
|
||||
|
||||
// calculate amplitude of movement
|
||||
progress_ += dt;
|
||||
if ( status_ == ACTIVE ) {
|
||||
|
||||
// perform movement
|
||||
s->group(View::GEOMETRY)->rotation_.z = start_ - speed_ * ( dt * 0.001f );
|
||||
angle_ -= speed_ * ( dt * 0.001f );
|
||||
s->group(View::GEOMETRY)->rotation_.z = angle_;
|
||||
|
||||
// timeout
|
||||
if ( progress_ > duration_ ) {
|
||||
if ( (elapsed_ - delay_) > duration_ )
|
||||
// done
|
||||
finished_ = true;
|
||||
status_ = FINISHED;
|
||||
}
|
||||
}
|
||||
else
|
||||
finished_ = true;
|
||||
}
|
||||
|
||||
void Turn::multiply (float factor)
|
||||
{
|
||||
@@ -635,6 +681,11 @@ SourceCallback *Turn::clone() const
|
||||
return new Turn(speed_, duration_);
|
||||
}
|
||||
|
||||
SourceCallback *Turn::reverse(Source *) const
|
||||
{
|
||||
return new Turn(speed_, 0.f);
|
||||
}
|
||||
|
||||
void Turn::accept(Visitor& v)
|
||||
{
|
||||
SourceCallback::accept(v);
|
||||
|
||||
@@ -33,25 +33,34 @@ public:
|
||||
SourceCallback();
|
||||
virtual ~SourceCallback() {}
|
||||
|
||||
virtual void update (Source *, float) = 0;
|
||||
virtual void update (Source *, float);
|
||||
virtual void multiply (float) {};
|
||||
virtual SourceCallback *clone () const = 0;
|
||||
virtual SourceCallback *reverse (Source *) const { return nullptr; }
|
||||
virtual CallbackType type () const { return CALLBACK_GENERIC; }
|
||||
virtual void accept (Visitor& v);
|
||||
|
||||
inline bool finished () const { return finished_; }
|
||||
inline void reset () { initialized_ = false; }
|
||||
inline bool finished () const { return status_ > ACTIVE; }
|
||||
inline void reset () { status_ = PENDING; }
|
||||
inline void delay (float milisec) { delay_ = milisec;}
|
||||
|
||||
protected:
|
||||
bool finished_;
|
||||
bool initialized_;
|
||||
|
||||
typedef enum {
|
||||
PENDING = 0,
|
||||
READY,
|
||||
ACTIVE,
|
||||
FINISHED
|
||||
} state;
|
||||
|
||||
state status_;
|
||||
float delay_;
|
||||
float elapsed_;
|
||||
};
|
||||
|
||||
class SetAlpha : public SourceCallback
|
||||
{
|
||||
float duration_;
|
||||
float progress_;
|
||||
float alpha_;
|
||||
glm::vec2 start_;
|
||||
glm::vec2 target_;
|
||||
@@ -81,10 +90,9 @@ class Loom : public SourceCallback
|
||||
glm::vec2 pos_;
|
||||
glm::vec2 step_;
|
||||
float duration_;
|
||||
float progress_;
|
||||
|
||||
public:
|
||||
Loom (float speed = 0.f, float ms = 0.f);
|
||||
Loom (float speed = 0.f, float ms = FLT_MAX);
|
||||
|
||||
float value () const { return speed_; }
|
||||
void setValue (float d) { speed_ = d; }
|
||||
@@ -94,6 +102,7 @@ public:
|
||||
void update (Source *s, float) override;
|
||||
void multiply (float factor) override;
|
||||
SourceCallback *clone() const override;
|
||||
SourceCallback *reverse(Source *) const override;
|
||||
CallbackType type () const override { return CALLBACK_LOOM; }
|
||||
void accept (Visitor& v) override;
|
||||
};
|
||||
@@ -116,7 +125,6 @@ public:
|
||||
class SetDepth : public SourceCallback
|
||||
{
|
||||
float duration_;
|
||||
float progress_;
|
||||
float start_;
|
||||
float target_;
|
||||
bool bidirectional_;
|
||||
@@ -152,7 +160,7 @@ public:
|
||||
bool bidirectional () const { return bidirectional_;}
|
||||
void setBidirectional (bool on) { bidirectional_ = on; }
|
||||
|
||||
void update (Source *s, float) override;
|
||||
void update (Source *s, float dt) override;
|
||||
SourceCallback *clone() const override;
|
||||
SourceCallback *reverse(Source *s) const override;
|
||||
CallbackType type () const override { return CALLBACK_PLAY; }
|
||||
@@ -164,7 +172,7 @@ class RePlay : public SourceCallback
|
||||
public:
|
||||
RePlay();
|
||||
|
||||
void update(Source *s, float) override;
|
||||
void update(Source *s, float dt) override;
|
||||
SourceCallback *clone() const override;
|
||||
CallbackType type () const override { return CALLBACK_REPLAY; }
|
||||
};
|
||||
@@ -173,7 +181,7 @@ class ResetGeometry : public SourceCallback
|
||||
{
|
||||
public:
|
||||
ResetGeometry () : SourceCallback() {}
|
||||
void update (Source *s, float) override;
|
||||
void update (Source *s, float dt) override;
|
||||
SourceCallback *clone () const override;
|
||||
CallbackType type () const override { return CALLBACK_RESETGEO; }
|
||||
};
|
||||
@@ -181,7 +189,6 @@ public:
|
||||
class SetGeometry : public SourceCallback
|
||||
{
|
||||
float duration_;
|
||||
float progress_;
|
||||
Group start_;
|
||||
Group target_;
|
||||
bool bidirectional_;
|
||||
@@ -207,12 +214,11 @@ public:
|
||||
class Grab : public SourceCallback
|
||||
{
|
||||
glm::vec2 speed_;
|
||||
glm::vec2 start_;
|
||||
glm::vec2 pos_;
|
||||
float duration_;
|
||||
float progress_;
|
||||
|
||||
public:
|
||||
Grab(float dx = 0.f, float dy = 0.f, float ms = 0.f);
|
||||
Grab(float dx = 0.f, float dy = 0.f, float ms = FLT_MAX);
|
||||
|
||||
glm::vec2 value () const { return speed_; }
|
||||
void setValue (glm::vec2 d) { speed_ = d; }
|
||||
@@ -222,6 +228,7 @@ public:
|
||||
void update (Source *s, float) override;
|
||||
void multiply (float factor) override;
|
||||
SourceCallback *clone () const override;
|
||||
SourceCallback *reverse(Source *) const override;
|
||||
CallbackType type () const override { return CALLBACK_GRAB; }
|
||||
void accept (Visitor& v) override;
|
||||
};
|
||||
@@ -229,12 +236,10 @@ public:
|
||||
class Resize : public SourceCallback
|
||||
{
|
||||
glm::vec2 speed_;
|
||||
glm::vec2 start_;
|
||||
float duration_;
|
||||
float progress_;
|
||||
|
||||
public:
|
||||
Resize(float dx = 0.f, float dy = 0.f, float ms = 0.f);
|
||||
Resize(float dx = 0.f, float dy = 0.f, float ms = FLT_MAX);
|
||||
|
||||
glm::vec2 value () const { return speed_; }
|
||||
void setValue (glm::vec2 d) { speed_ = d; }
|
||||
@@ -244,6 +249,7 @@ public:
|
||||
void update (Source *s, float) override;
|
||||
void multiply (float factor) override;
|
||||
SourceCallback *clone () const override;
|
||||
SourceCallback *reverse(Source *) const override;
|
||||
CallbackType type () const override { return CALLBACK_RESIZE; }
|
||||
void accept (Visitor& v) override;
|
||||
};
|
||||
@@ -251,12 +257,11 @@ public:
|
||||
class Turn : public SourceCallback
|
||||
{
|
||||
float speed_;
|
||||
float start_;
|
||||
float angle_;
|
||||
float duration_;
|
||||
float progress_;
|
||||
|
||||
public:
|
||||
Turn(float speed = 0.f, float ms = 0.f);
|
||||
Turn(float speed = 0.f, float ms = FLT_MAX);
|
||||
|
||||
float value () const { return speed_; }
|
||||
void setValue (float d) { speed_ = d; }
|
||||
@@ -266,6 +271,7 @@ public:
|
||||
void update (Source *s, float) override;
|
||||
void multiply (float factor) override;
|
||||
SourceCallback *clone () const override;
|
||||
SourceCallback *reverse(Source *) const override;
|
||||
CallbackType type () const override { return CALLBACK_TURN; }
|
||||
void accept (Visitor& v) override;
|
||||
};
|
||||
|
||||
@@ -151,7 +151,10 @@ SourceList join (const SourceList &first, const SourceList &second)
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
SourceLink::SourceLink(uint64_t id, Session *se): host_(nullptr), target_(nullptr), id_(0)
|
||||
{
|
||||
connect(id, se);
|
||||
}
|
||||
|
||||
SourceLink::SourceLink(Source *s): host_(nullptr), target_(nullptr), id_(0)
|
||||
{
|
||||
|
||||
@@ -34,6 +34,7 @@ class SourceLink {
|
||||
public:
|
||||
SourceLink(): host_(nullptr), target_(nullptr), id_(0) { }
|
||||
SourceLink(const SourceLink &);
|
||||
SourceLink(uint64_t id, Session *se);
|
||||
SourceLink(Source *s);
|
||||
~SourceLink();
|
||||
|
||||
|
||||
@@ -4587,26 +4587,6 @@ void InputMappingInterface::SliderParametersCallback(SourceCallback *callback, S
|
||||
}
|
||||
}
|
||||
|
||||
void InputMappingInterface::readInputSource()
|
||||
{
|
||||
// clear
|
||||
input_sources_callbacks.clear();
|
||||
memset(input_assigned, 0, sizeof(input_assigned));
|
||||
|
||||
// loop over sources of the session
|
||||
Session *ses = Mixer::manager().session();
|
||||
for (auto sit = ses->begin(); sit != ses->end(); ++sit) {
|
||||
// loop over registered keys
|
||||
std::list<uint> inputs = (*sit)->callbackInputs();
|
||||
for (auto k = inputs.begin(); k != inputs.end(); ++k) {
|
||||
// add entry in input map
|
||||
std::list<SourceCallback *> callbacks = (*sit)->inputCallbacks(*k);
|
||||
for (auto c = callbacks.begin(); c != callbacks.end(); ++c )
|
||||
input_sources_callbacks.emplace( *k, std::pair<Source *, SourceCallback*>(*sit, *c) );
|
||||
input_assigned[*k] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InputMappingInterface::Render()
|
||||
{
|
||||
@@ -4630,8 +4610,8 @@ void InputMappingInterface::Render()
|
||||
return;
|
||||
}
|
||||
|
||||
// Update internal data structures
|
||||
readInputSource();
|
||||
// short variable to refer to session
|
||||
Session *S = Mixer::manager().session();
|
||||
|
||||
// menu (no title bar)
|
||||
if (ImGui::BeginMenuBar())
|
||||
@@ -4645,11 +4625,8 @@ void InputMappingInterface::Render()
|
||||
ImGui::MenuItem( ICON_FA_BAN " Disable", nullptr, &Settings::application.mapping.disabled);
|
||||
|
||||
// Clear all
|
||||
if ( ImGui::MenuItem( ICON_FA_BACKSPACE " Clear all" ) ){
|
||||
Session *ses = Mixer::manager().session();
|
||||
for (auto sit = ses->begin(); sit != ses->end(); ++sit)
|
||||
(*sit)->clearInputCallbacks();
|
||||
}
|
||||
if ( ImGui::MenuItem( ICON_FA_BACKSPACE " Clear all" ) )
|
||||
S->clearSourceCallbacks();
|
||||
|
||||
// output manager menu
|
||||
ImGui::Separator();
|
||||
@@ -4684,29 +4661,24 @@ void InputMappingInterface::Render()
|
||||
const std::string keymenu = ICON_FA_HAND_POINT_RIGHT " Input " + Control::manager().inputLabel(current_input_);
|
||||
if (ImGui::BeginMenu(keymenu.c_str()) )
|
||||
{
|
||||
if ( ImGui::MenuItem( ICON_FA_WINDOW_CLOSE " Reset mapping", NULL, false, input_assigned[current_input_] ) ){
|
||||
if ( ImGui::MenuItem( ICON_FA_WINDOW_CLOSE " Reset mapping", NULL, false, S->inputAssigned(current_input_) ) )
|
||||
// remove all source callback of this input
|
||||
auto current_source_callback = input_sources_callbacks.equal_range(current_input_);
|
||||
for (auto kit = current_source_callback.first; kit != current_source_callback.second; ++kit)
|
||||
kit->second.first->removeInputCallback(kit->second.second);
|
||||
// internal data structure changed
|
||||
readInputSource();
|
||||
}
|
||||
S->deleteSourceCallbacks(current_input_);
|
||||
|
||||
if (ImGui::BeginMenu(ICON_FA_CLOCK " Metronome", input_assigned[current_input_]))
|
||||
if (ImGui::BeginMenu(ICON_FA_CLOCK " Metronome", S->inputAssigned(current_input_)))
|
||||
{
|
||||
Metronome::Synchronicity sync = Metronome::SYNC_NONE;
|
||||
Metronome::Synchronicity sync = S->inputSynchrony(current_input_);
|
||||
bool active = sync == Metronome::SYNC_NONE;
|
||||
if (ImGuiToolkit::MenuItemIcon(5, 13, " Not synchronized", active )){
|
||||
|
||||
S->setInputSynchrony(current_input_, Metronome::SYNC_NONE);
|
||||
}
|
||||
active = sync == Metronome::SYNC_BEAT;
|
||||
if (ImGuiToolkit::MenuItemIcon(6, 13, " Sync to beat", active )){
|
||||
|
||||
S->setInputSynchrony(current_input_, Metronome::SYNC_BEAT);
|
||||
}
|
||||
active = sync == Metronome::SYNC_PHASE;
|
||||
if (ImGuiToolkit::MenuItemIcon(7, 13, " Sync to phase", active )){
|
||||
|
||||
S->setInputSynchrony(current_input_, Metronome::SYNC_PHASE);
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
@@ -4716,17 +4688,13 @@ void InputMappingInterface::Render()
|
||||
// static var for the copy-paste mechanism
|
||||
static uint _copy_current_input = INPUT_UNDEFINED;
|
||||
// 2) Copy (if there are callbacks assigned)
|
||||
if (ImGui::MenuItem("Copy", NULL, false, input_assigned[current_input_] ))
|
||||
if (ImGui::MenuItem("Copy", NULL, false, S->inputAssigned(current_input_) ))
|
||||
// Remember the index of the input to copy
|
||||
_copy_current_input = current_input_;
|
||||
// 3) Paste (if copied input index is assigned)
|
||||
if (ImGui::MenuItem("Paste", NULL, false, input_assigned[_copy_current_input] )) {
|
||||
// create source callbacks at current input cloning those of the copied index
|
||||
auto copy_source_callback = input_sources_callbacks.equal_range(_copy_current_input);
|
||||
for (auto kit = copy_source_callback.first; kit != copy_source_callback.second; ++kit)
|
||||
kit->second.first->addInputCallback(current_input_, kit->second.second->clone());
|
||||
// internal data structure changed
|
||||
readInputSource();
|
||||
if (ImGui::MenuItem("Paste", NULL, false, S->inputAssigned(current_input_) )) {
|
||||
// copy source callbacks from rememberd index to current input index
|
||||
S->copySourceCallback(_copy_current_input, current_input_);
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
@@ -4768,13 +4736,14 @@ void InputMappingInterface::Render()
|
||||
}
|
||||
// draw key button
|
||||
ImGui::PushID(ik);
|
||||
if (ImGui::Selectable(Control::manager().inputLabel(ik).c_str(), input_assigned[ik], 0, keyLetterIconSize)) {
|
||||
if (ImGui::Selectable(Control::manager().inputLabel(ik).c_str(), S->inputAssigned(ik), 0, keyLetterIconSize)) {
|
||||
current_input_ = ik;
|
||||
// TODO SET VAR current input assigned??
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
||||
// if user clics and drags an assigned key icon...
|
||||
if (input_assigned[ik] && ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
|
||||
if (S->inputAssigned(ik) && ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
|
||||
ImGui::SetDragDropPayload("DND_KEYBOARD", &ik, sizeof(uint));
|
||||
ImGui::Text( ICON_FA_CUBE " %s ", Control::manager().inputLabel(ik).c_str());
|
||||
ImGui::EndDragDropSource();
|
||||
@@ -4785,10 +4754,8 @@ void InputMappingInterface::Render()
|
||||
if ( payload->DataSize == sizeof(uint) ) {
|
||||
// drop means change key of input callbacks
|
||||
uint previous_input_key = *(const int*)payload->Data;
|
||||
// index of current source changed;
|
||||
auto result = input_sources_callbacks.equal_range(previous_input_key);
|
||||
for (auto kit = result.first; kit != result.second; ++kit)
|
||||
kit->second.first->swapInputCallback(previous_input_key, ik);
|
||||
// swap
|
||||
S->swapSourceCallback(previous_input_key, ik);
|
||||
// switch to this key
|
||||
current_input_ = ik;
|
||||
}
|
||||
@@ -4848,12 +4815,12 @@ void InputMappingInterface::Render()
|
||||
}
|
||||
// draw key button
|
||||
ImGui::PushID(ik);
|
||||
if (ImGui::Selectable(Control::manager().inputLabel(ik).c_str(), input_assigned[ik], 0, iconsize)) {
|
||||
if (ImGui::Selectable(Control::manager().inputLabel(ik).c_str(), S->inputAssigned(ik), 0, iconsize)) {
|
||||
current_input_ = ik;
|
||||
}
|
||||
ImGui::PopID();
|
||||
// if user clics and drags an assigned key icon...
|
||||
if (input_assigned[ik] && ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
|
||||
if (S->inputAssigned(ik) && ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
|
||||
ImGui::SetDragDropPayload("DND_NUMPAD", &ik, sizeof(uint));
|
||||
ImGui::Text( ICON_FA_CUBE " %s ", Control::manager().inputLabel(ik).c_str());
|
||||
ImGui::EndDragDropSource();
|
||||
@@ -4864,10 +4831,8 @@ void InputMappingInterface::Render()
|
||||
if ( payload->DataSize == sizeof(uint) ) {
|
||||
// drop means change key of input callbacks
|
||||
uint previous_input_key = *(const int*)payload->Data;
|
||||
// index of current source changed;
|
||||
auto result = input_sources_callbacks.equal_range(previous_input_key);
|
||||
for (auto kit = result.first; kit != result.second; ++kit)
|
||||
kit->second.first->swapInputCallback(previous_input_key, ik);
|
||||
// swap
|
||||
S->swapSourceCallback(previous_input_key, ik);
|
||||
// switch to this key
|
||||
current_input_ = ik;
|
||||
}
|
||||
@@ -4924,10 +4889,12 @@ void InputMappingInterface::Render()
|
||||
|
||||
// draw key button
|
||||
ImGui::PushID(it);
|
||||
if (ImGui::Selectable(" ", input_assigned[it], 0, keyNumpadIconSize))
|
||||
if (ImGui::Selectable(" ", S->inputAssigned(it), 0, keyNumpadIconSize))
|
||||
current_input_ = it;
|
||||
ImGui::PopID();
|
||||
|
||||
// TODO DragN DROP
|
||||
|
||||
// 4 elements in a row
|
||||
if ((t % 4) < 3) ImGui::SameLine();
|
||||
|
||||
@@ -4997,12 +4964,12 @@ void InputMappingInterface::Render()
|
||||
}
|
||||
// draw key button
|
||||
ImGui::PushID(ig);
|
||||
if (ImGui::Selectable(gamepad_labels[b].c_str(), input_assigned[ig], 0, keyLetterIconSize))
|
||||
if (ImGui::Selectable(gamepad_labels[b].c_str(), S->inputAssigned(ig), 0, keyLetterIconSize))
|
||||
current_input_ = ig;
|
||||
ImGui::PopID();
|
||||
|
||||
// if user clics and drags an assigned key icon...
|
||||
if (input_assigned[ig] && ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
|
||||
if (S->inputAssigned(ig) && ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
|
||||
ImGui::SetDragDropPayload("DND_GAMEPAD", &ig, sizeof(uint));
|
||||
ImGui::Text( ICON_FA_CUBE " %s ", Control::manager().inputLabel(ig).c_str());
|
||||
ImGui::EndDragDropSource();
|
||||
@@ -5013,10 +4980,8 @@ void InputMappingInterface::Render()
|
||||
if ( payload->DataSize == sizeof(uint) ) {
|
||||
// drop means change key of input callbacks
|
||||
uint previous_input_key = *(const int*)payload->Data;
|
||||
// index of current source changed;
|
||||
auto result = input_sources_callbacks.equal_range(previous_input_key);
|
||||
for (auto kit = result.first; kit != result.second; ++kit)
|
||||
kit->second.first->swapInputCallback(previous_input_key, ig);
|
||||
// swap
|
||||
S->swapSourceCallback(previous_input_key, ig);
|
||||
// switch to this key
|
||||
current_input_ = ig;
|
||||
}
|
||||
@@ -5054,7 +5019,7 @@ void InputMappingInterface::Render()
|
||||
ImGuiToolkit::ValueBar(Control::manager().inputValue(INPUT_JOYSTICK_FIRST_AXIS), axis_bar_size);
|
||||
// Draw button to assign the axis to an action
|
||||
ImGui::SetCursorScreenPos( pos );
|
||||
if (ImGui::Selectable("LX", input_assigned[INPUT_JOYSTICK_FIRST_AXIS], 0, axis_icon_size))
|
||||
if (ImGui::Selectable("LX", S->inputAssigned(INPUT_JOYSTICK_FIRST_AXIS), 0, axis_icon_size))
|
||||
current_input_ = INPUT_JOYSTICK_FIRST_AXIS;
|
||||
// Draw frame around current gamepad axis
|
||||
if (current_input_ == INPUT_JOYSTICK_FIRST_AXIS)
|
||||
@@ -5064,7 +5029,7 @@ void InputMappingInterface::Render()
|
||||
ImGui::SetCursorScreenPos( pos + axis_bar_pos);
|
||||
ImGuiToolkit::ValueBar(Control::manager().inputValue(INPUT_JOYSTICK_FIRST_AXIS+1), axis_bar_size);
|
||||
ImGui::SetCursorScreenPos( pos );
|
||||
if (ImGui::Selectable("LY", input_assigned[INPUT_JOYSTICK_FIRST_AXIS+1], 0, axis_icon_size))
|
||||
if (ImGui::Selectable("LY", S->inputAssigned(INPUT_JOYSTICK_FIRST_AXIS+1), 0, axis_icon_size))
|
||||
current_input_ = INPUT_JOYSTICK_FIRST_AXIS+1;
|
||||
if (current_input_ == INPUT_JOYSTICK_FIRST_AXIS+1)
|
||||
draw_list->AddRect(pos, pos + axis_icon_size, ImGui::GetColorU32(ImGuiCol_Text), 6.f, ImDrawCornerFlags_All, 3.f);
|
||||
@@ -5073,7 +5038,7 @@ void InputMappingInterface::Render()
|
||||
ImGui::SetCursorScreenPos( pos + axis_bar_pos);
|
||||
ImGuiToolkit::ValueBar(Control::manager().inputValue(INPUT_JOYSTICK_FIRST_AXIS+2), axis_bar_size);
|
||||
ImGui::SetCursorScreenPos( pos );
|
||||
if (ImGui::Selectable("L2", input_assigned[INPUT_JOYSTICK_FIRST_AXIS+2], 0, axis_icon_size))
|
||||
if (ImGui::Selectable("L2", S->inputAssigned(INPUT_JOYSTICK_FIRST_AXIS+2), 0, axis_icon_size))
|
||||
current_input_ = INPUT_JOYSTICK_FIRST_AXIS+2;
|
||||
if (current_input_ == INPUT_JOYSTICK_FIRST_AXIS+2)
|
||||
draw_list->AddRect(pos, pos + axis_icon_size, ImGui::GetColorU32(ImGuiCol_Text), 6.f, ImDrawCornerFlags_All, 3.f);
|
||||
@@ -5088,7 +5053,7 @@ void InputMappingInterface::Render()
|
||||
ImGui::SetCursorScreenPos( pos + axis_bar_pos);
|
||||
ImGuiToolkit::ValueBar(Control::manager().inputValue(INPUT_JOYSTICK_FIRST_AXIS+3), axis_bar_size);
|
||||
ImGui::SetCursorScreenPos( pos );
|
||||
if (ImGui::Selectable("RX", input_assigned[INPUT_JOYSTICK_FIRST_AXIS+3], 0, axis_icon_size))
|
||||
if (ImGui::Selectable("RX", S->inputAssigned(INPUT_JOYSTICK_FIRST_AXIS+3), 0, axis_icon_size))
|
||||
current_input_ = INPUT_JOYSTICK_FIRST_AXIS+3;
|
||||
if (current_input_ == INPUT_JOYSTICK_FIRST_AXIS+3)
|
||||
draw_list->AddRect(pos, pos + axis_icon_size, ImGui::GetColorU32(ImGuiCol_Text), 6.f, ImDrawCornerFlags_All, 3.f);
|
||||
@@ -5097,7 +5062,7 @@ void InputMappingInterface::Render()
|
||||
ImGui::SetCursorScreenPos( pos + axis_bar_pos);
|
||||
ImGuiToolkit::ValueBar(Control::manager().inputValue(INPUT_JOYSTICK_FIRST_AXIS+4), axis_bar_size);
|
||||
ImGui::SetCursorScreenPos( pos );
|
||||
if (ImGui::Selectable("RY", input_assigned[INPUT_JOYSTICK_FIRST_AXIS+4], 0, axis_icon_size))
|
||||
if (ImGui::Selectable("RY", S->inputAssigned(INPUT_JOYSTICK_FIRST_AXIS+4), 0, axis_icon_size))
|
||||
current_input_ = INPUT_JOYSTICK_FIRST_AXIS+4;
|
||||
if (current_input_ == INPUT_JOYSTICK_FIRST_AXIS+4)
|
||||
draw_list->AddRect(pos, pos + axis_icon_size, ImGui::GetColorU32(ImGuiCol_Text), 6.f, ImDrawCornerFlags_All, 3.f);
|
||||
@@ -5106,7 +5071,7 @@ void InputMappingInterface::Render()
|
||||
ImGui::SetCursorScreenPos( pos + axis_bar_pos);
|
||||
ImGuiToolkit::ValueBar(Control::manager().inputValue(INPUT_JOYSTICK_FIRST_AXIS+5), axis_bar_size);
|
||||
ImGui::SetCursorScreenPos( pos );
|
||||
if (ImGui::Selectable("R2", input_assigned[INPUT_JOYSTICK_FIRST_AXIS+5], 0, axis_icon_size))
|
||||
if (ImGui::Selectable("R2", S->inputAssigned(INPUT_JOYSTICK_FIRST_AXIS+5), 0, axis_icon_size))
|
||||
current_input_ = INPUT_JOYSTICK_FIRST_AXIS+5;
|
||||
if (current_input_ == INPUT_JOYSTICK_FIRST_AXIS+5)
|
||||
draw_list->AddRect(pos, pos + axis_icon_size, ImGui::GetColorU32(ImGuiCol_Text), 6.f, ImDrawCornerFlags_All, 3.f);
|
||||
@@ -5126,20 +5091,20 @@ void InputMappingInterface::Render()
|
||||
|
||||
float w = ImGui::GetWindowWidth() *0.25f;
|
||||
|
||||
if (input_assigned[current_input_]) {
|
||||
if (S->inputAssigned(current_input_)) {
|
||||
|
||||
auto result = input_sources_callbacks.equal_range(current_input_);
|
||||
for (auto kit = result.first; kit != result.second; ++kit) {
|
||||
auto result = S->getSourceCallbacks(current_input_);
|
||||
for (auto kit = result.cbegin(); kit != result.cend(); ++kit) {
|
||||
|
||||
Source *source = kit->second.first;
|
||||
SourceCallback *callback = kit->second.second;
|
||||
Source *source = kit->first;
|
||||
SourceCallback *callback = kit->second;
|
||||
|
||||
// push ID because we repeat the same UI
|
||||
ImGui::PushID( (void*) callback);
|
||||
|
||||
// Delete interface
|
||||
if (ImGuiToolkit::IconButton(ICON_FA_MINUS, "Remove") ){
|
||||
source->removeInputCallback(callback);
|
||||
S->deleteSourceCallback(callback);
|
||||
// reload
|
||||
ImGui::PopID();
|
||||
break;
|
||||
@@ -5148,12 +5113,10 @@ void InputMappingInterface::Render()
|
||||
// Select Source
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
ImGui::SetNextItemWidth(w);
|
||||
Source *select = ComboSelectSource(source);
|
||||
if (select != nullptr) {
|
||||
// copy callback to other source
|
||||
select->addInputCallback(current_input_, callback->clone());
|
||||
// remove previous callback
|
||||
source->removeInputCallback(callback);
|
||||
Source *selected_source = ComboSelectSource(source);
|
||||
if (selected_source != nullptr) {
|
||||
// reassign the callback to newly selected source
|
||||
S->assignSourceCallback(current_input_, selected_source, callback);
|
||||
// reload
|
||||
ImGui::PopID();
|
||||
break;
|
||||
@@ -5165,9 +5128,9 @@ void InputMappingInterface::Render()
|
||||
uint type = ComboSelectCallback( callback->type() );
|
||||
if (type > 0) {
|
||||
// remove previous callback
|
||||
source->removeInputCallback(callback);
|
||||
// add callback
|
||||
source->addInputCallback(current_input_, SourceCallback::create((SourceCallback::CallbackType)type) );
|
||||
S->deleteSourceCallback(callback);
|
||||
// assign callback
|
||||
S->assignSourceCallback(current_input_, source, SourceCallback::create((SourceCallback::CallbackType)type) );
|
||||
// reload
|
||||
ImGui::PopID();
|
||||
break;
|
||||
@@ -5222,7 +5185,7 @@ void InputMappingInterface::Render()
|
||||
// user selected a callback type
|
||||
if (temp_new_callback > 0) {
|
||||
// step 4 : create new callback and add it to source
|
||||
temp_new_source->addInputCallback(current_input_, SourceCallback::create((SourceCallback::CallbackType)temp_new_callback) );
|
||||
S->assignSourceCallback(current_input_, temp_new_source, SourceCallback::create((SourceCallback::CallbackType)temp_new_callback) );
|
||||
// done
|
||||
temp_new_source = nullptr;
|
||||
temp_new_callback = 0;
|
||||
|
||||
@@ -368,13 +368,8 @@ class InputMappingInterface : public WorkspaceWindow
|
||||
{
|
||||
std::array< std::string, 4 > input_mode;
|
||||
std::array< uint, 4 > current_input_for_mode;
|
||||
|
||||
// data structures more adapted for display
|
||||
std::multimap< uint, std::pair<Source *, SourceCallback*> > input_sources_callbacks;
|
||||
bool input_assigned[100]{};
|
||||
uint current_input_;
|
||||
|
||||
void readInputSource();
|
||||
Source *ComboSelectSource(Source *current = nullptr);
|
||||
uint ComboSelectCallback(uint current);
|
||||
void SliderParametersCallback(SourceCallback *callback, Source *source);
|
||||
|
||||
Reference in New Issue
Block a user