Initial drop code added
This commit is contained in:
parent
f18c039074
commit
69253909e3
8 changed files with 228 additions and 59 deletions
|
|
@ -72,6 +72,25 @@ Track::print_branch()
|
|||
return print_branch_recursive(0);
|
||||
}
|
||||
|
||||
shared_ptr<Track>
|
||||
Track::find_parent(shared_ptr<Track> root, shared_ptr<Track> child)
|
||||
{
|
||||
REQUIRE(root != NULL);
|
||||
REQUIRE(child != NULL);
|
||||
const list< shared_ptr<Track> > children = root->get_child_tracks();
|
||||
BOOST_FOREACH(shared_ptr<Track> track, children)
|
||||
{
|
||||
if(track == child)
|
||||
return root;
|
||||
|
||||
shared_ptr<Track> result = find_parent(track, child);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
|
||||
return shared_ptr<Track>();
|
||||
}
|
||||
|
||||
string
|
||||
Track::print_branch_recursive(const unsigned int indentation)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -53,7 +53,9 @@ public:
|
|||
|
||||
virtual std::string print_track() = 0;
|
||||
|
||||
|
||||
static boost::shared_ptr<Track>
|
||||
find_parent(boost::shared_ptr<Track> root,
|
||||
boost::shared_ptr<Track> child);
|
||||
|
||||
protected:
|
||||
std::string print_branch_recursive(const unsigned int indentation);
|
||||
|
|
|
|||
|
|
@ -54,7 +54,8 @@ TimelineWidget::TimelineWidget(
|
|||
horizontalAdjustment(0, 0, 0),
|
||||
verticalAdjustment(0, 0, 0),
|
||||
horizontalScroll(horizontalAdjustment),
|
||||
verticalScroll(verticalAdjustment)
|
||||
verticalScroll(verticalAdjustment),
|
||||
update_tracks_frozen(false)
|
||||
{
|
||||
REQUIRE(sequence);
|
||||
|
||||
|
|
@ -288,6 +289,9 @@ TimelineWidget::on_add_track_command()
|
|||
void
|
||||
TimelineWidget::update_tracks()
|
||||
{
|
||||
if(update_tracks_frozen)
|
||||
return;
|
||||
|
||||
REQUIRE(sequence);
|
||||
|
||||
// Remove any tracks which are no longer present in the model
|
||||
|
|
@ -301,6 +305,18 @@ TimelineWidget::update_tracks()
|
|||
layoutHelper.update_layout();
|
||||
}
|
||||
|
||||
void
|
||||
TimelineWidget::freeze_update_tracks()
|
||||
{
|
||||
update_tracks_frozen = true;
|
||||
}
|
||||
|
||||
void
|
||||
TimelineWidget::thaw_update_tracks()
|
||||
{
|
||||
update_tracks_frozen = false;
|
||||
}
|
||||
|
||||
void
|
||||
TimelineWidget::create_timeline_tracks()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -171,6 +171,10 @@ private:
|
|||
**/
|
||||
void update_tracks();
|
||||
|
||||
void freeze_update_tracks();
|
||||
|
||||
void thaw_update_tracks();
|
||||
|
||||
/**
|
||||
* Ensures timeline UI tracks have been created for every model track
|
||||
* present in sequence.
|
||||
|
|
@ -297,6 +301,8 @@ protected:
|
|||
sigc::signal<void> playbackPeriodDragReleasedSignal;
|
||||
sigc::signal<void, boost::shared_ptr<timeline::Track> >
|
||||
hoveringTrackChangedSignal;
|
||||
|
||||
bool update_tracks_frozen;
|
||||
|
||||
/* ===== Constants ===== */
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -411,13 +411,13 @@ TimelineHeaderContainer::begin_drag()
|
|||
}
|
||||
|
||||
void
|
||||
TimelineHeaderContainer::end_drag()
|
||||
TimelineHeaderContainer::end_drag(bool apply)
|
||||
{
|
||||
TimelineLayoutHelper &layout = timelineWidget.layoutHelper;
|
||||
|
||||
// Has the user been dragging?
|
||||
if(layout.get_dragging_track())
|
||||
layout.end_dragging_track();
|
||||
layout.end_dragging_track(apply);
|
||||
|
||||
// Reset the arrow as a cursor
|
||||
REQUIRE(gdkWindow);
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ private:
|
|||
|
||||
void begin_drag();
|
||||
|
||||
void end_drag();
|
||||
void end_drag(bool apply = true);
|
||||
|
||||
/**
|
||||
* Recusively raises all the header widget windows in a branch to the
|
||||
|
|
|
|||
|
|
@ -150,13 +150,18 @@ TimelineLayoutHelper::begin_dragging_track(
|
|||
draggingTrack->get_model_track();
|
||||
draggingTrackIter = iterator_from_track(model_track);
|
||||
dragBranchHeight = measure_branch_height(draggingTrackIter);
|
||||
|
||||
draggingDrop.relation = None;
|
||||
|
||||
return draggingTrack;
|
||||
}
|
||||
|
||||
void
|
||||
TimelineLayoutHelper::end_dragging_track()
|
||||
TimelineLayoutHelper::end_dragging_track(bool apply)
|
||||
{
|
||||
if(apply)
|
||||
apply_drop_to_model_tree(draggingDrop);
|
||||
|
||||
draggingTrack.reset();
|
||||
clone_tree_from_sequence();
|
||||
update_layout();
|
||||
|
|
@ -177,6 +182,8 @@ TimelineLayoutHelper::get_dragging_track_iter() const
|
|||
void
|
||||
TimelineLayoutHelper::drag_to_point(const Gdk::Point &point)
|
||||
{
|
||||
optional<Drop> drop;
|
||||
|
||||
// Apply the scroll offset
|
||||
const Gdk::Point last_point(dragPoint);
|
||||
dragPoint = Gdk::Point(point.get_x(),
|
||||
|
|
@ -221,34 +228,42 @@ TimelineLayoutHelper::drag_to_point(const Gdk::Point &point)
|
|||
const int full_width = rect.get_x() + rect.get_width();
|
||||
const int x_mid = rect.get_x() + rect.get_width() / 2;
|
||||
|
||||
// Do hit test
|
||||
if(attempt_drop_upper(iterator, test_point, y,
|
||||
full_width, half_height))
|
||||
break;
|
||||
// Do hit test
|
||||
drop = attempt_drop_upper(iterator, test_point, y,
|
||||
full_width, half_height);
|
||||
if(drop) break;
|
||||
|
||||
if(attempt_drop_lower(iterator, test_point,
|
||||
x_mid, full_width, y_mid, half_height))
|
||||
break;
|
||||
drop = attempt_drop_lower(iterator, test_point,
|
||||
x_mid, full_width, y_mid, half_height);
|
||||
if(drop) break;
|
||||
}
|
||||
|
||||
|
||||
// Did we get a drop point?
|
||||
if(drop)
|
||||
{
|
||||
apply_drop_to_layout_tree(*drop);
|
||||
draggingDrop = *drop;
|
||||
}
|
||||
|
||||
update_layout();
|
||||
}
|
||||
|
||||
bool
|
||||
optional<TimelineLayoutHelper::Drop>
|
||||
TimelineLayoutHelper::attempt_drop_upper(
|
||||
TrackTree::pre_order_iterator target, const Gdk::Point &point,
|
||||
const int y, const int full_width, const int half_height)
|
||||
{
|
||||
if(pt_in_rect(point, Gdk::Rectangle(0, y, full_width, half_height)))
|
||||
{
|
||||
draggingTrackIter = layoutTree.move_before(
|
||||
target, draggingTrackIter);
|
||||
return true;
|
||||
Drop drop;
|
||||
drop.target = target;
|
||||
drop.relation = Before;
|
||||
return drop;
|
||||
}
|
||||
return false;
|
||||
return optional<Drop>();
|
||||
}
|
||||
|
||||
bool
|
||||
optional<TimelineLayoutHelper::Drop>
|
||||
TimelineLayoutHelper::attempt_drop_lower(
|
||||
TrackTree::pre_order_iterator target, const Gdk::Point &point,
|
||||
const int x_mid, const int full_width, const int y_mid,
|
||||
|
|
@ -259,7 +274,9 @@ TimelineLayoutHelper::attempt_drop_lower(
|
|||
|
||||
if(!pt_in_rect(point, Gdk::Rectangle(0, y_mid,
|
||||
full_width, half_height)))
|
||||
return false;
|
||||
return optional<Drop>();
|
||||
|
||||
Drop drop = {target, None};
|
||||
|
||||
if(model_track->can_host_children())
|
||||
{
|
||||
|
|
@ -267,47 +284,135 @@ TimelineLayoutHelper::attempt_drop_lower(
|
|||
{
|
||||
// Is our track being dragged after this header?
|
||||
if(dragPoint.get_x() < x_mid)
|
||||
{
|
||||
draggingTrackIter = layoutTree.move_after(
|
||||
target, draggingTrackIter);
|
||||
}
|
||||
drop.relation = After;
|
||||
else
|
||||
{
|
||||
if(draggingTrackIter.node->parent != target.node)
|
||||
{
|
||||
// Insert a place-holder in the tree
|
||||
const TrackTree::pre_order_iterator placeholder =
|
||||
layoutTree.prepend_child(target);
|
||||
|
||||
// Replace it with the relocated branch
|
||||
draggingTrackIter = layoutTree.move_ontop(
|
||||
placeholder, draggingTrackIter);
|
||||
}
|
||||
}
|
||||
drop.relation = FirstChild;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(draggingTrackIter.node->parent != target.node)
|
||||
{
|
||||
// Insert a place-holder in the tree
|
||||
const TrackTree::pre_order_iterator placeholder =
|
||||
layoutTree.append_child(target);
|
||||
|
||||
// Replace it with the relocated branch
|
||||
draggingTrackIter = layoutTree.move_ontop(
|
||||
placeholder, draggingTrackIter);
|
||||
}
|
||||
}
|
||||
drop.relation = LastChild;
|
||||
}
|
||||
else
|
||||
{
|
||||
// When this track cannot be a parent, the dragging track is
|
||||
// simply dropped after
|
||||
draggingTrackIter = layoutTree.move_after(
|
||||
target, draggingTrackIter);
|
||||
// simply dropped after
|
||||
drop.relation = After;
|
||||
}
|
||||
|
||||
return true;
|
||||
return drop;
|
||||
}
|
||||
|
||||
void
|
||||
TimelineLayoutHelper::apply_drop_to_layout_tree(
|
||||
const TimelineLayoutHelper::Drop &drop)
|
||||
{
|
||||
switch(drop.relation)
|
||||
{
|
||||
case None:
|
||||
break;
|
||||
|
||||
case Before:
|
||||
draggingTrackIter = layoutTree.move_before(
|
||||
drop.target, draggingTrackIter);
|
||||
break;
|
||||
|
||||
case After:
|
||||
draggingTrackIter = layoutTree.move_after(
|
||||
drop.target, draggingTrackIter);
|
||||
break;
|
||||
|
||||
case FirstChild:
|
||||
if(draggingTrackIter.node->parent != drop.target.node)
|
||||
{
|
||||
draggingTrackIter = layoutTree.move_ontop(
|
||||
layoutTree.prepend_child(drop.target), draggingTrackIter);
|
||||
}
|
||||
break;
|
||||
|
||||
case LastChild:
|
||||
if(draggingTrackIter.node->parent != drop.target.node)
|
||||
{
|
||||
draggingTrackIter = layoutTree.move_ontop(
|
||||
layoutTree.append_child(drop.target), draggingTrackIter);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ASSERT(0); // Unexpected value of relation
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TimelineLayoutHelper::apply_drop_to_model_tree(
|
||||
const TimelineLayoutHelper::Drop &drop)
|
||||
{
|
||||
if(drop.relation == None)
|
||||
return;
|
||||
|
||||
// Freeze the timeline widget - it must be done manually later
|
||||
timelineWidget.freeze_update_tracks();
|
||||
|
||||
// Get the tracks
|
||||
shared_ptr<model::Track> &dragging_track = *draggingTrackIter;
|
||||
REQUIRE(dragging_track);
|
||||
REQUIRE(dragging_track != timelineWidget.sequence);
|
||||
|
||||
shared_ptr<model::Track> &target_track = *drop.target;
|
||||
REQUIRE(target_track);
|
||||
REQUIRE(target_track != timelineWidget.sequence);
|
||||
|
||||
// Detach the track from the old parent
|
||||
shared_ptr<model::ParentTrack> old_parent =
|
||||
dynamic_pointer_cast<model::ParentTrack, model::Track>(
|
||||
model::Track::find_parent(
|
||||
timelineWidget.sequence, dragging_track));
|
||||
REQUIRE(old_parent); // The track must have a parent
|
||||
old_parent->get_child_track_list().remove(dragging_track);
|
||||
|
||||
if(drop.relation == Before || drop.relation == After)
|
||||
{
|
||||
// Find the new parent track
|
||||
shared_ptr<model::ParentTrack> new_parent =
|
||||
dynamic_pointer_cast<model::ParentTrack, model::Track>(
|
||||
model::Track::find_parent(
|
||||
timelineWidget.sequence, target_track));
|
||||
REQUIRE(new_parent); // The track must have a parent
|
||||
|
||||
// Find the destination point
|
||||
observable_list< shared_ptr<model::Track> > &dest =
|
||||
new_parent->get_child_track_list();
|
||||
list< shared_ptr<model::Track> >::iterator iter;
|
||||
for(iter = dest.begin(); iter != dest.end(); iter++)
|
||||
{
|
||||
if(*iter == target_track)
|
||||
break;
|
||||
}
|
||||
REQUIRE(iter != dest.end()); // The target must be
|
||||
// in the destination
|
||||
|
||||
// We have to jump on 1 if we want to insert after
|
||||
if(drop.relation == After)
|
||||
iter++;
|
||||
|
||||
// Insert at this point
|
||||
dest.insert(iter, dragging_track);
|
||||
}
|
||||
else if(drop.relation == FirstChild || drop.relation == LastChild)
|
||||
{
|
||||
shared_ptr<model::ParentTrack> new_parent =
|
||||
dynamic_pointer_cast<model::ParentTrack, model::Track>(
|
||||
target_track);
|
||||
REQUIRE(new_parent); // The track must have a parent
|
||||
|
||||
if(drop.relation == FirstChild)
|
||||
new_parent->get_child_track_list().push_front(dragging_track);
|
||||
else if(drop.relation == LastChild)
|
||||
new_parent->get_child_track_list().push_back(dragging_track);
|
||||
}
|
||||
else ASSERT(0); // Unexpected value of relation
|
||||
|
||||
// Freeze the timeline widget - we will do it manually
|
||||
timelineWidget.freeze_update_tracks();
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ public:
|
|||
boost::shared_ptr<timeline::Track>
|
||||
begin_dragging_track(const Gdk::Point &mouse_point);
|
||||
|
||||
void end_dragging_track();
|
||||
void end_dragging_track(bool apply);
|
||||
|
||||
boost::shared_ptr<timeline::Track> get_dragging_track() const;
|
||||
|
||||
|
|
@ -159,7 +159,23 @@ public:
|
|||
boost::shared_ptr<model::Track> model_track);
|
||||
|
||||
int measure_branch_height(TrackTree::iterator_base parent_iterator);
|
||||
|
||||
protected:
|
||||
enum TreeRelation
|
||||
{
|
||||
None,
|
||||
Before,
|
||||
After,
|
||||
FirstChild,
|
||||
LastChild
|
||||
};
|
||||
|
||||
struct Drop
|
||||
{
|
||||
TrackTree::pre_order_iterator target;
|
||||
TreeRelation relation;
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
|
|
@ -221,16 +237,19 @@ protected:
|
|||
* The animation timer tick callback.
|
||||
**/
|
||||
bool on_animation_tick();
|
||||
|
||||
bool
|
||||
|
||||
boost::optional<TimelineLayoutHelper::Drop>
|
||||
attempt_drop_upper(TrackTree::pre_order_iterator target, const Gdk::Point &point, const int y, const int full_width, const int half_height);
|
||||
|
||||
|
||||
bool
|
||||
boost::optional<TimelineLayoutHelper::Drop>
|
||||
attempt_drop_lower(TrackTree::pre_order_iterator target, const Gdk::Point &point, const int x_mid, const int full_width, const int y_mid, const int half_height);
|
||||
|
||||
protected:
|
||||
|
||||
void apply_drop_to_layout_tree(const Drop &drop);
|
||||
|
||||
void apply_drop_to_model_tree(const Drop &drop);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* The owner timeline widget as provided to the constructor.
|
||||
**/
|
||||
|
|
@ -268,6 +287,8 @@ protected:
|
|||
|
||||
int dragBranchHeight;
|
||||
|
||||
Drop draggingDrop;
|
||||
|
||||
/**
|
||||
* The connection to the animation timer.
|
||||
* @see begin_animation()
|
||||
|
|
|
|||
Loading…
Reference in a new issue