diff --git a/src/gui/widgets/timeline/timeline-header-container.cpp b/src/gui/widgets/timeline/timeline-header-container.cpp index 1db3aa3f0..78a479412 100644 --- a/src/gui/widgets/timeline/timeline-header-container.cpp +++ b/src/gui/widgets/timeline/timeline-header-container.cpp @@ -149,12 +149,17 @@ bool TimelineHeaderContainer::on_button_press_event ( { case 1: // Left Click // Did the user press the button on an expander? - if(hoveringExpander != NULL) + if(hoveringExpander) { // Yes? The prime for a release event clickedExpander = hoveringExpander; queue_draw(); } + else if(hoveringTrack) // Is the user hovering on a track + { + + } + break; case 3: // Right Click @@ -186,6 +191,8 @@ bool TimelineHeaderContainer::on_button_press_event ( bool TimelineHeaderContainer::on_button_release_event ( GdkEventButton* event) { + TimelineLayoutHelper &layout = timelineWidget.layoutHelper; + // Did the user release the button on an expander? if(clickedExpander != NULL) { @@ -194,8 +201,12 @@ bool TimelineHeaderContainer::on_button_release_event ( clickedExpander->get_expanded() ? Track::Collapse : Track::Expand); clickedExpander.reset(); - timelineWidget.layoutHelper.update_layout(); + layout.update_layout(); } + + // Has the user been dragging? + if(layout.get_dragging_track()) + layout.end_dragging_track(); return Container::on_button_release_event(event); } @@ -204,31 +215,50 @@ bool TimelineHeaderContainer::on_motion_notify_event ( GdkEventMotion* event) { REQUIRE(event != NULL); - - // Hit test the rectangle - shared_ptr header = - timelineWidget.layoutHelper.header_from_point( - Gdk::Point(event->x, event->y)); - if(header) - { - const optional rect = - get_expander_button_rectangle(header); + const bool result = Container::on_motion_notify_event(event); + + const Gdk::Point point(event->x, event->y); + TimelineLayoutHelper &layout = timelineWidget.layoutHelper; + + // Are we beginning to drag a header? + if((event->state & GDK_BUTTON1_MASK) && hoveringTrack && + !hoveringExpander && !layout.get_dragging_track()) + { + layout.begin_dragging_track(hoveringTrack); + return result; + } - REQUIRE(rect); + // Are we currently dragging? + if(layout.get_dragging_track()) + { + layout.drag_to_point(point); + return result; + } + + // Hit test the rectangle + hoveringTrack = layout.header_from_point(point); + + if(hoveringTrack) + { + const optional rect = + get_expander_button_rectangle(hoveringTrack); + + REQUIRE(rect); - // Are we hovering on the expander? - if(event->x >= rect->get_x() && - event->x < rect->get_x() + rect->get_width() && - event->y >= rect->get_y() && - event->y < rect->get_y() + rect->get_height()) - { - hoveringExpander = header; - queue_draw(); - } - } + // Are we hovering on the expander? + if(event->x >= rect->get_x() && + event->x < rect->get_x() + rect->get_width() && + event->y >= rect->get_y() && + event->y < rect->get_y() + rect->get_height()) + { + hoveringExpander = hoveringTrack; + queue_draw(); + } + else hoveringExpander.reset(); + } - return Container::on_motion_notify_event(event); + return result; } void diff --git a/src/gui/widgets/timeline/timeline-header-container.hpp b/src/gui/widgets/timeline/timeline-header-container.hpp index 567d195c5..0f851cd53 100644 --- a/src/gui/widgets/timeline/timeline-header-container.hpp +++ b/src/gui/widgets/timeline/timeline-header-container.hpp @@ -221,6 +221,8 @@ private: Gtk::Menu contextMenu; //----- User Interaction State -----// + boost::shared_ptr hoveringTrack; + boost::shared_ptr hoveringExpander; boost::shared_ptr clickedExpander; diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index aec2e0a61..e82f8f422 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -132,6 +132,71 @@ TimelineLayoutHelper::track_from_y(int y) return shared_ptr(); } +void +TimelineLayoutHelper::begin_dragging_track( + boost::shared_ptr track) +{ + REQUIRE(track); + draggingTrack = track; + g_message("begin_dragging_track"); + + // Find the track in the tree + const shared_ptr model_track = track->get_model_track(); + REQUIRE(model_track); + for(draggingTrackIter = layoutTree.begin(); + draggingTrackIter != layoutTree.end(); + draggingTrackIter++) + { + if(*draggingTrackIter == model_track) + break; + } +} + +void +TimelineLayoutHelper::end_dragging_track() +{ + draggingTrack.reset(); + clone_tree_from_sequence(); + update_layout(); +} + +boost::shared_ptr +TimelineLayoutHelper::get_dragging_track() const +{ + return draggingTrack; +} + +void +TimelineLayoutHelper::drag_to_point(Gdk::Point point) +{ + // Apply the scroll offset + point.set_y(point.get_y() + timelineWidget.get_y_scroll_offset()); + + // Search the headers + TrackTree::pre_order_iterator iterator; + for(iterator = ++layoutTree.begin(); // ++ so we miss out the root sequence + iterator != layoutTree.end(); + iterator++) + { + // Hit test the rectangle + const weak_ptr track = + lookup_timeline_track(*iterator); + const Gdk::Rectangle &rect = headerBoxes[track]; + + if(point.get_x() >= rect.get_x() && + point.get_x() < rect.get_x() + rect.get_width() && + point.get_y() >= rect.get_y() && + point.get_y() < rect.get_y() + rect.get_height()) + { + // Relocate the header + draggingTrackIter = layoutTree.move_after( + iterator, draggingTrackIter); + update_layout(); + return; + } + } +} + int TimelineLayoutHelper::get_total_height() const { diff --git a/src/gui/widgets/timeline/timeline-layout-helper.hpp b/src/gui/widgets/timeline/timeline-layout-helper.hpp index e533babb4..da585f356 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.hpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.hpp @@ -127,6 +127,14 @@ public: **/ boost::shared_ptr track_from_y(int y); + void begin_dragging_track(boost::shared_ptr track); + + void end_dragging_track(); + + boost::shared_ptr get_dragging_track() const; + + void drag_to_point(Gdk::Point point); + /** * Returns the total height in pixels of the layout tree. * @remarks This function is only on returns a valid value fter @@ -228,6 +236,10 @@ protected: **/ int totalHeight; + TrackTree::pre_order_iterator draggingTrackIter; + + boost::shared_ptr draggingTrack; + /** * The connection to the animation timer. * @see begin_animation()