diff --git a/src/gui/model/parent-track.cpp b/src/gui/model/parent-track.cpp index 612e112d7..6aec58e8a 100644 --- a/src/gui/model/parent-track.cpp +++ b/src/gui/model/parent-track.cpp @@ -42,6 +42,12 @@ ParentTrack::get_child_track_list() return tracks; } +bool +ParentTrack::can_host_children() const +{ + return true; +} + bool ParentTrack::remove_child_track(const boost::shared_ptr track) { diff --git a/src/gui/model/parent-track.hpp b/src/gui/model/parent-track.hpp index a895b3427..ecc084e4b 100644 --- a/src/gui/model/parent-track.hpp +++ b/src/gui/model/parent-track.hpp @@ -46,6 +46,8 @@ public: lumiera::observable_list< boost::shared_ptr >& get_child_track_list(); + bool can_host_children() const; + bool remove_child_track(const boost::shared_ptr track); protected: diff --git a/src/gui/model/track.cpp b/src/gui/model/track.cpp index 50d50e4b8..d13e698e1 100644 --- a/src/gui/model/track.cpp +++ b/src/gui/model/track.cpp @@ -52,7 +52,13 @@ Track::set_name(const std::string &name) } bool -Track::remove_child_track(const boost::shared_ptr track) +Track::can_host_children() const +{ + return false; +} + +bool +Track::remove_child_track(const boost::shared_ptr /*track*/) { return false; } diff --git a/src/gui/model/track.hpp b/src/gui/model/track.hpp index 42c6e890b..300e0f9b8 100644 --- a/src/gui/model/track.hpp +++ b/src/gui/model/track.hpp @@ -45,6 +45,8 @@ public: void set_name(const std::string &name); + virtual bool can_host_children() const; + virtual bool remove_child_track(const boost::shared_ptr track); std::string print_branch(); diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index f90633e97..6b772b0a8 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -33,6 +33,7 @@ using namespace std; using namespace boost; using namespace lumiera; using namespace util; +using namespace gui::util; namespace gui { namespace widgets { @@ -178,23 +179,78 @@ TimelineLayoutHelper::drag_to_point(const Gdk::Point &point) // Search the headers TrackTree::pre_order_iterator iterator; - for(iterator = ++layoutTree.begin(); // ++ so we miss out the root sequence + + for(iterator = ++layoutTree.begin(); iterator != layoutTree.end(); iterator++) - { - // Hit test the rectangle - const weak_ptr track = - lookup_timeline_track(*iterator); - - if(util::pt_in_rect(dragPoint, headerBoxes[track])) + { + // Skip the dragging branch + if(iterator == draggingTrackIter) { - // Relocate the header - draggingTrackIter = layoutTree.move_after( + iterator.skip_children(); + continue; + } + + // Get the rectangle and the next rectangle + const shared_ptr model_track(*iterator); + REQUIRE(model_track); + const weak_ptr timeline_track = + lookup_timeline_track(model_track); + const Gdk::Rectangle &rect = headerBoxes[timeline_track]; + const int half_height = rect.get_height() / 2; + const int y = rect.get_y(); + const int y_mid = y + half_height; + const int full_width = TimelineWidget::HeaderWidth; + const int x_mid = rect.get_x() + rect.get_width() / 2; + + // Is our track being dragged before this header? + if(pt_in_rect(dragPoint, + Gdk::Rectangle(0, y, full_width, half_height))) + { + draggingTrackIter = layoutTree.move_before( iterator, draggingTrackIter); - update_layout(); - return; + break; + } + + if(model_track->can_host_children() && + model_track->get_child_tracks().empty()) + { + // Is our track being dragged after this header? + if(pt_in_rect(dragPoint, + Gdk::Rectangle(0, y_mid, x_mid, half_height))) + { + draggingTrackIter = layoutTree.move_after( + iterator, draggingTrackIter); + break; + } + else if(pt_in_rect(dragPoint, + Gdk::Rectangle(x_mid, y_mid, + full_width - x_mid, half_height))) + { + // Insert a place-holder in the tree + const TrackTree::pre_order_iterator placeholder = + layoutTree.append_child( + iterator, shared_ptr()); + + // Replace it with the relocated branch + draggingTrackIter = layoutTree.move_ontop( + placeholder, draggingTrackIter); + break; + } + } + else + { + if(pt_in_rect(dragPoint, + Gdk::Rectangle(0, y_mid, full_width, half_height))) + { + draggingTrackIter = layoutTree.move_after( + iterator, draggingTrackIter); + break; + } } } + + update_layout(); } int