mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-11 18:34:58 +01:00
New Geometry source callback
Set Geometry callback applies and interpolates position, scale and rotation of a source. Implemented UI and XML.
This commit is contained in:
@@ -63,8 +63,19 @@ InfoVisitor::InfoVisitor() : brief_(true), current_id_(0)
|
||||
{
|
||||
}
|
||||
|
||||
void InfoVisitor::visit(Node &)
|
||||
void InfoVisitor::visit(Node &n)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << std::fixed << std::setprecision(1);
|
||||
oss << "Pos ( " << n.translation_.x << ", " << n.translation_.y << " )" << std::endl;
|
||||
oss << "Scale ( " << n.scale_.x << ", " << n.scale_.y << " )" << std::endl;
|
||||
oss << "Angle " << std::setprecision(2) << n.rotation_.z * 180.f / M_PI << "\u00B0" << std::endl;
|
||||
|
||||
if (!brief_) {
|
||||
oss << n.crop_.x << ", " << n.crop_.y << " Crop" << std::endl;
|
||||
}
|
||||
|
||||
information_ = oss.str();
|
||||
}
|
||||
|
||||
void InfoVisitor::visit(Group &)
|
||||
|
||||
@@ -1192,6 +1192,28 @@ void SessionLoader::visit (SetDepth &c)
|
||||
c.setBidirectional(b);
|
||||
}
|
||||
|
||||
void SessionLoader::visit (SetGeometry &c)
|
||||
{
|
||||
float d = 0.f;
|
||||
xmlCurrent_->QueryFloatAttribute("duration", &d);
|
||||
c.setDuration(d);
|
||||
|
||||
bool b = false;
|
||||
xmlCurrent_->QueryBoolAttribute("bidirectional", &b);
|
||||
c.setBidirectional(b);
|
||||
|
||||
XMLElement* current = xmlCurrent_;
|
||||
|
||||
xmlCurrent_ = xmlCurrent_->FirstChildElement("Geometry");
|
||||
if (xmlCurrent_) {
|
||||
Group tmp;
|
||||
tmp.accept(*this);
|
||||
c.setTarget(&tmp);
|
||||
}
|
||||
|
||||
xmlCurrent_ = current;
|
||||
}
|
||||
|
||||
void SessionLoader::visit (Loom &c)
|
||||
{
|
||||
float d = 0.f;
|
||||
|
||||
@@ -67,6 +67,7 @@ public:
|
||||
void visit (SourceCallback&) override;
|
||||
void visit (SetAlpha&) override;
|
||||
void visit (SetDepth&) override;
|
||||
void visit (SetGeometry&) override;
|
||||
void visit (Loom&) override;
|
||||
void visit (Grab&) override;
|
||||
void visit (Resize&) override;
|
||||
|
||||
@@ -589,9 +589,9 @@ void SessionVisitor::visit (Source& s)
|
||||
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);
|
||||
callbackselement->InsertEndChild(xmlCurrent_);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -784,6 +784,22 @@ void SessionVisitor::visit (SetDepth &c)
|
||||
xmlCurrent_->SetAttribute("bidirectional", c.bidirectional());
|
||||
}
|
||||
|
||||
void SessionVisitor::visit (SetGeometry &c)
|
||||
{
|
||||
xmlCurrent_->SetAttribute("duration", c.duration());
|
||||
xmlCurrent_->SetAttribute("bidirectional", c.bidirectional());
|
||||
|
||||
// get geometry of target
|
||||
Group g;
|
||||
c.getTarget(&g);
|
||||
|
||||
XMLElement *geom = xmlDoc_->NewElement( "Geometry" );
|
||||
xmlCurrent_->InsertEndChild(geom);
|
||||
xmlCurrent_ = geom;
|
||||
g.accept(*this);
|
||||
|
||||
}
|
||||
|
||||
void SessionVisitor::visit (Loom &c)
|
||||
{
|
||||
xmlCurrent_->SetAttribute("delta", c.value());
|
||||
|
||||
@@ -73,6 +73,7 @@ public:
|
||||
void visit (SourceCallback&) override;
|
||||
void visit (SetAlpha&) override;
|
||||
void visit (SetDepth&) override;
|
||||
void visit (SetGeometry&) override;
|
||||
void visit (Loom&) override;
|
||||
void visit (Grab&) override;
|
||||
void visit (Resize&) override;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "defines.h"
|
||||
#include "Source.h"
|
||||
#include "UpdateCallback.h"
|
||||
#include "Visitor.h"
|
||||
#include "Log.h"
|
||||
|
||||
@@ -36,8 +37,8 @@ SourceCallback *SourceCallback::create(CallbackType type)
|
||||
case SourceCallback::CALLBACK_LOOM:
|
||||
loadedcallback = new Loom;
|
||||
break;
|
||||
case SourceCallback::CALLBACK_DEPTH:
|
||||
loadedcallback = new SetDepth;
|
||||
case SourceCallback::CALLBACK_GEOMETRY:
|
||||
loadedcallback = new SetGeometry;
|
||||
break;
|
||||
case SourceCallback::CALLBACK_GRAB:
|
||||
loadedcallback = new Grab;
|
||||
@@ -48,6 +49,9 @@ SourceCallback *SourceCallback::create(CallbackType type)
|
||||
case SourceCallback::CALLBACK_TURN:
|
||||
loadedcallback = new Turn;
|
||||
break;
|
||||
case SourceCallback::CALLBACK_DEPTH:
|
||||
loadedcallback = new SetDepth;
|
||||
break;
|
||||
case SourceCallback::CALLBACK_PLAY:
|
||||
loadedcallback = new Play;
|
||||
break;
|
||||
@@ -188,7 +192,7 @@ void SetAlpha::update(Source *s, float dt)
|
||||
|
||||
// time-out
|
||||
if ( progress_ > duration_ ) {
|
||||
// apply depth to target
|
||||
// apply alpha to target
|
||||
s->group(View::MIXING)->translation_ = glm::vec3(target_, s->group(View::MIXING)->translation_.z);
|
||||
// done
|
||||
finished_ = true;
|
||||
@@ -407,6 +411,87 @@ SourceCallback *RePlay::clone() const
|
||||
return new RePlay;
|
||||
}
|
||||
|
||||
|
||||
SetGeometry::SetGeometry(const Group *g, float ms, bool revert) : SourceCallback(),
|
||||
duration_(ms), progress_(0.f), bidirectional_(revert)
|
||||
{
|
||||
setTarget(g);
|
||||
}
|
||||
|
||||
void SetGeometry::getTarget (Group *g) const
|
||||
{
|
||||
if (g!=nullptr)
|
||||
g->copyTransform(&target_);
|
||||
}
|
||||
|
||||
void SetGeometry::setTarget (const Group *g)
|
||||
{
|
||||
if (g!=nullptr)
|
||||
target_.copyTransform(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_){
|
||||
start_.copyTransform(s->group(View::GEOMETRY));
|
||||
progress_ = 0.f;
|
||||
initialized_ = true;
|
||||
}
|
||||
|
||||
// time passed
|
||||
progress_ += dt;
|
||||
|
||||
// perform movement
|
||||
if ( ABS(duration_) > 0.f){
|
||||
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_;
|
||||
intermediate.rotation_ = (1.f - ratio) * start_.rotation_ + ratio * target_.rotation_;
|
||||
// apply geometry
|
||||
s->group(View::GEOMETRY)->copyTransform(&intermediate);
|
||||
s->touch();
|
||||
}
|
||||
|
||||
// time-out
|
||||
if ( progress_ > duration_ ) {
|
||||
// apply target
|
||||
s->group(View::GEOMETRY)->copyTransform(&target_);
|
||||
s->touch();
|
||||
// done
|
||||
finished_ = true;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
finished_ = true;
|
||||
}
|
||||
|
||||
void SetGeometry::multiply (float factor)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SourceCallback *SetGeometry::clone() const
|
||||
{
|
||||
return new SetGeometry(&target_, duration_, bidirectional_);
|
||||
}
|
||||
|
||||
SourceCallback *SetGeometry::reverse(Source *s) const
|
||||
{
|
||||
return bidirectional_ ? new SetGeometry( s->group(View::GEOMETRY), duration_) : nullptr;
|
||||
}
|
||||
|
||||
void SetGeometry::accept(Visitor& v)
|
||||
{
|
||||
SourceCallback::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Grab::Grab(float dx, float dy, float ms) : SourceCallback(),
|
||||
speed_(glm::vec2(dx, dy)), duration_(ms), progress_(0.f)
|
||||
{
|
||||
@@ -528,7 +613,7 @@ void Turn::update(Source *s, float dt)
|
||||
progress_ += dt;
|
||||
|
||||
// perform movement
|
||||
s->group(View::GEOMETRY)->rotation_.z = start_ + speed_ * ( dt * -0.001f / M_PI);
|
||||
s->group(View::GEOMETRY)->rotation_.z = start_ - speed_ * ( dt * 0.001f );
|
||||
|
||||
// timeout
|
||||
if ( progress_ > duration_ ) {
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "Scene.h"
|
||||
|
||||
class Visitor;
|
||||
class Source;
|
||||
|
||||
@@ -14,14 +16,15 @@ public:
|
||||
CALLBACK_GENERIC = 0,
|
||||
CALLBACK_ALPHA = 1,
|
||||
CALLBACK_LOOM = 2,
|
||||
CALLBACK_GRAB = 3,
|
||||
CALLBACK_RESIZE = 4,
|
||||
CALLBACK_TURN = 5,
|
||||
CALLBACK_DEPTH = 6,
|
||||
CALLBACK_PLAY = 7,
|
||||
CALLBACK_REPLAY = 8,
|
||||
CALLBACK_RESETGEO = 9,
|
||||
CALLBACK_LOCK = 10
|
||||
CALLBACK_GEOMETRY = 3,
|
||||
CALLBACK_GRAB = 4,
|
||||
CALLBACK_RESIZE = 5,
|
||||
CALLBACK_TURN = 6,
|
||||
CALLBACK_DEPTH = 7,
|
||||
CALLBACK_PLAY = 8,
|
||||
CALLBACK_REPLAY = 9,
|
||||
CALLBACK_RESETGEO = 10,
|
||||
CALLBACK_LOCK = 11
|
||||
} CallbackType;
|
||||
|
||||
static SourceCallback *create(CallbackType type);
|
||||
@@ -45,15 +48,6 @@ protected:
|
||||
bool initialized_;
|
||||
};
|
||||
|
||||
class ResetGeometry : public SourceCallback
|
||||
{
|
||||
public:
|
||||
ResetGeometry () : SourceCallback() {}
|
||||
void update (Source *s, float) override;
|
||||
SourceCallback *clone () const override;
|
||||
CallbackType type () const override { return CALLBACK_RESETGEO; }
|
||||
};
|
||||
|
||||
class SetAlpha : public SourceCallback
|
||||
{
|
||||
float duration_;
|
||||
@@ -175,6 +169,41 @@ public:
|
||||
CallbackType type () const override { return CALLBACK_REPLAY; }
|
||||
};
|
||||
|
||||
class ResetGeometry : public SourceCallback
|
||||
{
|
||||
public:
|
||||
ResetGeometry () : SourceCallback() {}
|
||||
void update (Source *s, float) override;
|
||||
SourceCallback *clone () const override;
|
||||
CallbackType type () const override { return CALLBACK_RESETGEO; }
|
||||
};
|
||||
|
||||
class SetGeometry : public SourceCallback
|
||||
{
|
||||
float duration_;
|
||||
float progress_;
|
||||
Group start_;
|
||||
Group target_;
|
||||
bool bidirectional_;
|
||||
|
||||
public:
|
||||
SetGeometry (const Group *g = nullptr, float ms = 0.f, bool revert = false);
|
||||
|
||||
void getTarget (Group *g) const;
|
||||
void setTarget (const Group *g);
|
||||
float duration () const { return duration_;}
|
||||
void setDuration (float ms) { duration_ = ms; }
|
||||
bool bidirectional () const { return bidirectional_;}
|
||||
void setBidirectional (bool on) { bidirectional_ = on; }
|
||||
|
||||
void update (Source *s, float dt) override;
|
||||
void multiply (float factor) override;
|
||||
SourceCallback *clone () const override;
|
||||
SourceCallback *reverse(Source *s) const override;
|
||||
CallbackType type () const override { return CALLBACK_GEOMETRY; }
|
||||
void accept (Visitor& v) override;
|
||||
};
|
||||
|
||||
class Grab : public SourceCallback
|
||||
{
|
||||
glm::vec2 speed_;
|
||||
|
||||
@@ -2905,7 +2905,7 @@ void SourceController::RenderSelectedSources()
|
||||
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_ITALIC);
|
||||
center.x -= ImGui::GetTextLineHeight() * 2.f;
|
||||
ImGui::SetCursorScreenPos(top + center);
|
||||
ImGui::Text("Nothing to play");
|
||||
ImGui::Text("Nothing selected");
|
||||
ImGui::PopFont();
|
||||
ImGui::PopStyleColor(1);
|
||||
|
||||
@@ -4352,17 +4352,17 @@ uint InputMappingInterface::ComboSelectCallback(uint current)
|
||||
const char* callback_names[9] = { "Select",
|
||||
ICON_FA_BULLSEYE " Alpha",
|
||||
ICON_FA_BULLSEYE " Loom",
|
||||
ICON_FA_OBJECT_UNGROUP " Geometry",
|
||||
ICON_FA_OBJECT_UNGROUP " Grab",
|
||||
ICON_FA_OBJECT_UNGROUP " Resize",
|
||||
ICON_FA_OBJECT_UNGROUP " Turn",
|
||||
ICON_FA_LAYER_GROUP " Depth",
|
||||
ICON_FA_PLAY_CIRCLE " Play",
|
||||
ICON_FA_PLAY_CIRCLE " Replay"
|
||||
ICON_FA_PLAY_CIRCLE " Play"
|
||||
};
|
||||
|
||||
int selected = 0;
|
||||
if (ImGui::BeginCombo("##ComboSelectCallback", callback_names[current]) ) {
|
||||
for (uint i = SourceCallback::CALLBACK_ALPHA; i < SourceCallback::CALLBACK_REPLAY; ++i){
|
||||
for (uint i = SourceCallback::CALLBACK_ALPHA; i <= SourceCallback::CALLBACK_PLAY; ++i){
|
||||
if ( ImGui::Selectable( callback_names[i]) ) {
|
||||
selected = i;
|
||||
}
|
||||
@@ -4381,7 +4381,7 @@ struct ClosestIndex
|
||||
void operator()(float v) { if (v < val) ++index; }
|
||||
};
|
||||
|
||||
void InputMappingInterface::SliderParametersCallback(SourceCallback *callback)
|
||||
void InputMappingInterface::SliderParametersCallback(SourceCallback *callback, Source *source)
|
||||
{
|
||||
const float right_align = -1.05f * ImGui::GetTextLineHeightWithSpacing();
|
||||
static const char *press_tooltip[3] = {"Key Press\nApply value on key press",
|
||||
@@ -4428,6 +4428,39 @@ void InputMappingInterface::SliderParametersCallback(SourceCallback *callback)
|
||||
edited->setValue(val);
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE / 2);
|
||||
ImGuiToolkit::Indication("Increment making the source more visible (>0) or more transparent (<0)", 19, 12);
|
||||
}
|
||||
break;
|
||||
case SourceCallback::CALLBACK_GEOMETRY:
|
||||
{
|
||||
SetGeometry *edited = static_cast<SetGeometry*>(callback);
|
||||
|
||||
bool bd = edited->bidirectional();
|
||||
if ( ImGuiToolkit::IconToggle(2, 13, 3, 13, &bd, press_tooltip ) )
|
||||
edited->setBidirectional(bd);
|
||||
|
||||
ClosestIndex d = std::for_each(speed_values.begin(), speed_values.end(), ClosestIndex(edited->duration()));
|
||||
int speed_index = d.index;
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE / 2);
|
||||
if (ImGuiToolkit::IconMultistate(speed_icon, &speed_index, speed_tooltip ))
|
||||
edited->setDuration(speed_values[speed_index]);
|
||||
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE / 2);
|
||||
if (ImGui::Button("Capture", ImVec2(right_align, 0))) {
|
||||
edited->setTarget( source->group(View::GEOMETRY) );
|
||||
}
|
||||
// show current geometry on over
|
||||
if (ImGui::IsItemHovered()) {
|
||||
InfoVisitor info;
|
||||
Group tmp; edited->getTarget(&tmp);
|
||||
tmp.accept(info);
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::Text(info.str().c_str());
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE / 2);
|
||||
ImGuiToolkit::Indication("Target geometry places the source by setting its position, scale and rotation", 1, 16);
|
||||
|
||||
}
|
||||
break;
|
||||
case SourceCallback::CALLBACK_GRAB:
|
||||
@@ -4464,10 +4497,11 @@ void InputMappingInterface::SliderParametersCallback(SourceCallback *callback)
|
||||
Turn *edited = static_cast<Turn*>(callback);
|
||||
float val = edited->value();
|
||||
ImGui::SetNextItemWidth(right_align);
|
||||
if (ImGui::SliderFloat("##CALLBACK_TURN", &val, -2.f, 2.f, "%.2f")) // 18.9
|
||||
edited->setValue(val);
|
||||
if ( ImGui::SliderAngle("##CALLBACK_TURN", &val, -180.f, 180.f) )
|
||||
edited->setValue(val );
|
||||
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE / 2);
|
||||
ImGuiToolkit::Indication("Angle of rotation of the source, clockwise (>0) or counter-clockwise (<0).", 18, 9);
|
||||
ImGuiToolkit::Indication("Rotation of the source (speed in \u00B0/s),\nclockwise (>0), counterclockwise (<0)", 18, 9);
|
||||
}
|
||||
break;
|
||||
case SourceCallback::CALLBACK_DEPTH:
|
||||
@@ -4516,10 +4550,29 @@ void InputMappingInterface::SliderParametersCallback(SourceCallback *callback)
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
Session *ses = Mixer::manager().session();
|
||||
|
||||
const ImGuiContext& g = *GImGui;
|
||||
static ImVec2 keyItemSpacing = ImVec2(6, 6);
|
||||
static ImVec2 keyLetterIconSize = ImVec2(48, 48);
|
||||
@@ -4540,6 +4593,9 @@ void InputMappingInterface::Render()
|
||||
return;
|
||||
}
|
||||
|
||||
// Update internal data structures
|
||||
readInputSource();
|
||||
|
||||
// menu (no title bar)
|
||||
if (ImGui::BeginMenuBar())
|
||||
{
|
||||
@@ -4551,8 +4607,9 @@ void InputMappingInterface::Render()
|
||||
// Disable
|
||||
ImGui::MenuItem( ICON_FA_BAN " Disable", nullptr, &Settings::application.mapping.disabled);
|
||||
|
||||
// Clear
|
||||
if ( ImGui::MenuItem( ICON_FA_BACKSPACE " Clear" ) ){
|
||||
// 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();
|
||||
}
|
||||
@@ -4586,6 +4643,59 @@ void InputMappingInterface::Render()
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
// Options for current key
|
||||
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_] ) ){
|
||||
// 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();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu(ICON_FA_CLOCK " Metronome", input_assigned[current_input_]))
|
||||
{
|
||||
Metronome::Synchronicity sync = Metronome::SYNC_NONE;
|
||||
bool active = sync == Metronome::SYNC_NONE;
|
||||
if (ImGuiToolkit::MenuItemIcon(5, 13, " Not synchronized", active )){
|
||||
|
||||
}
|
||||
active = sync == Metronome::SYNC_BEAT;
|
||||
if (ImGuiToolkit::MenuItemIcon(6, 13, " Sync to beat", active )){
|
||||
|
||||
}
|
||||
active = sync == Metronome::SYNC_PHASE;
|
||||
if (ImGuiToolkit::MenuItemIcon(7, 13, " Sync to phase", active )){
|
||||
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu(ICON_FA_COPY " Duplicate"))
|
||||
{
|
||||
// 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_] ))
|
||||
// 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();
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
|
||||
@@ -4594,29 +4704,10 @@ void InputMappingInterface::Render()
|
||||
ImDrawList* draw_list = window->DrawList;
|
||||
ImVec2 frame_top = ImGui::GetCursorScreenPos();
|
||||
|
||||
// create data structures more adapted for display
|
||||
std::multimap< uint, std::pair<Source *, SourceCallback*> > input_sources_callbacks;
|
||||
bool input_assigned[INPUT_MAX]{};
|
||||
// loop over sources of the 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;
|
||||
}
|
||||
}
|
||||
|
||||
// tooltip declined for each mode
|
||||
std::string _tooltip;
|
||||
//
|
||||
// KEYBOARD
|
||||
//
|
||||
if ( Settings::application.mapping.mode == 0 ) {
|
||||
_tooltip = "Key press on computer keyboard.";
|
||||
|
||||
// Draw table of letter keys [A] to [Y]
|
||||
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_LARGE);
|
||||
@@ -4688,7 +4779,6 @@ void InputMappingInterface::Render()
|
||||
// NUMPAD
|
||||
//
|
||||
else if ( Settings::application.mapping.mode == 1 ) {
|
||||
_tooltip = "Key press on computer numerical keypad.";
|
||||
|
||||
// custom layout of numerical keypad
|
||||
std::vector<uint> numpad_inputs = { INPUT_NUMPAD_FIRST+7, INPUT_NUMPAD_FIRST+8, INPUT_NUMPAD_FIRST+9, INPUT_NUMPAD_FIRST+11,
|
||||
@@ -4769,7 +4859,6 @@ void InputMappingInterface::Render()
|
||||
// MULTITOUCH OSC
|
||||
//
|
||||
else if ( Settings::application.mapping.mode == 2 ) {
|
||||
_tooltip = "Press and hold in the 'Multitouch' panel of the vimix TouchOSC companion.";
|
||||
|
||||
// Draw table of TouchOSC buttons
|
||||
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_LARGE);
|
||||
@@ -4828,7 +4917,6 @@ void InputMappingInterface::Render()
|
||||
// JOYSTICK
|
||||
//
|
||||
else if ( Settings::application.mapping.mode == 3 ) {
|
||||
_tooltip = "Button press and axis movements on a connected gamepad or joystick.";
|
||||
|
||||
// custom layout of gamepad buttons
|
||||
std::vector<uint> gamepad_inputs = { INPUT_JOYSTICK_FIRST_BUTTON+11, INPUT_JOYSTICK_FIRST_BUTTON+13,
|
||||
@@ -4993,18 +5081,11 @@ void InputMappingInterface::Render()
|
||||
|
||||
}
|
||||
|
||||
// Draw Indicator for current input
|
||||
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_MONO);
|
||||
ImGui::SetCursorScreenPos(frame_top + ImVec2(inputarea_width, 0) + g.Style.FramePadding);
|
||||
ImGui::Text( ICON_FA_CUBE " %s", Control::manager().inputLabel(current_input_).c_str() );
|
||||
ImGui::PopFont();
|
||||
|
||||
// Draw child Window (rounded border) to list reactions to input
|
||||
ImGui::SetCursorScreenPos(frame_top + ImVec2(inputarea_width, g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y * 2.0f));
|
||||
// Draw child Window (right) to list reactions to input
|
||||
ImGui::SetCursorScreenPos(frame_top + g.Style.FramePadding + ImVec2(inputarea_width,0.f));
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2.f, g.Style.ItemSpacing.y * 2.f) );
|
||||
ImGui::BeginChild("InputsMappingInterfacePanel", ImVec2(0, 0), true);
|
||||
ImGui::BeginChild("InputsMappingInterfacePanel", ImVec2(0, 0), false);
|
||||
|
||||
float w = ImGui::GetWindowWidth() *0.25f;
|
||||
|
||||
@@ -5058,7 +5139,7 @@ void InputMappingInterface::Render()
|
||||
// Adjust parameters
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
if (callback)
|
||||
SliderParametersCallback( callback );
|
||||
SliderParametersCallback( callback, source );
|
||||
|
||||
ImGui::PopID();
|
||||
|
||||
@@ -5066,8 +5147,7 @@ void InputMappingInterface::Render()
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
ImGui::Text("No action mapped to this input. Add one with '+'.");
|
||||
ImGui::Text("No action mapped to this input. Add one with +.");
|
||||
}
|
||||
|
||||
// Add a new interface
|
||||
@@ -5114,40 +5194,11 @@ void InputMappingInterface::Render()
|
||||
}
|
||||
}
|
||||
|
||||
// close child window
|
||||
ImGui::EndChild();
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
|
||||
// Custom popup menu for the current input actions (right aligned)
|
||||
ImGui::SetCursorScreenPos(frame_top + ImVec2(window->Size.x - 2.f * g.FontSize - g.Style.FramePadding.x * 3.0f - g.Style.WindowPadding.x, g.Style.FramePadding.y));
|
||||
ImGuiToolkit::HelpToolTip(_tooltip.c_str());
|
||||
ImGui::SameLine(0, g.Style.FramePadding.x);
|
||||
if (ImGuiToolkit::IconButton(5, 8))
|
||||
ImGui::OpenPopup( "MenuInputMapping" );
|
||||
if (ImGui::BeginPopup( "MenuInputMapping" ))
|
||||
{
|
||||
// 1) Reset (if there are callbacks assigned)
|
||||
if (ImGui::MenuItem("Reset", NULL, false, input_assigned[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);
|
||||
}
|
||||
// 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_] ))
|
||||
// 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());
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
@@ -369,11 +369,15 @@ 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);
|
||||
void SliderParametersCallback(SourceCallback *callback, Source *source);
|
||||
|
||||
public:
|
||||
InputMappingInterface();
|
||||
|
||||
@@ -44,6 +44,7 @@ class MultiFileSource;
|
||||
class SourceCallback;
|
||||
class SetAlpha;
|
||||
class SetDepth;
|
||||
class SetGeometry;
|
||||
class Loom;
|
||||
class Grab;
|
||||
class Resize;
|
||||
@@ -98,6 +99,7 @@ public:
|
||||
virtual void visit (SourceCallback&) {}
|
||||
virtual void visit (SetAlpha&) {}
|
||||
virtual void visit (SetDepth&) {}
|
||||
virtual void visit (SetGeometry&) {}
|
||||
virtual void visit (Loom&) {}
|
||||
virtual void visit (Grab&) {}
|
||||
virtual void visit (Resize&) {}
|
||||
|
||||
Reference in New Issue
Block a user