From b04c7c9d7d821003b31b3bfb4eafa221e2aca33a Mon Sep 17 00:00:00 2001 From: brunoherbelin Date: Sat, 20 Jun 2020 17:23:54 +0200 Subject: [PATCH] Fixed and improved multi-source selection. --- Mixer.cpp | 69 +++++++++-------- Mixer.h | 22 +++--- Selection.cpp | 28 ++++++- Selection.h | 3 +- Source.cpp | 5 +- UserInterfaceManager.cpp | 156 +++++++++++++++++++++------------------ 6 files changed, 167 insertions(+), 116 deletions(-) diff --git a/Mixer.cpp b/Mixer.cpp index 39503d1..966a4e6 100644 --- a/Mixer.cpp +++ b/Mixer.cpp @@ -270,7 +270,14 @@ Source * Mixer::createSourceClone(std::string namesource) // ready to create a source Source *s = nullptr; - SourceList::iterator origin = session_->find(namesource); + // origin to clone is either the given name or the current + SourceList::iterator origin = session_->end(); + if ( !namesource.empty() ) + origin =session_->find(namesource); + else if (current_source_ != session_->end()) + origin = current_source_; + + // have an origin, can clone it if (origin != session_->end()) { // create a source @@ -285,7 +292,8 @@ Source * Mixer::createSourceClone(std::string namesource) void Mixer::addSource(Source *s) { - candidate_sources_.push_back(s); + if (s != nullptr) + candidate_sources_.push_back(s); } void Mixer::insertSource(Source *s, bool makecurrent) @@ -306,22 +314,17 @@ void Mixer::insertSource(Source *s, bool makecurrent) layer_.scene.ws()->attach(s->group(View::LAYER)); if (makecurrent) { - // set this new source as current - setCurrentSource( sit ); - // switch to Mixing view to show source created setView(View::MIXING); current_view_->update(0); current_view_->centerSource(s); + + // set this new source as current + setCurrentSource( sit ); } } } -void Mixer::deleteCurrentSource() -{ - deleteSource( currentSource() ); -} - void Mixer::deleteSource(Source *s) { if ( s != nullptr ) @@ -387,13 +390,17 @@ void Mixer::setCurrentSource(SourceList::iterator it) // change current if it is valid if ( it != session_->end() ) { current_source_ = it; - current_source_index_ = session_->index(it); - // set selection if not already selected - if (!selection().contains(*it)) - selection().set(*it); + current_source_index_ = session_->index(current_source_); + + // set selection for this only source if not already part of a selection + if (!selection().contains(*current_source_)) + selection().set(*current_source_); + // show status as current (*current_source_)->setMode(Source::CURRENT); + Log::Info("setCurrentSource"); } + } Source * Mixer::findSource (Node *node) @@ -404,6 +411,14 @@ Source * Mixer::findSource (Node *node) return nullptr; } +Source * Mixer::findSource (std::string namesource) +{ + SourceList::iterator it = session_->find(namesource); + if (it != session_->end()) + return *it; + return nullptr; +} + void Mixer::setCurrentSource(Node *node) { setCurrentSource( session_->find(node) ); @@ -439,18 +454,20 @@ void Mixer::setCurrentNext() void Mixer::unsetCurrentSource() { + Log::Info("unsetCurrentSource"); + // discard overlay for previously current source if ( current_source_ != session_->end() ) { -// if (selection().size() > 1) { -// } -// // current source is the sole selected source : unselect and -// else + // current source is part of a selection, just change status + if (selection().size() > 1) { + (*current_source_)->setMode(Source::SELECTED); + } + // current source is the only selected source, unselect too + else { // remove from selection -// selection().remove( *current_source_ ); - // show status as normal - (*current_source_)->setMode(Source::SELECTED); + selection().remove( *current_source_ ); } } @@ -459,16 +476,6 @@ void Mixer::unsetCurrentSource() current_source_index_ = -1; } -void Mixer::cloneCurrentSource() -{ - if ( current_source_ != session_->end() ) - { - Source *s = createSourceClone( (*current_source_)->name() ); - - insertSource(s); - } -} - int Mixer::indexCurrentSource() { return current_source_index_; diff --git a/Mixer.h b/Mixer.h index 9c23fde..1806d09 100644 --- a/Mixer.h +++ b/Mixer.h @@ -41,7 +41,7 @@ public: // creation of sources Source * createSourceFile (std::string path); - Source * createSourceClone (std::string namesource); + Source * createSourceClone (std::string namesource = ""); Source * createSourceRender (); // operations on sources @@ -50,34 +50,32 @@ public: void renameSource (Source *s, const std::string &newname); // current source + void setCurrentSource (Source *s); void setCurrentSource (std::string namesource); void setCurrentSource (Node *node); void setCurrentSource (int index); - void setCurrentSource (Source *s); void setCurrentNext (); void unsetCurrentSource (); - - void cloneCurrentSource (); - void deleteCurrentSource (); int indexCurrentSource (); - Source * currentSource (); + + // browsing into sources Source * findSource (Node *node); + Source * findSource (std::string name); // management of view - View *view (View::Mode m = View::INVALID); + View *view (View::Mode m = View::INVALID); void setView (View::Mode m); -// View *currentView (); // manipulate, load and save sessions inline Session *session () const { return session_; } - void clear (); - void save (); + void clear (); + void save (); void saveas (const std::string& filename); void open (const std::string& filename); void import (const std::string& filename); - void merge (Session *s); - void set (Session *s); + void merge (Session *s); + void set (Session *s); protected: diff --git a/Selection.cpp b/Selection.cpp index 14139ac..a72c939 100644 --- a/Selection.cpp +++ b/Selection.cpp @@ -4,18 +4,25 @@ Selection::Selection() { - } void Selection::add(Source *s) { + if (s == nullptr) + return; + selection_.push_back(s); + selection_.sort(); + selection_.unique(); s->setMode(Source::SELECTED); } void Selection::remove(Source *s) { + if (s == nullptr) + return; + SourceList::iterator it = find(s); if (it != selection_.end()) { selection_.erase(it); @@ -25,6 +32,9 @@ void Selection::remove(Source *s) void Selection::toggle(Source *s) { + if (s == nullptr) + return; + if (contains(s)) remove(s); else @@ -34,6 +44,10 @@ void Selection::toggle(Source *s) void Selection::set(Source *s) { clear(); + + if (s == nullptr) + return; + selection_.push_back(s); s->setMode(Source::SELECTED); } @@ -91,6 +105,16 @@ uint Selection::size() return selection_.size(); } +Source *Selection::front() +{ + return selection_.front(); +} + +bool Selection::empty() +{ + return selection_.empty(); +} + SourceList::iterator Selection::find(Source *s) { return std::find(selection_.begin(), selection_.end(), s); @@ -111,3 +135,5 @@ SourceList::iterator Selection::end() { return selection_.end(); } + + diff --git a/Selection.h b/Selection.h index 7868331..552fd28 100644 --- a/Selection.h +++ b/Selection.h @@ -21,13 +21,14 @@ public: SourceList::iterator begin (); SourceList::iterator end (); + Source *front(); bool contains (Source *s); + bool empty(); uint size (); protected: SourceList::iterator find (Source *s); SourceList selection_; - }; #endif // SELECTION_H diff --git a/Source.cpp b/Source.cpp index 546fdd3..88747ca 100644 --- a/Source.cpp +++ b/Source.cpp @@ -180,6 +180,7 @@ void Source::setMode(Source::Mode m) } +// test update callback void fix_ar(Node *n) { n->scale_.y = n->scale_.x; @@ -222,7 +223,9 @@ void Source::attach(FrameBuffer *renderbuffer) // test update callback // groups_[View::GEOMETRY]->update_callbacks_.push_front(fix_ar); - setMode(Source::NORMAL); + // make the source visible + if ( mode_ == HIDDEN ) + setMode(NORMAL); } void Source::update(float dt) diff --git a/UserInterfaceManager.cpp b/UserInterfaceManager.cpp index b008315..6ad4302 100644 --- a/UserInterfaceManager.cpp +++ b/UserInterfaceManager.cpp @@ -274,7 +274,7 @@ void UserInterface::handleKeyboard() else if ( !ImGui::IsAnyWindowFocused() ){ // Backspace to delete source if (ImGui::IsKeyPressed( GLFW_KEY_BACKSPACE ) || ImGui::IsKeyPressed( GLFW_KEY_DELETE )) - Mixer::manager().deleteCurrentSource(); + Mixer::manager().deleteSource( Mixer::manager().currentSource() ); // button esc to toggle fullscreen else if (ImGui::IsKeyPressed( GLFW_KEY_ESCAPE )) Rendering::manager().mainWindow().setFullscreen(nullptr); @@ -293,17 +293,16 @@ void UserInterface::handleKeyboard() } -void setMouseCursor(View::Cursor c = View::Cursor()) +void setMouseCursor(glm::vec2 mousepos, View::Cursor c = View::Cursor()) { ImGui::SetMouseCursor(c.type); if ( !c.info.empty()) { - ImGuiIO& io = ImGui::GetIO(); float d = 0.5f * ImGui::GetFrameHeight() ; - ImVec2 window_pos = ImVec2( io.MousePos.x - d, io.MousePos.y - d ); + ImVec2 window_pos = ImVec2( mousepos.x - d, mousepos.y - d ); ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always); ImGui::SetNextWindowBgAlpha(0.75f); // Transparent background - if (ImGui::Begin("MouseInfoContext", NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav)) + if (ImGui::Begin("MouseInfoContext", NULL, ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav)) { ImGuiToolkit::PushFont(ImGuiToolkit::FONT_MONO); ImGui::Text(" %s", c.info.c_str()); @@ -322,6 +321,7 @@ void UserInterface::handleMouse() mouseclic[ImGuiMouseButton_Left] = glm::vec2(io.MouseClickedPos[ImGuiMouseButton_Left].x * io.DisplayFramebufferScale.y, io.MouseClickedPos[ImGuiMouseButton_Left].y* io.DisplayFramebufferScale.x); mouseclic[ImGuiMouseButton_Right] = glm::vec2(io.MouseClickedPos[ImGuiMouseButton_Right].x * io.DisplayFramebufferScale.y, io.MouseClickedPos[ImGuiMouseButton_Right].y* io.DisplayFramebufferScale.x); + static bool mousedown = false; static std::pair picked = { nullptr, glm::vec2(0.f) }; // steal focus on right button clic @@ -332,7 +332,6 @@ void UserInterface::handleMouse() // if not on any window if ( !ImGui::IsAnyWindowHovered() && !ImGui::IsAnyWindowFocused() ) { - Source *current = Mixer::manager().currentSource(); // if (current) // { @@ -361,13 +360,12 @@ void UserInterface::handleMouse() { // right mouse drag => drag current view View::Cursor c = Mixer::manager().view()->drag( mouseclic[ImGuiMouseButton_Right], mousepos); - setMouseCursor(c); + setMouseCursor(mousepos, c); } else if ( ImGui::IsMouseDown(ImGuiMouseButton_Right)) { Mixer::manager().unsetCurrentSource(); navigator.hidePannel(); - // glm::vec3 point = Rendering::manager().unProject(mousepos, Mixer::manager().currentView()->scene.root()->transform_ ); } @@ -379,74 +377,60 @@ void UserInterface::handleMouse() // // LEFT Mouse button // - if ( ImGui::IsMouseDragging(ImGuiMouseButton_Left, 5.0f) ) - { - if (current) + if ( ImGui::IsMouseDown(ImGuiMouseButton_Left) ) { + + if ( !mousedown) { + mousedown = true; + Log::Info("LMB %d", mousedown); - // grab current source -// View::Cursor c = Mixer::manager().currentView()->grab(current, mouseclic[ImGuiMouseButton_Left], mousepos, picked); -// setMouseCursor(c); - // grab selected sources (current is also selected by default) - View::Cursor c = View::Cursor_Arrow; - for (auto it = Mixer::selection().begin(); it != Mixer::selection().end(); it++) - c = Mixer::manager().view()->grab(*it, mouseclic[ImGuiMouseButton_Left], mousepos, picked); - setMouseCursor(c); - } - else { - // Selection area - ImGui::GetBackgroundDrawList()->AddRect(io.MouseClickedPos[ImGuiMouseButton_Left], io.MousePos, - ImGui::GetColorU32(ImGuiCol_ResizeGripHovered)); - ImGui::GetBackgroundDrawList()->AddRectFilled(io.MouseClickedPos[ImGuiMouseButton_Left], io.MousePos, - ImGui::GetColorU32(ImGuiCol_ResizeGripHovered, 0.3f)); + // ask the view what was picked + picked = Mixer::manager().view()->pick(mousepos); - // Bounding box multiple sources selection - Mixer::manager().view()->select(mouseclic[ImGuiMouseButton_Left], mousepos); - - } - } - else if ( ImGui::IsMouseClicked(ImGuiMouseButton_Left) ) { - - // ask the view what was picked - picked = Mixer::manager().view()->pick(mousepos); - - // if nothing picked, - if ( picked.first == nullptr ) { - // unset current - Mixer::manager().unsetCurrentSource(); - navigator.hidePannel(); - // clear selection - Mixer::selection().clear(); - } - // something was picked - else { - // get if a source was picked - Source *s = Mixer::manager().findSource(picked.first); - if (s != nullptr) { - - if (keyboard_modifier_active) { - // selection - Mixer::selection().toggle( s ); // TODO toggle selection - } - // make current - else { - Mixer::manager().setCurrentSource( s ); - if (navigator.pannelVisible()) - navigator.showPannelSource( Mixer::manager().indexCurrentSource() ); - } - - // indicate to view that an action can be initiated (e.g. grab) - Mixer::manager().view()->initiate(); + // if nothing picked, + if ( picked.first == nullptr ) { + // unset current + Mixer::manager().unsetCurrentSource(); + navigator.hidePannel(); + // clear selection + Mixer::selection().clear(); } + // something was picked + else { + // get if a source was picked + Source *s = Mixer::manager().findSource(picked.first); + if (s != nullptr) { + if (keyboard_modifier_active) { + if ( !Mixer::selection().contains(s) ) + Mixer::selection().add( s ); + else { + Mixer::selection().remove( s ); + if ( Mixer::selection().size() > 1 ) + s = Mixer::selection().front(); + else { + s = nullptr; + } + } +// Mixer::selection().toggle( Mixer::manager().currentSource() ); + } + + { + + Mixer::manager().setCurrentSource( s ); + if (navigator.pannelVisible()) + navigator.showPannelSource( Mixer::manager().indexCurrentSource() ); + + } + + // indicate to view that an action can be initiated (e.g. grab) + Mixer::manager().view()->initiate(); + } + + } } } - else if ( ImGui::IsMouseReleased(ImGuiMouseButton_Left) ) - { - picked = { nullptr, glm::vec2(0.f) }; - - } - if ( ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left) ) + else if ( ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left) ) { // display source in left pannel navigator.showPannelSource( Mixer::manager().indexCurrentSource() ); @@ -454,7 +438,39 @@ void UserInterface::handleMouse() // (because single clic maintains same source active) Mixer::manager().unsetCurrentSource(); } + else if ( ImGui::IsMouseReleased(ImGuiMouseButton_Left) ) + { + mousedown = false; + Log::Info("LMB %d", mousedown); + picked = { nullptr, glm::vec2(0.f) }; + } + +// if ( mousedown && glm::distance(mouseclic[ImGuiMouseButton_Left], mousepos) > 3.f ) + if ( ImGui::IsMouseDragging(ImGuiMouseButton_Left, 5.0f) ) + { +// Log::Info("LMB drag %f", glm::distance(mouseclic[ImGuiMouseButton_Left], mousepos)); + + Source *current = Mixer::manager().currentSource(); + if (current) + { + // grab selected sources (current is also selected by default) + View::Cursor c = View::Cursor_Arrow; + for (auto it = Mixer::selection().begin(); it != Mixer::selection().end(); it++) + c = Mixer::manager().view()->grab(*it, mouseclic[ImGuiMouseButton_Left], mousepos, picked); + setMouseCursor(mousepos, c); + } + else { + // Selection area + ImGui::GetBackgroundDrawList()->AddRect(io.MouseClickedPos[ImGuiMouseButton_Left], io.MousePos, + ImGui::GetColorU32(ImGuiCol_ResizeGripHovered)); + ImGui::GetBackgroundDrawList()->AddRectFilled(io.MouseClickedPos[ImGuiMouseButton_Left], io.MousePos, + ImGui::GetColorU32(ImGuiCol_ResizeGripHovered, 0.3f)); + + // Bounding box multiple sources selection + Mixer::manager().view()->select(mouseclic[ImGuiMouseButton_Left], mousepos); + } + } } } @@ -1198,7 +1214,7 @@ void Navigator::RenderSourcePannel(Source *s) ImGui::Text(" "); // Action on source if ( ImGui::Button( ICON_FA_SHARE_SQUARE " Clone", ImVec2(ImGui::GetContentRegionAvail().x, 0)) ) - Mixer::manager().cloneCurrentSource(); + Mixer::manager().addSource ( Mixer::manager().createSourceClone() ); if ( ImGui::Button( ICON_FA_BACKSPACE " Delete", ImVec2(ImGui::GetContentRegionAvail().x, 0)) ) { Mixer::manager().deleteSource(s); }