Fixed and improved multi-source selection.

This commit is contained in:
brunoherbelin
2020-06-20 17:23:54 +02:00
parent b8d394954c
commit b04c7c9d7d
6 changed files with 167 additions and 116 deletions

View File

@@ -270,7 +270,14 @@ Source * Mixer::createSourceClone(std::string namesource)
// ready to create a source // ready to create a source
Source *s = nullptr; 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()) { if (origin != session_->end()) {
// create a source // create a source
@@ -285,7 +292,8 @@ Source * Mixer::createSourceClone(std::string namesource)
void Mixer::addSource(Source *s) 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) 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)); layer_.scene.ws()->attach(s->group(View::LAYER));
if (makecurrent) { if (makecurrent) {
// set this new source as current
setCurrentSource( sit );
// switch to Mixing view to show source created // switch to Mixing view to show source created
setView(View::MIXING); setView(View::MIXING);
current_view_->update(0); current_view_->update(0);
current_view_->centerSource(s); current_view_->centerSource(s);
// set this new source as current
setCurrentSource( sit );
} }
} }
} }
void Mixer::deleteCurrentSource()
{
deleteSource( currentSource() );
}
void Mixer::deleteSource(Source *s) void Mixer::deleteSource(Source *s)
{ {
if ( s != nullptr ) if ( s != nullptr )
@@ -387,13 +390,17 @@ void Mixer::setCurrentSource(SourceList::iterator it)
// change current if it is valid // change current if it is valid
if ( it != session_->end() ) { if ( it != session_->end() ) {
current_source_ = it; current_source_ = it;
current_source_index_ = session_->index(it); current_source_index_ = session_->index(current_source_);
// set selection if not already selected
if (!selection().contains(*it)) // set selection for this only source if not already part of a selection
selection().set(*it); if (!selection().contains(*current_source_))
selection().set(*current_source_);
// show status as current // show status as current
(*current_source_)->setMode(Source::CURRENT); (*current_source_)->setMode(Source::CURRENT);
Log::Info("setCurrentSource");
} }
} }
Source * Mixer::findSource (Node *node) Source * Mixer::findSource (Node *node)
@@ -404,6 +411,14 @@ Source * Mixer::findSource (Node *node)
return nullptr; 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) void Mixer::setCurrentSource(Node *node)
{ {
setCurrentSource( session_->find(node) ); setCurrentSource( session_->find(node) );
@@ -439,18 +454,20 @@ void Mixer::setCurrentNext()
void Mixer::unsetCurrentSource() void Mixer::unsetCurrentSource()
{ {
Log::Info("unsetCurrentSource");
// discard overlay for previously current source // discard overlay for previously current source
if ( current_source_ != session_->end() ) { if ( current_source_ != session_->end() ) {
// if (selection().size() > 1) {
// } // current source is part of a selection, just change status
// // current source is the sole selected source : unselect and if (selection().size() > 1) {
// else (*current_source_)->setMode(Source::SELECTED);
}
// current source is the only selected source, unselect too
else
{ {
// remove from selection // remove from selection
// selection().remove( *current_source_ ); selection().remove( *current_source_ );
// show status as normal
(*current_source_)->setMode(Source::SELECTED);
} }
} }
@@ -459,16 +476,6 @@ void Mixer::unsetCurrentSource()
current_source_index_ = -1; current_source_index_ = -1;
} }
void Mixer::cloneCurrentSource()
{
if ( current_source_ != session_->end() )
{
Source *s = createSourceClone( (*current_source_)->name() );
insertSource(s);
}
}
int Mixer::indexCurrentSource() int Mixer::indexCurrentSource()
{ {
return current_source_index_; return current_source_index_;

22
Mixer.h
View File

@@ -41,7 +41,7 @@ public:
// creation of sources // creation of sources
Source * createSourceFile (std::string path); Source * createSourceFile (std::string path);
Source * createSourceClone (std::string namesource); Source * createSourceClone (std::string namesource = "");
Source * createSourceRender (); Source * createSourceRender ();
// operations on sources // operations on sources
@@ -50,34 +50,32 @@ public:
void renameSource (Source *s, const std::string &newname); void renameSource (Source *s, const std::string &newname);
// current source // current source
void setCurrentSource (Source *s);
void setCurrentSource (std::string namesource); void setCurrentSource (std::string namesource);
void setCurrentSource (Node *node); void setCurrentSource (Node *node);
void setCurrentSource (int index); void setCurrentSource (int index);
void setCurrentSource (Source *s);
void setCurrentNext (); void setCurrentNext ();
void unsetCurrentSource (); void unsetCurrentSource ();
void cloneCurrentSource ();
void deleteCurrentSource ();
int indexCurrentSource (); int indexCurrentSource ();
Source * currentSource (); Source * currentSource ();
// browsing into sources
Source * findSource (Node *node); Source * findSource (Node *node);
Source * findSource (std::string name);
// management of view // management of view
View *view (View::Mode m = View::INVALID); View *view (View::Mode m = View::INVALID);
void setView (View::Mode m); void setView (View::Mode m);
// View *currentView ();
// manipulate, load and save sessions // manipulate, load and save sessions
inline Session *session () const { return session_; } inline Session *session () const { return session_; }
void clear (); void clear ();
void save (); void save ();
void saveas (const std::string& filename); void saveas (const std::string& filename);
void open (const std::string& filename); void open (const std::string& filename);
void import (const std::string& filename); void import (const std::string& filename);
void merge (Session *s); void merge (Session *s);
void set (Session *s); void set (Session *s);
protected: protected:

View File

@@ -4,18 +4,25 @@
Selection::Selection() Selection::Selection()
{ {
} }
void Selection::add(Source *s) void Selection::add(Source *s)
{ {
if (s == nullptr)
return;
selection_.push_back(s); selection_.push_back(s);
selection_.sort();
selection_.unique();
s->setMode(Source::SELECTED); s->setMode(Source::SELECTED);
} }
void Selection::remove(Source *s) void Selection::remove(Source *s)
{ {
if (s == nullptr)
return;
SourceList::iterator it = find(s); SourceList::iterator it = find(s);
if (it != selection_.end()) { if (it != selection_.end()) {
selection_.erase(it); selection_.erase(it);
@@ -25,6 +32,9 @@ void Selection::remove(Source *s)
void Selection::toggle(Source *s) void Selection::toggle(Source *s)
{ {
if (s == nullptr)
return;
if (contains(s)) if (contains(s))
remove(s); remove(s);
else else
@@ -34,6 +44,10 @@ void Selection::toggle(Source *s)
void Selection::set(Source *s) void Selection::set(Source *s)
{ {
clear(); clear();
if (s == nullptr)
return;
selection_.push_back(s); selection_.push_back(s);
s->setMode(Source::SELECTED); s->setMode(Source::SELECTED);
} }
@@ -91,6 +105,16 @@ uint Selection::size()
return selection_.size(); return selection_.size();
} }
Source *Selection::front()
{
return selection_.front();
}
bool Selection::empty()
{
return selection_.empty();
}
SourceList::iterator Selection::find(Source *s) SourceList::iterator Selection::find(Source *s)
{ {
return std::find(selection_.begin(), selection_.end(), s); return std::find(selection_.begin(), selection_.end(), s);
@@ -111,3 +135,5 @@ SourceList::iterator Selection::end()
{ {
return selection_.end(); return selection_.end();
} }

View File

@@ -21,13 +21,14 @@ public:
SourceList::iterator begin (); SourceList::iterator begin ();
SourceList::iterator end (); SourceList::iterator end ();
Source *front();
bool contains (Source *s); bool contains (Source *s);
bool empty();
uint size (); uint size ();
protected: protected:
SourceList::iterator find (Source *s); SourceList::iterator find (Source *s);
SourceList selection_; SourceList selection_;
}; };
#endif // SELECTION_H #endif // SELECTION_H

View File

@@ -180,6 +180,7 @@ void Source::setMode(Source::Mode m)
} }
// test update callback
void fix_ar(Node *n) void fix_ar(Node *n)
{ {
n->scale_.y = n->scale_.x; n->scale_.y = n->scale_.x;
@@ -222,7 +223,9 @@ void Source::attach(FrameBuffer *renderbuffer)
// test update callback // test update callback
// groups_[View::GEOMETRY]->update_callbacks_.push_front(fix_ar); // 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) void Source::update(float dt)

View File

@@ -274,7 +274,7 @@ void UserInterface::handleKeyboard()
else if ( !ImGui::IsAnyWindowFocused() ){ else if ( !ImGui::IsAnyWindowFocused() ){
// Backspace to delete source // Backspace to delete source
if (ImGui::IsKeyPressed( GLFW_KEY_BACKSPACE ) || ImGui::IsKeyPressed( GLFW_KEY_DELETE )) 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 // button esc to toggle fullscreen
else if (ImGui::IsKeyPressed( GLFW_KEY_ESCAPE )) else if (ImGui::IsKeyPressed( GLFW_KEY_ESCAPE ))
Rendering::manager().mainWindow().setFullscreen(nullptr); 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); ImGui::SetMouseCursor(c.type);
if ( !c.info.empty()) { if ( !c.info.empty()) {
ImGuiIO& io = ImGui::GetIO();
float d = 0.5f * ImGui::GetFrameHeight() ; 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::SetNextWindowPos(window_pos, ImGuiCond_Always);
ImGui::SetNextWindowBgAlpha(0.75f); // Transparent background 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); ImGuiToolkit::PushFont(ImGuiToolkit::FONT_MONO);
ImGui::Text(" %s", c.info.c_str()); 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_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); 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<Node *, glm::vec2> picked = { nullptr, glm::vec2(0.f) }; static std::pair<Node *, glm::vec2> picked = { nullptr, glm::vec2(0.f) };
// steal focus on right button clic // steal focus on right button clic
@@ -332,7 +332,6 @@ void UserInterface::handleMouse()
// if not on any window // if not on any window
if ( !ImGui::IsAnyWindowHovered() && !ImGui::IsAnyWindowFocused() ) if ( !ImGui::IsAnyWindowHovered() && !ImGui::IsAnyWindowFocused() )
{ {
Source *current = Mixer::manager().currentSource();
// if (current) // if (current)
// { // {
@@ -361,13 +360,12 @@ void UserInterface::handleMouse()
{ {
// right mouse drag => drag current view // right mouse drag => drag current view
View::Cursor c = Mixer::manager().view()->drag( mouseclic[ImGuiMouseButton_Right], mousepos); View::Cursor c = Mixer::manager().view()->drag( mouseclic[ImGuiMouseButton_Right], mousepos);
setMouseCursor(c); setMouseCursor(mousepos, c);
} }
else if ( ImGui::IsMouseDown(ImGuiMouseButton_Right)) { else if ( ImGui::IsMouseDown(ImGuiMouseButton_Right)) {
Mixer::manager().unsetCurrentSource(); Mixer::manager().unsetCurrentSource();
navigator.hidePannel(); navigator.hidePannel();
// glm::vec3 point = Rendering::manager().unProject(mousepos, Mixer::manager().currentView()->scene.root()->transform_ ); // glm::vec3 point = Rendering::manager().unProject(mousepos, Mixer::manager().currentView()->scene.root()->transform_ );
} }
@@ -379,74 +377,60 @@ void UserInterface::handleMouse()
// //
// LEFT Mouse button // LEFT Mouse button
// //
if ( ImGui::IsMouseDragging(ImGuiMouseButton_Left, 5.0f) ) if ( ImGui::IsMouseDown(ImGuiMouseButton_Left) ) {
{
if (current) if ( !mousedown)
{ {
mousedown = true;
Log::Info("LMB %d", mousedown);
// grab current source // ask the view what was picked
// View::Cursor c = Mixer::manager().currentView()->grab(current, mouseclic[ImGuiMouseButton_Left], mousepos, picked); picked = Mixer::manager().view()->pick(mousepos);
// 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));
// Bounding box multiple sources selection // if nothing picked,
Mixer::manager().view()->select(mouseclic[ImGuiMouseButton_Left], mousepos); if ( picked.first == nullptr ) {
// unset current
} Mixer::manager().unsetCurrentSource();
} navigator.hidePannel();
else if ( ImGui::IsMouseClicked(ImGuiMouseButton_Left) ) { // clear selection
Mixer::selection().clear();
// 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();
} }
// 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) ) else if ( ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left) )
{
picked = { nullptr, glm::vec2(0.f) };
}
if ( ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left) )
{ {
// display source in left pannel // display source in left pannel
navigator.showPannelSource( Mixer::manager().indexCurrentSource() ); navigator.showPannelSource( Mixer::manager().indexCurrentSource() );
@@ -454,7 +438,39 @@ void UserInterface::handleMouse()
// (because single clic maintains same source active) // (because single clic maintains same source active)
Mixer::manager().unsetCurrentSource(); 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(" "); ImGui::Text(" ");
// Action on source // Action on source
if ( ImGui::Button( ICON_FA_SHARE_SQUARE " Clone", ImVec2(ImGui::GetContentRegionAvail().x, 0)) ) 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)) ) { if ( ImGui::Button( ICON_FA_BACKSPACE " Delete", ImVec2(ImGui::GetContentRegionAvail().x, 0)) ) {
Mixer::manager().deleteSource(s); Mixer::manager().deleteSource(s);
} }