diff --git a/InfoVisitor.cpp b/InfoVisitor.cpp index aee6797..fcffae1 100644 --- a/InfoVisitor.cpp +++ b/InfoVisitor.cpp @@ -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 &) diff --git a/SessionCreator.cpp b/SessionCreator.cpp index a4b8d29..239c74d 100644 --- a/SessionCreator.cpp +++ b/SessionCreator.cpp @@ -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; diff --git a/SessionCreator.h b/SessionCreator.h index 54a461f..1d8e8fa 100644 --- a/SessionCreator.h +++ b/SessionCreator.h @@ -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; diff --git a/SessionVisitor.cpp b/SessionVisitor.cpp index d05396c..65d6062 100644 --- a/SessionVisitor.cpp +++ b/SessionVisitor.cpp @@ -589,9 +589,9 @@ void SessionVisitor::visit (Source& s) std::list 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()); diff --git a/SessionVisitor.h b/SessionVisitor.h index cc1746a..ea4cdef 100644 --- a/SessionVisitor.h +++ b/SessionVisitor.h @@ -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; diff --git a/SourceCallback.cpp b/SourceCallback.cpp index 9073da7..79d45cf 100644 --- a/SourceCallback.cpp +++ b/SourceCallback.cpp @@ -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_ ) { diff --git a/SourceCallback.h b/SourceCallback.h index 371034a..b87b386 100644 --- a/SourceCallback.h +++ b/SourceCallback.h @@ -3,6 +3,8 @@ #include +#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_; diff --git a/UserInterfaceManager.cpp b/UserInterfaceManager.cpp index a146de8..fa5c98c 100644 --- a/UserInterfaceManager.cpp +++ b/UserInterfaceManager.cpp @@ -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(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(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 inputs = (*sit)->callbackInputs(); + for (auto k = inputs.begin(); k != inputs.end(); ++k) { + // add entry in input map + std::list callbacks = (*sit)->inputCallbacks(*k); + for (auto c = callbacks.begin(); c != callbacks.end(); ++c ) + input_sources_callbacks.emplace( *k, std::pair(*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 > 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 inputs = (*sit)->callbackInputs(); - for (auto k = inputs.begin(); k != inputs.end(); ++k) { - // add entry in input map - std::list callbacks = (*sit)->inputCallbacks(*k); - for (auto c = callbacks.begin(); c != callbacks.end(); ++c ) - input_sources_callbacks.emplace( *k, std::pair(*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 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 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(); } diff --git a/UserInterfaceManager.h b/UserInterfaceManager.h index 68f6014..4aad7bd 100644 --- a/UserInterfaceManager.h +++ b/UserInterfaceManager.h @@ -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 > 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(); diff --git a/Visitor.h b/Visitor.h index a8189c3..790c37d 100644 --- a/Visitor.h +++ b/Visitor.h @@ -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&) {}