more profound changes to canvas scrolling, in particular find appropriate ScrollGroup for Canvas::{window,canvas}_to_{canvas,window}()
This commit is contained in:
parent
d4989ed9ce
commit
e0533e9dd7
|
@ -2421,21 +2421,31 @@ Editor::get_state ()
|
|||
return *node;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @param y y offset from the top of all trackviews.
|
||||
/** @param y y is in canvas coordinate space, in pixel units
|
||||
*
|
||||
* @return pair: TimeAxisView that y is over, layer index.
|
||||
*
|
||||
* TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
|
||||
* in stacked or expanded region display mode, otherwise 0.
|
||||
*/
|
||||
std::pair<TimeAxisView *, double>
|
||||
Editor::trackview_by_y_position (double y)
|
||||
{
|
||||
for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
|
||||
/* convert y into an offset within the trackview group */
|
||||
|
||||
std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
|
||||
if (r.first) {
|
||||
return r;
|
||||
ArdourCanvas::Duple top_of_trackviews_canvas = _trackview_group->item_to_canvas (ArdourCanvas::Duple (0, 0));
|
||||
|
||||
if (y >= top_of_trackviews_canvas.y) {
|
||||
|
||||
y -= top_of_trackviews_canvas.y;
|
||||
|
||||
for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
|
||||
|
||||
std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
|
||||
|
||||
if (r.first) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -744,9 +744,6 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
|
|||
/* The group containing all trackviews. */
|
||||
ArdourCanvas::Group* _trackview_group;
|
||||
|
||||
/* The group used for region motion. Sits on top of _trackview_group */
|
||||
ArdourCanvas::Group* _region_motion_group;
|
||||
|
||||
/* a rect that sits at the bottom of all tracks to act as a drag-no-drop/clickable
|
||||
* target area.
|
||||
*/
|
||||
|
|
|
@ -116,12 +116,8 @@ Editor::initialize_canvas ()
|
|||
CANVAS_DEBUG_NAME (time_line_group, "time line group");
|
||||
|
||||
_trackview_group = new ArdourCanvas::Group (hv_scroll_group);
|
||||
//_trackview_group->set_scroll_sensitivity (ArdourCanvas::Group::ScrollSensitivity (ArdourCanvas::Group::ScrollsVertically|ArdourCanvas::Group::ScrollsHorizontally));
|
||||
CANVAS_DEBUG_NAME (_trackview_group, "Canvas TrackViews");
|
||||
|
||||
_region_motion_group = new ArdourCanvas::Group (_trackview_group);
|
||||
CANVAS_DEBUG_NAME (_region_motion_group, "Canvas Region Motion");
|
||||
|
||||
/* TIME BAR CANVAS */
|
||||
|
||||
_time_markers_group = new ArdourCanvas::Group (h_scroll_group);
|
||||
|
@ -453,7 +449,7 @@ Editor::drop_paths (const RefPtr<Gdk::DragContext>& context,
|
|||
|
||||
if (convert_drop_to_paths (paths, context, x, y, data, info, time) == 0) {
|
||||
|
||||
/* D-n-D coordinates are window-relative, so convert to "world" coordinates
|
||||
/* D-n-D coordinates are window-relative, so convert to canvas coordinates
|
||||
*/
|
||||
|
||||
ev.type = GDK_BUTTON_RELEASE;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
*
|
||||
Copyright (C) 2009 Paul Davis
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
@ -40,6 +40,8 @@
|
|||
#include "ardour/region_factory.h"
|
||||
#include "ardour/session.h"
|
||||
|
||||
#include "canvas/scroll_group.h"
|
||||
|
||||
#include "editor.h"
|
||||
#include "i18n.h"
|
||||
#include "keyboard.h"
|
||||
|
@ -654,7 +656,7 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
|
|||
pair<TimeAxisView*, double> const r = _editor->trackview_by_y_position (_drags->current_pointer_y ());
|
||||
TimeAxisView* tv = r.first;
|
||||
|
||||
if (tv) {
|
||||
if (tv && tv->view()) {
|
||||
double layer = r.second;
|
||||
|
||||
if (first_move && tv->view()->layer_display() == Stacked) {
|
||||
|
@ -700,22 +702,9 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
|
|||
}
|
||||
|
||||
if (first_move) {
|
||||
|
||||
rv->drag_start ();
|
||||
|
||||
/* Reparent to a non scrolling group so that we can keep the
|
||||
region selection above all time axis views.
|
||||
Reparenting means that we will have to move the region view
|
||||
within its new parent, as the two parent groups have different coordinates.
|
||||
*/
|
||||
|
||||
ArdourCanvas::Group* rvg = rv->get_canvas_group();
|
||||
Duple rv_canvas_offset = rvg->item_to_canvas (Duple (0,0));
|
||||
|
||||
rv->get_canvas_group()->reparent (_editor->_region_motion_group);
|
||||
|
||||
rv->fake_set_opaque (true);
|
||||
rvg->set_position (rv_canvas_offset);
|
||||
rv->raise_to_top ();
|
||||
}
|
||||
|
||||
/* If we have moved tracks, we'll fudge the layer delta so that the
|
||||
|
@ -730,7 +719,13 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
|
|||
|
||||
if (tv) {
|
||||
|
||||
/* The TimeAxisView that this region is now on */
|
||||
int track_index = i->time_axis_view + delta_time_axis_view;
|
||||
|
||||
if (track_index < 0 || track_index >= (int) _time_axis_views.size()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* The TimeAxisView that this region is now over */
|
||||
TimeAxisView* current_tv = _time_axis_views[i->time_axis_view + delta_time_axis_view];
|
||||
|
||||
/* Ensure it is moved from stacked -> expanded if appropriate */
|
||||
|
@ -762,39 +757,50 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
|
|||
if (_brushing) {
|
||||
_editor->mouse_brush_insert_region (rv, pending_region_position);
|
||||
} else {
|
||||
double x = 0;
|
||||
double y = 0;
|
||||
|
||||
/* Get the y coordinate of the top of the track that this region is now on */
|
||||
current_tv->canvas_display()->item_to_canvas (x, y);
|
||||
Duple track_origin;
|
||||
|
||||
/* Get the y coordinate of the top of the track that this region is now over */
|
||||
track_origin = current_tv->canvas_display()->item_to_canvas (track_origin);
|
||||
|
||||
/* And adjust for the layer that it should be on */
|
||||
StreamView* cv = current_tv->view ();
|
||||
switch (cv->layer_display ()) {
|
||||
case Overlaid:
|
||||
break;
|
||||
case Stacked:
|
||||
y += (cv->layers() - i->layer - 1) * cv->child_height ();
|
||||
track_origin.y += (cv->layers() - i->layer - 1) * cv->child_height ();
|
||||
break;
|
||||
case Expanded:
|
||||
y += (cv->layers() - i->layer - 0.5) * 2 * cv->child_height ();
|
||||
track_origin.y += (cv->layers() - i->layer - 0.5) * 2 * cv->child_height ();
|
||||
break;
|
||||
}
|
||||
|
||||
/* need to get the parent of the regionview
|
||||
* canvas group and get its position in
|
||||
* equivalent coordinate space as the trackview
|
||||
* we are now dragging over.
|
||||
*/
|
||||
|
||||
/* Now move the region view */
|
||||
rv->move (x_delta, y - rv->get_canvas_group()->position().y);
|
||||
rv->move (x_delta, track_origin.y - rv->get_canvas_group()->item_to_canvas (Duple (0, 0)).y);
|
||||
}
|
||||
} else {
|
||||
double y = 0;
|
||||
double x = 0;
|
||||
|
||||
TimeAxisView* last = _time_axis_views.back();
|
||||
last->canvas_display()->item_to_canvas (x, y);
|
||||
y += last->effective_height();
|
||||
rv->move (x_delta, y - rv->get_canvas_group()->position().y);
|
||||
i->time_axis_view = -1;
|
||||
}
|
||||
|
||||
/* Only move the region into the empty dropzone at the bottom if the pointer
|
||||
* is down there.
|
||||
*/
|
||||
|
||||
if (_drags->current_pointer_y() >= _editor->get_trackview_group()->item_to_canvas (Duple (0,0)).y) {
|
||||
Duple track_origin;
|
||||
|
||||
TimeAxisView* last = _time_axis_views.back();
|
||||
track_origin = last->canvas_display()->item_to_canvas (track_origin);
|
||||
track_origin.y += last->effective_height();
|
||||
rv->move (x_delta, track_origin.y - rv->get_canvas_group()->item_to_canvas (Duple (0,0)).y);
|
||||
i->time_axis_view = -1;
|
||||
}
|
||||
}
|
||||
|
||||
} /* foreach region */
|
||||
|
||||
_total_x_delta += x_delta;
|
||||
|
|
|
@ -140,12 +140,6 @@ Editor::window_event_sample (GdkEvent const * event, double* pcx, double* pcy) c
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* adjust for scrolling (the canvas used by Ardour has global scroll
|
||||
* disabled, so we have to do the adjustment explicitly).
|
||||
*/
|
||||
|
||||
d.translate (ArdourCanvas::Duple (horizontal_adjustment.get_value(), vertical_adjustment.get_value()));
|
||||
|
||||
/* event coordinates are in window units, so convert to canvas
|
||||
*/
|
||||
|
||||
|
@ -2710,8 +2704,6 @@ Editor::add_region_drag (ArdourCanvas::Item* item, GdkEvent*, RegionView* region
|
|||
return;
|
||||
}
|
||||
|
||||
_region_motion_group->raise_to_top ();
|
||||
|
||||
if (Config->get_edit_mode() == Splice) {
|
||||
_drags->add (new RegionSpliceDrag (this, item, region_view, selection->regions.by_layer()));
|
||||
} else {
|
||||
|
@ -2728,8 +2720,6 @@ Editor::add_region_copy_drag (ArdourCanvas::Item* item, GdkEvent*, RegionView* r
|
|||
return;
|
||||
}
|
||||
|
||||
_region_motion_group->raise_to_top ();
|
||||
|
||||
_drags->add (new RegionMoveDrag (this, item, region_view, selection->regions.by_layer(), false, true));
|
||||
}
|
||||
|
||||
|
|
|
@ -1333,8 +1333,6 @@ Editor::scroll_tracks_up_line ()
|
|||
bool
|
||||
Editor::scroll_down_one_track ()
|
||||
{
|
||||
double vertical_pos = vertical_adjustment.get_value () + vertical_adjustment.get_page_size() - 1.0;
|
||||
|
||||
TrackViewList::reverse_iterator next = track_views.rend();
|
||||
std::pair<TimeAxisView*,double> res;
|
||||
|
||||
|
@ -1343,7 +1341,8 @@ Editor::scroll_down_one_track ()
|
|||
continue;
|
||||
}
|
||||
|
||||
res = (*t)->covers_y_position (vertical_pos);
|
||||
/* find the trackview at the bottom of the trackview group */
|
||||
res = (*t)->covers_y_position (_visible_canvas_height);
|
||||
|
||||
if (res.first) {
|
||||
break;
|
||||
|
@ -1376,7 +1375,8 @@ Editor::scroll_up_one_track ()
|
|||
continue;
|
||||
}
|
||||
|
||||
res = (*t)->covers_y_position(vertical_pos);
|
||||
/* find the trackview at the top of the trackview group */
|
||||
res = (*t)->covers_y_position (0);
|
||||
|
||||
if (res.first) {
|
||||
break;
|
||||
|
|
|
@ -694,7 +694,18 @@ RegionView::move (double x_delta, double y_delta)
|
|||
return;
|
||||
}
|
||||
|
||||
get_canvas_group()->move (ArdourCanvas::Duple (x_delta, y_delta));
|
||||
/* items will not prevent Item::move() moving
|
||||
* them to a negative x-axis coordinate, which
|
||||
* is legal, but we don't want that here.
|
||||
*/
|
||||
|
||||
ArdourCanvas::Item *item = get_canvas_group ();
|
||||
|
||||
if (item->position().x + x_delta < 0) {
|
||||
x_delta = -item->position().x; /* move it to zero */
|
||||
}
|
||||
|
||||
item->move (ArdourCanvas::Duple (x_delta, y_delta));
|
||||
|
||||
/* note: ghosts never leave their tracks so y_delta for them is always zero */
|
||||
|
||||
|
|
|
@ -1151,9 +1151,12 @@ TimeAxisView::color_handler ()
|
|||
}
|
||||
|
||||
/** @return Pair: TimeAxisView, layer index.
|
||||
* TimeAxisView is non-0 if this object covers y, or one of its children does.
|
||||
* TimeAxisView is non-0 if this object covers @param y, or one of its children
|
||||
* does. @param y is an offset from the top of the trackview area.
|
||||
*
|
||||
* If the covering object is a child axis, then the child is returned.
|
||||
* TimeAxisView is 0 otherwise.
|
||||
*
|
||||
* Layer index is the layer number (possibly fractional) if the TimeAxisView is valid
|
||||
* and is in stacked or expanded * region display mode, otherwise 0.
|
||||
*/
|
||||
|
|
|
@ -207,13 +207,53 @@ Canvas::item_changed (Item* item, boost::optional<Rect> pre_change_bounding_box)
|
|||
Duple
|
||||
Canvas::window_to_canvas (Duple const & d) const
|
||||
{
|
||||
/* Find the scroll group that covers d (a window coordinate). Scroll groups are only allowed
|
||||
* as children of the root group, so we just scan its first level
|
||||
* children and see what we can find.
|
||||
*/
|
||||
|
||||
std::list<Item*> const& root_children (_root.items());
|
||||
ScrollGroup* sg = 0;
|
||||
|
||||
for (std::list<Item*>::const_iterator i = root_children.begin(); i != root_children.end(); ++i) {
|
||||
if (((sg = dynamic_cast<ScrollGroup*>(*i)) != 0) && sg->covers_window (d)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sg) {
|
||||
return d.translate (sg->scroll_offset());
|
||||
}
|
||||
|
||||
/* fallback to global canvas offset ... it would be nice to remove this */
|
||||
|
||||
return d.translate (_scroll_offset);
|
||||
}
|
||||
|
||||
Duple
|
||||
Canvas::canvas_to_window (Duple const & d, bool rounded) const
|
||||
{
|
||||
Duple wd = d.translate (-_scroll_offset);
|
||||
/* Find the scroll group that covers d (a canvas coordinate). Scroll groups are only allowed
|
||||
* as children of the root group, so we just scan its first level
|
||||
* children and see what we can find.
|
||||
*/
|
||||
|
||||
std::list<Item*> const& root_children (_root.items());
|
||||
ScrollGroup* sg = 0;
|
||||
Duple wd;
|
||||
|
||||
for (std::list<Item*>::const_iterator i = root_children.begin(); i != root_children.end(); ++i) {
|
||||
if (((sg = dynamic_cast<ScrollGroup*>(*i)) != 0) && sg->covers_canvas (d)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (sg) {
|
||||
wd = d.translate (-sg->scroll_offset());
|
||||
} else {
|
||||
wd = d.translate (-_scroll_offset);
|
||||
}
|
||||
|
||||
/* Note that this intentionally almost always returns integer coordinates */
|
||||
|
||||
|
@ -225,29 +265,6 @@ Canvas::canvas_to_window (Duple const & d, bool rounded) const
|
|||
return wd;
|
||||
}
|
||||
|
||||
Rect
|
||||
Canvas::window_to_canvas (Rect const & r) const
|
||||
{
|
||||
return r.translate (Duple (_scroll_offset.x, _scroll_offset.y));
|
||||
}
|
||||
|
||||
Rect
|
||||
Canvas::canvas_to_window (Rect const & r, bool rounded) const
|
||||
{
|
||||
Rect wr = r.translate (Duple (-_scroll_offset.x, -_scroll_offset.y));
|
||||
|
||||
/* Note that this intentionally almost always returns integer coordinates */
|
||||
|
||||
if (rounded) {
|
||||
wr.x0 = round (wr.x0);
|
||||
wr.x1 = round (wr.x1);
|
||||
wr.y0 = round (wr.y0);
|
||||
wr.y1 = round (wr.y1);
|
||||
}
|
||||
|
||||
return wr;
|
||||
}
|
||||
|
||||
/** Called when an item has moved.
|
||||
* @param item Item that has moved.
|
||||
* @param pre_change_parent_bounding_box The bounding box of the item before
|
||||
|
|
|
@ -90,8 +90,7 @@ public:
|
|||
void item_moved (Item *, boost::optional<Rect>);
|
||||
|
||||
virtual Cairo::RefPtr<Cairo::Context> context () = 0;
|
||||
Rect canvas_to_window (Rect const&, bool rounded = true) const;
|
||||
Rect window_to_canvas (Rect const&) const;
|
||||
|
||||
Duple canvas_to_window (Duple const&, bool rounded = true) const;
|
||||
Duple window_to_canvas (Duple const&) const;
|
||||
|
||||
|
|
|
@ -129,6 +129,10 @@ public:
|
|||
return _position;
|
||||
}
|
||||
|
||||
Duple window_origin() const;
|
||||
|
||||
ScrollGroup* scroll_parent() const { return _scroll_parent; }
|
||||
|
||||
boost::optional<Rect> bounding_box () const;
|
||||
Coord height() const;
|
||||
Coord width() const;
|
||||
|
|
|
@ -37,6 +37,9 @@ class LIBCANVAS_API ScrollGroup : public Group
|
|||
void scroll_to (Duple const& d);
|
||||
Duple scroll_offset() const { return _scroll_offset; }
|
||||
|
||||
bool covers_canvas (Duple const& d) const;
|
||||
bool covers_window (Duple const& d) const;
|
||||
|
||||
private:
|
||||
ScrollSensitivity _scroll_sensitivity;
|
||||
Duple _scroll_offset;
|
||||
|
|
|
@ -82,6 +82,20 @@ Item::~Item ()
|
|||
}
|
||||
}
|
||||
|
||||
Duple
|
||||
Item::window_origin () const
|
||||
{
|
||||
/* This is slightly subtle. Our _position is in the coordinate space of
|
||||
our parent. So to find out where that is in window coordinates, we
|
||||
have to ask our parent.
|
||||
*/
|
||||
if (_parent) {
|
||||
return _parent->item_to_window (_position);
|
||||
} else {
|
||||
return _parent->item_to_window (Duple (0,0));
|
||||
}
|
||||
}
|
||||
|
||||
ArdourCanvas::Rect
|
||||
Item::item_to_parent (ArdourCanvas::Rect const & r) const
|
||||
{
|
||||
|
|
|
@ -49,3 +49,29 @@ ScrollGroup::scroll_to (Duple const& d)
|
|||
_scroll_offset.y = d.y;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ScrollGroup::covers_canvas (Duple const& d) const
|
||||
{
|
||||
boost::optional<Rect> r = bounding_box ();
|
||||
|
||||
if (!r) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return r->contains (d);
|
||||
}
|
||||
|
||||
bool
|
||||
ScrollGroup::covers_window (Duple const& d) const
|
||||
{
|
||||
boost::optional<Rect> r = bounding_box ();
|
||||
|
||||
if (!r) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Rect w = r->translate (-_scroll_offset);
|
||||
|
||||
return w.contains (d);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue