diff --git a/ImGuiVisitor.cpp b/ImGuiVisitor.cpp index aafe1fb..4fbac0c 100644 --- a/ImGuiVisitor.cpp +++ b/ImGuiVisitor.cpp @@ -421,6 +421,15 @@ void ImGuiVisitor::visit (Source& s) else ImGuiToolkit::HelpMarker("Unlocked", ICON_FA_LOCK_OPEN); + // Inform on workspace + ImGui::SetCursorPos( ImVec2(preview_width + 20, pos.y -height + 2.f * ImGui::GetFrameHeight()) ); + if (s.workspace() == Source::BACKGROUND) + ImGuiToolkit::HelpIcon("Background",10, 16); + else if (s.workspace() == Source::FOREGROUND) + ImGuiToolkit::HelpIcon("Foreground",12, 16); + else + ImGuiToolkit::HelpIcon("Stage",11, 16); + // toggle enable/disable image processing bool on = s.imageProcessingEnabled(); ImGui::SetCursorPos( ImVec2(preview_width + 15, pos.y -ImGui::GetFrameHeight() ) ); diff --git a/Mixer.cpp b/Mixer.cpp index 505002a..32052c1 100644 --- a/Mixer.cpp +++ b/Mixer.cpp @@ -736,6 +736,12 @@ void Mixer::setView(View::Mode m) break; } + // selection might have to change + for (auto sit = session_->begin(); sit != session_->end(); sit++) { + if ( !current_view_->canSelect(*sit) ) + deselect( *sit ); + } + // need to deeply update view to apply eventual changes View::need_deep_update_++; diff --git a/SessionCreator.cpp b/SessionCreator.cpp index 246ef84..3b70823 100644 --- a/SessionCreator.cpp +++ b/SessionCreator.cpp @@ -447,6 +447,9 @@ void SessionLoader::visit (Source& s) XMLElement* sourceNode = xmlCurrent_; const char *pName = sourceNode->Attribute("name"); s.setName(pName); + bool l = false; + sourceNode->QueryBoolAttribute("locked", &l); + s.setLocked(l); xmlCurrent_ = sourceNode->FirstChildElement("Mixing"); if (xmlCurrent_) s.groupNode(View::MIXING)->accept(*this); diff --git a/SessionVisitor.cpp b/SessionVisitor.cpp index b2074a1..1b21076 100644 --- a/SessionVisitor.cpp +++ b/SessionVisitor.cpp @@ -342,6 +342,7 @@ void SessionVisitor::visit (Source& s) XMLElement *sourceNode = xmlDoc_->NewElement( "Source" ); sourceNode->SetAttribute("id", s.id()); sourceNode->SetAttribute("name", s.name().c_str() ); + sourceNode->SetAttribute("locked", s.locked() ); // insert into hierarchy xmlCurrent_->InsertFirstChild(sourceNode); diff --git a/Settings.cpp b/Settings.cpp index de767fe..290b10f 100644 --- a/Settings.cpp +++ b/Settings.cpp @@ -131,6 +131,7 @@ void Settings::Save() // save current view only if [mixing, geometry, layers, appearance] int v = application.current_view > 4 ? 1 : application.current_view; viewsNode->SetAttribute("current", v); + viewsNode->SetAttribute("workspace", application.current_workspace); map::iterator iter; for (iter=application.views.begin(); iter != application.views.end(); iter++) @@ -332,6 +333,7 @@ void Settings::Load() if (pElement) { pElement->QueryIntAttribute("current", &application.current_view); + pElement->QueryIntAttribute("workspace", &application.current_workspace); XMLElement* viewNode = pElement->FirstChildElement("View"); for( ; viewNode ; viewNode=viewNode->NextSiblingElement()) diff --git a/Settings.h b/Settings.h index 8d8560d..c0ea030 100644 --- a/Settings.h +++ b/Settings.h @@ -190,6 +190,7 @@ struct Application // Settings of Views int current_view; + int current_workspace; std::map views; // settings render @@ -221,6 +222,7 @@ struct Application action_history_follow_view = false; accept_connections = false; current_view = 1; + current_workspace= 1; windows = std::vector(3); windows[0].name = APP_NAME APP_TITLE; windows[0].w = 1600; diff --git a/Source.cpp b/Source.cpp index 083dc20..4f9017c 100644 --- a/Source.cpp +++ b/Source.cpp @@ -17,7 +17,7 @@ #include "Log.h" #include "Mixer.h" -Source::Source() : initialized_(false), active_(true), locked_(false), need_update_(true), symbol_(nullptr) +Source::Source() : initialized_(false), symbol_(nullptr), active_(true), locked_(false), need_update_(true), workspace_(STAGE) { // create unique id id_ = GlmToolkit::uniqueId(); @@ -178,21 +178,12 @@ Source::Source() : initialized_(false), active_(true), locked_(false), need_upda groups_[View::TRANSITION] = new Group; // - // shared locker symbol - // - locker_ = new Symbol(Symbol::LOCK, glm::vec3(0.8f, -0.8f, 0.01f)); - locker_->color = glm::vec4(1.f, 1.f, 1.f, 0.6f); - - // add semi transparent icon statically to mixing and layer views - Group *lockgroup = new Group; - lockgroup->translation_.z = 0.1; - lockgroup->attach( locker_ ); - groups_[View::LAYER]->attach(lockgroup); - groups_[View::MIXING]->attach(lockgroup); - - // add semi transparent icon dynamically with overlay - overlays_[View::LAYER]->attach( locker_ ); - overlays_[View::MIXING]->attach( locker_ ); + // locker switch button : locked / unlocked icons + locker_ = new Switch; + lock_ = new Handles(Handles::LOCKED); + locker_->attach(lock_); + unlock_ = new Handles(Handles::UNLOCKED); + locker_->attach(unlock_); // create objects stored_status_ = new Group; @@ -299,7 +290,7 @@ void Source::setMode(Source::Mode m) // show overlay if current bool current = m >= Source::CURRENT; for (auto o = overlays_.begin(); o != overlays_.end(); o++) - (*o).second->visible_ = current; + (*o).second->visible_ = current & !locked_; // show in appearance view if current groups_[View::APPEARANCE]->visible_ = m > Source::VISIBLE; @@ -389,6 +380,14 @@ void Source::attach(FrameBuffer *renderbuffer) if (groups_[View::TRANSITION]->numChildren() > 0) groups_[View::TRANSITION]->attach(mixingsurface_); + // hack to place the symbols in the corner independently of aspect ratio + symbol_->translation_.x += 0.1f * (renderbuffer_->aspectRatio()-1.f); + + // add lock icon to views (displayed on front) + groups_[View::LAYER]->attach( locker_ ); + groups_[View::MIXING]->attach( locker_ ); + groups_[View::GEOMETRY]->attach( locker_ ); + // scale all icon nodes to match aspect ratio for (int v = View::MIXING; v < View::INVALID; v++) { NodeSet::iterator node; @@ -398,10 +397,6 @@ void Source::attach(FrameBuffer *renderbuffer) } } - // hack to place the symbols in the corner independently of aspect ratio - symbol_->translation_.x += 0.1f * (renderbuffer_->aspectRatio()-1.f); - locker_->translation_.x += 0.1f * (renderbuffer_->aspectRatio()-1.f); - // (re) create the masking buffer if (maskbuffer_) delete maskbuffer_; @@ -430,27 +425,16 @@ void Source::setActive (bool on) groups_[View::RENDERING]->visible_ = active_; groups_[View::GEOMETRY]->visible_ = active_; groups_[View::LAYER]->visible_ = active_; - } void Source::setLocked (bool on) { locked_ = on; - // the lock icon is visible when locked - locker_->visible_ = on; - + // the lock icon + locker_->setActive( on ? 0 : 1); } -void Source::setFixed (bool on) -{ - fixed_ = on; - - groups_[View::GEOMETRY]->visible_ = !fixed_; - groups_[View::MIXING]->visible_ = !fixed_; -} - - // Transfer functions from coordinates to alpha (1 - transparency) float linear_(float x, float y) { return 1.f - CLAMP( sqrt( ( x * x ) + ( y * y ) ), 0.f, 1.f ); @@ -511,16 +495,18 @@ void Source::update(float dt) // Layers icons are displayed in Perspective (diagonal) groups_[View::LAYER]->translation_.y = groups_[View::LAYER]->translation_.x / LAYER_PERSPECTIVE; - // CHANGE lock based on range of layers stage - bool l = (groups_[View::LAYER]->translation_.x < -FOREGROUND_DEPTH) - || (groups_[View::LAYER]->translation_.x > -BACKGROUND_DEPTH); - setLocked( l ); - - // adjust position of layer icon: step up when on stage - if (groups_[View::LAYER]->translation_.x < -FOREGROUND_DEPTH) + // Update workspace based on depth, and + // adjust vertical position of icon depending on workspace + if (groups_[View::LAYER]->translation_.x < -FOREGROUND_DEPTH) { groups_[View::LAYER]->translation_.y -= 0.3f; - else if (groups_[View::LAYER]->translation_.x < -BACKGROUND_DEPTH) + workspace_ = Source::FOREGROUND; + } + else if (groups_[View::LAYER]->translation_.x < -BACKGROUND_DEPTH) { groups_[View::LAYER]->translation_.y -= 0.15f; + workspace_ = Source::STAGE; + } + else + workspace_ = Source::BACKGROUND; // MODIFY depth based on LAYER node groups_[View::MIXING]->translation_.z = groups_[View::LAYER]->translation_.z; diff --git a/Source.h b/Source.h index 78d1cbf..2c6968a 100644 --- a/Source.h +++ b/Source.h @@ -97,15 +97,19 @@ public: // update mode virtual void setActive (bool on); - inline bool active () { return active_; } + inline bool active () const { return active_; } // lock mode virtual void setLocked (bool on); - inline bool locked () { return locked_; } + inline bool locked () const { return locked_; } - // lock mode - virtual void setFixed (bool on); - inline bool fixed () { return fixed_; } + // Workspace + typedef enum { + BACKGROUND = 0, + STAGE = 1, + FOREGROUND = 2 + } Workspace; + inline Workspace workspace () const { return workspace_; } // a Source shall informs if the source failed (i.e. shall be deleted) virtual bool failed () const = 0; @@ -204,15 +208,17 @@ protected: std::map overlays_; std::map frames_; std::map handles_; - Symbol *symbol_, *locker_; + Handles *lock_, *unlock_; + Switch *locker_; + Symbol *symbol_; // update bool active_; bool locked_; - bool fixed_; bool need_update_; float dt_; Group *stored_status_; + Workspace workspace_; // clones CloneList clones_; diff --git a/View.cpp b/View.cpp index d6d2bae..cf3dc9c 100644 --- a/View.cpp +++ b/View.cpp @@ -197,9 +197,12 @@ void View::selectAll() Mixer::selection().clear(); for(auto sit = Mixer::manager().session()->begin(); sit != Mixer::manager().session()->end(); sit++) { - if ( (*sit)->active() ) + if (canSelect(*sit)) Mixer::selection().add(*sit); } + // special case of one single source in selection : make current after release + if (Mixer::selection().size() == 1) + Mixer::manager().setCurrentSource( Mixer::selection().front() ); } void View::select(glm::vec2 A, glm::vec2 B) @@ -212,25 +215,28 @@ void View::select(glm::vec2 A, glm::vec2 B) PickingVisitor pv(scene_point_A, scene_point_B); scene.accept(pv); - // reset selection - Mixer::selection().clear(); - // picking visitor found nodes in the area? if ( !pv.empty()) { // create a list of source matching the list of picked nodes SourceList selection; -// std::vector< std::pair > pick = pv.picked(); // loop over the nodes and add all sources found. -// for(std::vector< std::pair >::iterator p = pick.begin(); p != pick.end(); p++){ - for(std::vector< std::pair >::const_reverse_iterator p = pv.rbegin(); p != pv.rend(); p++){ + for(std::vector< std::pair >::const_reverse_iterator p = pv.rbegin(); p != pv.rend(); p++){ Source *s = Mixer::manager().findSource( p->first ); - if (s) + if (canSelect(s)) selection.push_back( s ); } // set the selection with list of picked (overlaped) sources Mixer::selection().set(selection); } + else + // reset selection + Mixer::selection().clear(); +} + +bool View::canSelect(Source *s) { + + return ( s!=nullptr && !s->locked() ); } @@ -355,81 +361,46 @@ void MixingView::centerSource(Source *s) } -void MixingView::select(glm::vec2 A, glm::vec2 B) -{ - // unproject mouse coordinate into scene coordinates - glm::vec3 scene_point_A = Rendering::manager().unProject(A); - glm::vec3 scene_point_B = Rendering::manager().unProject(B); - - // picking visitor traverses the scene - PickingVisitor pv(scene_point_A, scene_point_B); - scene.accept(pv); - - // reset selection - Mixer::selection().clear(); - - // picking visitor found nodes in the area? - if ( !pv.empty()) { - - // create a list of source matching the list of picked nodes - SourceList selection; - // loop over the nodes and add all sources found. - for(std::vector< std::pair >::const_reverse_iterator p = pv.rbegin(); p != pv.rend(); p++){ - Source *s = Mixer::manager().findSource( p->first ); - if (s && !s->locked()) - selection.push_back( s ); - } - // set the selection with list of picked (overlaped) sources - Mixer::selection().set(selection); - } -} - -void MixingView::selectAll() -{ - for(auto sit = Mixer::manager().session()->begin(); - sit != Mixer::manager().session()->end(); sit++) { - Mixer::selection().add(*sit); - } -} - void MixingView::update(float dt) { View::update(dt); - // a more complete update is requested - // for mixing, this means restore position of the fading slider - if (View::need_deep_update_ > 0) { + if (Mixer::manager().view() == this ) { + // a more complete update is requested + // for mixing, this means restore position of the fading slider + if (View::need_deep_update_ > 0) { - // - // Set slider to match the actual fading of the session - // - float f = Mixer::manager().session()->fading(); + // + // Set slider to match the actual fading of the session + // + float f = Mixer::manager().session()->fading(); - // reverse calculate angle from fading & move slider - slider_root_->rotation_.z = SIGN(slider_root_->rotation_.z) * asin(f) * 2.f; - - // visual feedback on mixing circle - f = 1.f - f; - mixingCircle_->shader()->color = glm::vec4(f, f, f, 1.f); - - } - else { - // - // Set session fading to match the slider angle - // - - // calculate fading from angle - float f = sin( ABS(slider_root_->rotation_.z) * 0.5f); - - // apply fading - if ( ABS_DIFF( f, Mixer::manager().session()->fading()) > EPSILON ) - { - // apply fading to session - Mixer::manager().session()->setFading(f); + // reverse calculate angle from fading & move slider + slider_root_->rotation_.z = SIGN(slider_root_->rotation_.z) * asin(f) * 2.f; // visual feedback on mixing circle f = 1.f - f; mixingCircle_->shader()->color = glm::vec4(f, f, f, 1.f); + + } + else { + // + // Set session fading to match the slider angle + // + + // calculate fading from angle + float f = sin( ABS(slider_root_->rotation_.z) * 0.5f); + + // apply fading + if ( ABS_DIFF( f, Mixer::manager().session()->fading()) > EPSILON ) + { + // apply fading to session + Mixer::manager().session()->setFading(f); + + // visual feedback on mixing circle + f = 1.f - f; + mixingCircle_->shader()->color = glm::vec4(f, f, f, 1.f); + } } } @@ -463,8 +434,19 @@ std::pair MixingView::pick(glm::vec2 P) else { // get if a source was picked Source *s = Mixer::manager().findSource(pick.first); - if (s != nullptr && s->locked()) { - if ( !UserInterface::manager().ctrlModifier() ) + if (s != nullptr) { + // pick on the lock icon; unlock source + if ( pick.first == s->lock_) { + s->setLocked(false); + pick = { s->locker_, pick.second }; + } + // pick on the open lock icon; lock source and cancel pick + else if ( pick.first == s->unlock_ ) { + s->setLocked(true); + pick = { nullptr, glm::vec2(0.f) }; + } + // pick a locked source without CTRL key; cancel pick + else if ( s->locked() && !UserInterface::manager().ctrlModifier() ) pick = { nullptr, glm::vec2(0.f) }; } } @@ -681,6 +663,11 @@ RenderView::~RenderView() delete fading_overlay_; } +bool RenderView::canSelect(Source *s) { + + return false; +} + void RenderView::setFading(float f) { if (fading_overlay_ == nullptr) @@ -921,34 +908,83 @@ void GeometryView::draw() } } - // draw scene of this view - View::draw(); + // Drawing of Geometry view is different as it renders + // only sources in the current workspace + std::vector surfaces; + std::vector overlays; + for (auto source_iter = Mixer::manager().session()->begin(); + source_iter != Mixer::manager().session()->end(); source_iter++) { + // if it is in the current workspace + if ((*source_iter)->workspace() == Settings::application.current_workspace) { + // will draw its surface + surfaces.push_back((*source_iter)->groups_[mode_]); + // will draw its frame and locker icon + overlays.push_back((*source_iter)->frames_[mode_]); + overlays.push_back((*source_iter)->locker_); + } + } + // 0. prepare projection for draw visitors glm::mat4 projection = Rendering::manager().Projection(); - // draw scene rendered on top + // 1. Draw surface of sources in the current workspace + DrawVisitor draw_surfaces(surfaces, projection); + scene.accept(draw_surfaces); + + // 2. Draw scene rendering on top (which includes rendering of all visible sources) DrawVisitor draw_rendering(output_surface_, projection, true); scene.accept(draw_rendering); - // re-draw frames of all sources on top - // (otherwise hidden in stack of sources) - for (auto source_iter = Mixer::manager().session()->begin(); - source_iter != Mixer::manager().session()->end(); source_iter++) { - DrawVisitor dv((*source_iter)->frames_[mode_], projection); - scene.accept(dv); - } + // 3. Draw frames and icons of sources in the current workspace + DrawVisitor draw_overlays(overlays, projection); + scene.accept(draw_overlays); - // re-draw overlay of current source on top - // (allows manipulation current source even when hidden below others) - if (s != nullptr) { + // 4. Draw control overlays of current source on top (if selectable) + if (canSelect(s)) { s->setMode(Source::CURRENT); DrawVisitor dv(s->overlays_[mode_], projection); scene.accept(dv); } - // draw overlays of view - DrawVisitor draw_overlay(scene.fg(), projection); - scene.accept(draw_overlay); + // 5. Finally, draw overlays of view + DrawVisitor draw_foreground(scene.fg(), projection); + scene.accept(draw_foreground); + + // display interface + glm::vec2 P = glm::vec2(-output_surface_->scale_.x - 0.02f, output_surface_->scale_.y + 0.01 ); + P = Rendering::manager().project(glm::vec3(P, 0.f), scene.root()->transform_, false); + ImGui::SetNextWindowPos(ImVec2(P.x, P.y - 70.f ), ImGuiCond_Always); + if (ImGui::Begin("##GeometryViewOptions", NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBackground + | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings + | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBringToFrontOnFocus )) + { + // style grey + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(COLOR_FRAME_LIGHT, 0.98f)); // 1 + ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0.14f, 0.14f, 0.14f, 0.84f)); + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.14f, 0.14f, 0.14f, 0.00f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(0.24f, 0.24f, 0.24f, 0.46f)); + ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.85f, 0.85f, 0.85f, 0.86f)); + ImGui::PushStyleColor(ImGuiCol_SliderGrabActive, ImVec4(0.95f, 0.95f, 0.95f, 1.00f)); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.00f, 0.00f, 0.00f, 0.00f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.24f, 0.24f, 0.24f, 0.46f)); + ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.67f, 0.67f, 0.67f, 0.79f)); + ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.36f, 0.36f, 0.36f, 0.44f)); + ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.88f, 0.88f, 0.88f, 0.73f)); + ImGui::PushStyleColor(ImGuiCol_Tab, ImVec4(0.83f, 0.83f, 0.84f, 0.78f)); + ImGui::PushStyleColor(ImGuiCol_TabHovered, ImVec4(0.53f, 0.53f, 0.53f, 0.60f)); + ImGui::PushStyleColor(ImGuiCol_TabActive, ImVec4(0.40f, 0.40f, 0.40f, 1.00f)); // 14 colors + // large display + ImGuiToolkit::PushFont(ImGuiToolkit::FONT_LARGE); + + static std::vector< std::pair > icons_ws = { {10,16}, {11,16}, {12,16} }; + if ( ImGuiToolkit::ComboIcon (icons_ws, &Settings::application.current_workspace) ){ + View::need_deep_update_++; + } + + ImGui::PopFont(); + ImGui::PopStyleColor(14); // 14 colors + ImGui::End(); + } // display popup menu if (show_context_menu_) { @@ -975,14 +1011,14 @@ std::pair GeometryView::pick(glm::vec2 P) // picking visitor found nodes? if ( !pv.empty() ) { // keep current source active if it is clicked - Source *s = Mixer::manager().currentSource(); - if (s != nullptr) { + Source *current = Mixer::manager().currentSource(); + if (current != nullptr) { // find if the current source was picked auto itp = pv.rbegin(); for (; itp != pv.rend(); itp++){ // test if source contains this node Source::hasNode is_in_source((*itp).first ); - if ( is_in_source( s ) ){ + if ( is_in_source( current ) ){ // a node in the current source was clicked ! pick = *itp; break; @@ -990,23 +1026,66 @@ std::pair GeometryView::pick(glm::vec2 P) } // not found: the current source was not clicked if (itp == pv.rend()) - s = nullptr; - // picking on the menu handle - else if ( pick.first == s->handles_[mode_][Handles::MENU] ) { - // show context menu + current = nullptr; + // picking on the menu handle: show context menu + else if ( pick.first == current->handles_[mode_][Handles::MENU] ) { show_context_menu_ = true; } + // pick on the lock icon; unlock source + else if ( pick.first == current->lock_ ) { + current->setLocked(false); + } + // pick on the open lock icon; lock source and cancel pick + else if ( pick.first == current->unlock_ ) { + current->setLocked(true); + pick = { nullptr, glm::vec2(0.f) }; + } + // pick a locked source without CTRL key; cancel pick + else if ( current->locked() && !UserInterface::manager().ctrlModifier() ) { + pick = { nullptr, glm::vec2(0.f) }; + } } // the clicked source changed (not the current source) - if (s == nullptr) { - // select top-most Node picked - pick = pv.back(); + if (current == nullptr){ + + // default to failed pick + pick = { nullptr, glm::vec2(0.f) }; + + // loop over all nodes picked + for (auto itp = pv.rbegin(); itp != pv.rend(); itp++){ + + // get if a source was picked + Source *s = Mixer::manager().findSource((*itp).first); + + // accept picked sources in current workspaces + if ( s!=nullptr && s->workspace() == Settings::application.current_workspace) { + + // lock icon of a source is picked : unlock + if ( (*itp).first == s->lock_) { + s->setLocked(false); + pick = { s->locker_, (*itp).second }; + break; + } + // a non-locked source is picked (or locked with CTRL key) + else if ( !s->locked() || ( s->locked() && UserInterface::manager().ctrlModifier() ) ) { + pick = { s->locker_, (*itp).second }; + break; + } + } + + } + } } return pick; } +bool GeometryView::canSelect(Source *s) { + + return ( View::canSelect(s) && s->active() && s->workspace() == Settings::application.current_workspace); +} + View::Cursor GeometryView::grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair pick) { View::Cursor ret = Cursor(); @@ -1418,7 +1497,6 @@ void GeometryView::terminate() } - void GeometryView::arrow (glm::vec2 movement) { Source *s = Mixer::manager().currentSource(); @@ -1466,12 +1544,6 @@ LayerView::LayerView() : View(LAYER), aspect_ratio(1.f) frame_->attach(border); scene.bg()->attach(frame_); -// persp_layer_ = new Mesh("mesh/perspective_layer.ply"); -// persp_layer_->shader()->color = glm::vec4( COLOR_FRAME, 0.8f ); -// persp_layer_->scale_.x = LAYER_PERSPECTIVE; -// persp_layer_->translation_.z = -0.1f; -// scene.bg()->attach(persp_layer_); - persp_left_ = new Mesh("mesh/perspective_axis_left.ply"); persp_left_->shader()->color = glm::vec4( COLOR_FRAME_LIGHT, 0.9f ); persp_left_->scale_.x = LAYER_PERSPECTIVE; @@ -1483,6 +1555,8 @@ LayerView::LayerView() : View(LAYER), aspect_ratio(1.f) persp_right_->scale_.x = LAYER_PERSPECTIVE; persp_right_->translation_.z = -0.1f; scene.bg()->attach(persp_right_); + + } void LayerView::update(float dt) @@ -1495,22 +1569,20 @@ void LayerView::update(float dt) // update rendering of render frame FrameBuffer *output = Mixer::manager().session()->frame(); if (output){ + // correct with aspect ratio aspect_ratio = output->aspectRatio(); frame_->scale_.x = aspect_ratio; - persp_left_->translation_.x = -aspect_ratio; persp_right_->translation_.x = aspect_ratio + 0.06; -// for (NodeSet::iterator node = scene.bg()->begin(); node != scene.bg()->end(); node++) { -// (*node)->scale_.x = aspect_ratio; -// } -// for (NodeSet::iterator node = scene.fg()->begin(); node != scene.fg()->end(); node++) { -// (*node)->scale_.x = aspect_ratio; -// } -// } } } +bool LayerView::canSelect(Source *s) { + + return ( View::canSelect(s) && s->active() ); +} + void LayerView::resize ( int scale ) { float z = CLAMP(0.01f * (float) scale, 0.f, 1.f); @@ -1532,6 +1604,35 @@ int LayerView::size () return (int) ( sqrt(z) * 100.f); } + +std::pair LayerView::pick(glm::vec2 P) +{ + // get picking from generic View + std::pair pick = View::pick(P); + + + // get if a source was picked + Source *s = Mixer::manager().findSource(pick.first); + if (s != nullptr) { + // pick on the lock icon; unlock source + if ( pick.first == s->lock_) { + s->setLocked(false); + pick = { s->locker_, pick.second }; + } + // pick on the open lock icon; lock source and cancel pick + else if ( pick.first == s->unlock_ ) { + s->setLocked(true); + pick = { nullptr, glm::vec2(0.f) }; + } + // pick a locked source without CTRL key; cancel pick + else if ( s->locked() && !UserInterface::manager().ctrlModifier() ) + pick = { nullptr, glm::vec2(0.f) }; + } + + return pick; +} + + float LayerView::setDepth(Source *s, float d) { if (!s) @@ -1592,7 +1693,7 @@ View::Cursor LayerView::grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair std::ostringstream info; info << "Depth " << std::fixed << std::setprecision(2) << d << " "; - info << (s->locked() ? ICON_FA_LOCK : ICON_FA_LOCK_OPEN); +// info << (s->locked() ? ICON_FA_LOCK : ICON_FA_LOCK_OPEN); // TODO static not locked // store action in history current_action_ = s->name() + ": " + info.str(); @@ -1694,6 +1795,7 @@ void TransitionView::update(float dt) } output_surface_->setTextureIndex( output->texture() ); } + } // Update transition source @@ -1790,10 +1892,9 @@ void TransitionView::draw() } -void TransitionView::selectAll() -{ - Mixer::selection().clear(); - Mixer::selection().add(transition_source_); +bool TransitionView::canSelect(Source *s) { + + return ( s!=nullptr && s == transition_source_); } void TransitionView::attach(SessionSource *ts) @@ -1839,6 +1940,8 @@ Session *TransitionView::detach() // detatch the session and return it ret = transition_source_->detach(); + Mixer::manager().setCurrentSource(transition_source_); + // done with transition transition_source_ = nullptr; } @@ -2039,23 +2142,6 @@ AppearanceView::AppearanceView() : View(APPEARANCE), edit_source_(nullptr), need mask_node_->attach(mask_vertical_); scene.fg()->attach(mask_node_); - // horizontal_mark_ = new Mesh("mesh/h_mark.ply"); - // horizontal_mark_->translation_ = glm::vec3(0.f, 1.12f, 0.0f); - // horizontal_mark_->scale_ = glm::vec3(2.5f, -2.5f, 0.0f); - // horizontal_mark_->shader()->color = glm::vec4( COLOR_TRANSITION_LINES, 0.9f ); - //// scene.bg()->attach(horizontal_mark_); - // // vertical axis - // vertical_line_ = new Group; - // Mesh *line = new Mesh("mesh/h_line.ply"); - // line->shader()->color = glm::vec4( COLOR_TRANSITION_LINES, 0.9f ); - // line->translation_ = glm::vec3(-0.12f, 0.0f, 0.0f); - // line->scale_.x = 1.0f; - // line->scale_.y = 3.0f; - // line->rotation_.z = M_PI_2; - //// vertical_line_->attach(line); - - - // Source manipulation (texture coordinates) // // point to show POSITION @@ -2159,8 +2245,9 @@ void AppearanceView::update(float dt) View::update(dt); // a more complete update is requested (e.g. after switching to view) - if (View::need_deep_update_ > 0 || edit_source_ != Mixer::manager().currentSource()) + if (View::need_deep_update_ > 0 || edit_source_ != Mixer::manager().currentSource()) { need_edit_update_ = true; + } } @@ -2184,12 +2271,6 @@ int AppearanceView::size () return (int) ( sqrt(z) * 100.f); } - -void AppearanceView::selectAll() -{ - Mixer::manager().setCurrentSource( getEditOrCurrentSource() ); -} - void AppearanceView::select(glm::vec2 A, glm::vec2 B) { // unproject mouse coordinate into scene coordinates @@ -2197,21 +2278,32 @@ void AppearanceView::select(glm::vec2 A, glm::vec2 B) glm::vec3 scene_point_B = Rendering::manager().unProject(B); // picking visitor traverses the scene - PickingVisitor pv(scene_point_A, scene_point_B, true); + PickingVisitor pv(scene_point_A, scene_point_B, true); // here is the difference scene.accept(pv); // picking visitor found nodes in the area? if ( !pv.empty()) { - // loop over sources matching the list of picked nodes - for(std::vector< std::pair >::const_reverse_iterator p = pv.rbegin(); p != pv.rend(); p++){ + + // create a list of source matching the list of picked nodes + SourceList selection; + // loop over the nodes and add all sources found. + for(std::vector< std::pair >::const_reverse_iterator p = pv.rbegin(); p != pv.rend(); p++){ Source *s = Mixer::manager().findSource( p->first ); - // set the edit source as current if selected - if (s != nullptr && s == edit_source_) - Mixer::manager().setCurrentSource( s ); + if (canSelect(s)) + selection.push_back( s ); } + // set the selection with list of picked (overlaped) sources + Mixer::selection().set(selection); } + else + // reset selection + Mixer::selection().clear(); } +bool AppearanceView::canSelect(Source *s) { + + return ( s!=nullptr && ( s == Mixer::manager().currentSource() || s == edit_source_ )); +} View::Cursor AppearanceView::over (glm::vec2 pos) { @@ -2252,7 +2344,7 @@ View::Cursor AppearanceView::over (glm::vec2 pos) } } } - // show crup cursor + // show crop cursor else if (edit_source_->maskShader()->mode == MaskShader::SHAPE) { if (mask_cursor_shape_ > 0) { mask_cursor_crop_->visible_ = true; @@ -2470,6 +2562,23 @@ void AppearanceView::draw() | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBringToFrontOnFocus )) { + + // style grey + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.00f, 1.00f, 1.00f, 0.98f)); // 1 + ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0.14f, 0.14f, 0.14f, 0.84f)); + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.14f, 0.14f, 0.14f, 0.00f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(0.24f, 0.24f, 0.24f, 0.46f)); + ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.85f, 0.85f, 0.85f, 0.86f)); + ImGui::PushStyleColor(ImGuiCol_SliderGrabActive, ImVec4(0.95f, 0.95f, 0.95f, 1.00f)); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.00f, 0.00f, 0.00f, 0.00f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.24f, 0.24f, 0.24f, 0.46f)); + ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.67f, 0.67f, 0.67f, 0.79f)); + ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.36f, 0.36f, 0.36f, 0.44f)); + ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.88f, 0.88f, 0.88f, 0.73f)); + ImGui::PushStyleColor(ImGuiCol_Tab, ImVec4(0.83f, 0.83f, 0.84f, 0.78f)); + ImGui::PushStyleColor(ImGuiCol_TabHovered, ImVec4(0.53f, 0.53f, 0.53f, 0.60f)); + ImGui::PushStyleColor(ImGuiCol_TabActive, ImVec4(0.40f, 0.40f, 0.40f, 1.00f)); // 14 colors + // large display ImGuiToolkit::PushFont(ImGuiToolkit::FONT_LARGE); int mode = edit_source_->maskShader()->mode; @@ -2537,7 +2646,7 @@ void AppearanceView::draw() ImGui::SameLine(); show_cursor_forced_ = false; - if (ImGui::Button(ICON_FA_DOT_CIRCLE)) + if (ImGui::Button(ICON_FA_DOT_CIRCLE ICON_FA_SORT_DOWN )) ImGui::OpenPopup("brush_size_popup"); if (ImGui::BeginPopup("brush_size_popup", ImGuiWindowFlags_NoMove)) { @@ -2567,7 +2676,7 @@ void AppearanceView::draw() mask_cursor_square_->scale_ = glm::vec3(s * 1.75f, 1.f); ImGui::SameLine(); - if (ImGui::Button(ICON_FA_FEATHER_ALT)) + if (ImGui::Button(ICON_FA_FEATHER_ALT ICON_FA_SORT_DOWN )) ImGui::OpenPopup("brush_pressure_popup"); if (ImGui::BeginPopup("brush_pressure_popup", ImGuiWindowFlags_NoMove)) { @@ -2588,7 +2697,7 @@ void AppearanceView::draw() ImGui::SameLine(0, 60); edit_source_->maskShader()->effect = 0; - if (ImGui::Button(ICON_FA_MAGIC)) + if (ImGui::Button(ICON_FA_MAGIC ICON_FA_SORT_DOWN )) ImGui::OpenPopup( "brush_menu_popup" ); if (ImGui::BeginPopup( "brush_menu_popup" )) { @@ -2679,7 +2788,7 @@ void AppearanceView::draw() } ImGui::SameLine(0, 20); - if (ImGui::Button(ICON_FA_RADIATION_ALT)) + if (ImGui::Button(ICON_FA_RADIATION_ALT ICON_FA_SORT_DOWN )) ImGui::OpenPopup("shape_smooth_popup"); if (ImGui::BeginPopup("shape_smooth_popup", ImGuiWindowFlags_NoMove)) { @@ -2733,6 +2842,7 @@ void AppearanceView::draw() } ImGui::PopFont(); + ImGui::PopStyleColor(14); // 14 colors ImGui::End(); } diff --git a/View.h b/View.h index 95430af..db04f84 100644 --- a/View.h +++ b/View.h @@ -60,6 +60,7 @@ public: // select sources provided a start and end selection points in screen coordinates virtual void select(glm::vec2, glm::vec2); virtual void selectAll(); + virtual bool canSelect(Source *); // drag the view provided a start and an end point in screen coordinates virtual Cursor drag (glm::vec2, glm::vec2); @@ -106,8 +107,6 @@ public: void resize (int) override; int size () override; void centerSource(Source *) override; - void select(glm::vec2, glm::vec2) override; - void selectAll() override; std::pair pick(glm::vec2) override; Cursor grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair) override; @@ -139,6 +138,7 @@ public: ~RenderView (); void draw () override; + bool canSelect(Source *) override; void setResolution (glm::vec3 resolution = glm::vec3(0.f)); glm::vec3 resolution() const { return frame_buffer_->resolution(); } @@ -158,6 +158,7 @@ public: void update (float dt) override; void resize (int) override; int size () override; + bool canSelect(Source *) override; std::pair pick(glm::vec2 P) override; Cursor grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair pick) override; @@ -177,6 +178,7 @@ private: Node *overlay_scaling_grid_; Node *overlay_crop_; bool show_context_menu_; + }; class LayerView : public View @@ -187,7 +189,9 @@ public: void update (float dt) override; void resize (int) override; int size () override; + bool canSelect(Source *) override; + std::pair pick(glm::vec2) override; Cursor grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair pick) override; void arrow (glm::vec2) override; @@ -208,7 +212,7 @@ public: void draw () override; void update (float dt) override; void zoom (float factor) override; - void selectAll() override; + bool canSelect(Source *) override; std::pair pick(glm::vec2 P) override; Cursor grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair pick) override; @@ -232,14 +236,12 @@ class AppearanceView : public View public: AppearanceView(); - void select(glm::vec2, glm::vec2) override; - void selectAll() override; - void draw () override; - void update (float dt) override; void resize (int) override; int size () override; + bool canSelect(Source *) override; + void select(glm::vec2 A, glm::vec2 B) override; std::pair pick(glm::vec2 P) override; Cursor grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair pick) override;