notable changes to try to improve most of enter/leave handling for canvas items
This commit is contained in:
parent
006ba7cd36
commit
7bbd28aa08
|
@ -172,17 +172,17 @@ AudioRegionView::init (Gdk::Color const & basic_color, bool wfd)
|
|||
if (!_recregion) {
|
||||
fade_in_handle = new ArdourCanvas::Rectangle (group);
|
||||
CANVAS_DEBUG_NAME (fade_in_handle, string_compose ("fade in handle for %1", region()->name()));
|
||||
fade_in_handle->set_fill_color (UINT_RGBA_CHANGE_A (fill_color, 0));
|
||||
fade_in_handle->set_outline_color (RGBA_TO_UINT (0, 0, 0, 0));
|
||||
|
||||
fade_in_handle->set_outline_color (RGBA_TO_UINT (0, 0, 0, 255));
|
||||
fade_in_handle->set_fill_color (UINT_RGBA_CHANGE_A (fade_color, 255));
|
||||
fade_in_handle->set_data ("regionview", this);
|
||||
fade_in_handle->hide ();
|
||||
|
||||
fade_out_handle = new ArdourCanvas::Rectangle (group);
|
||||
CANVAS_DEBUG_NAME (fade_out_handle, string_compose ("fade out handle for %1", region()->name()));
|
||||
fade_out_handle->set_fill_color (UINT_RGBA_CHANGE_A (fill_color, 0));
|
||||
fade_out_handle->set_outline_color (RGBA_TO_UINT (0, 0, 0, 0));
|
||||
|
||||
fade_out_handle->set_outline_color (RGBA_TO_UINT (0, 0, 0, 255));
|
||||
fade_out_handle->set_fill_color (UINT_RGBA_CHANGE_A (fade_color, 255));
|
||||
fade_out_handle->set_data ("regionview", this);
|
||||
fade_out_handle->hide ();
|
||||
}
|
||||
|
||||
setup_fade_handle_positions ();
|
||||
|
@ -410,10 +410,9 @@ AudioRegionView::reset_width_dependent_items (double pixel_width)
|
|||
if (pixel_width <= 6.0 || _height < 5.0 || !trackview.session()->config.get_show_region_fades()) {
|
||||
fade_in_handle->hide();
|
||||
fade_out_handle->hide();
|
||||
}
|
||||
else {
|
||||
fade_in_handle->show();
|
||||
fade_out_handle->show();
|
||||
} else {
|
||||
//fade_in_handle->show();
|
||||
//fade_out_handle->show();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -533,8 +532,6 @@ AudioRegionView::reset_fade_in_shape_width (boost::shared_ptr<AudioRegion> ar, f
|
|||
return;
|
||||
}
|
||||
|
||||
fade_in_handle->show ();
|
||||
|
||||
/* smallest size for a fade is 64 frames */
|
||||
|
||||
width = std::max ((framecnt_t) 64, width);
|
||||
|
@ -629,8 +626,6 @@ AudioRegionView::reset_fade_out_shape_width (boost::shared_ptr<AudioRegion> ar,
|
|||
return;
|
||||
}
|
||||
|
||||
fade_out_handle->show ();
|
||||
|
||||
/* smallest size for a fade is 64 frames */
|
||||
|
||||
width = std::max ((framecnt_t) 64, width);
|
||||
|
@ -1374,11 +1369,13 @@ AudioRegionView::entered (bool internal_editing)
|
|||
gain_line->add_visibility (AutomationLine::ControlPoints);
|
||||
}
|
||||
|
||||
cerr << "Entered! ARV for " << _region->name() << endl;
|
||||
|
||||
if (fade_in_handle && !internal_editing) {
|
||||
fade_in_handle->set_outline_color (RGBA_TO_UINT (0, 0, 0, 255));
|
||||
fade_in_handle->set_fill_color (UINT_RGBA_CHANGE_A (fade_color, 255));
|
||||
fade_out_handle->set_outline_color (RGBA_TO_UINT (0, 0, 0, 255));
|
||||
fade_out_handle->set_fill_color (UINT_RGBA_CHANGE_A (fade_color, 255));
|
||||
fade_in_handle->show ();
|
||||
fade_out_handle->show ();
|
||||
fade_out_handle->raise_to_top ();
|
||||
fade_in_handle->raise_to_top ();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1392,11 +1389,11 @@ AudioRegionView::exited ()
|
|||
gain_line->remove_visibility (AutomationLine::ControlPoints);
|
||||
}
|
||||
|
||||
cerr << "Left! ARV for " << _region->name() << endl;
|
||||
|
||||
if (fade_in_handle) {
|
||||
fade_in_handle->set_outline_color (RGBA_TO_UINT (0, 0, 0, 0));
|
||||
fade_in_handle->set_fill_color (UINT_RGBA_CHANGE_A (fade_color, 0));
|
||||
fade_out_handle->set_outline_color (RGBA_TO_UINT (0, 0, 0, 0));
|
||||
fade_out_handle->set_fill_color (UINT_RGBA_CHANGE_A (fade_color, 0));
|
||||
fade_in_handle->hide ();
|
||||
fade_out_handle->hide ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
|
||||
#include "evoral/Curve.hpp"
|
||||
|
||||
#include "canvas/debug.h"
|
||||
|
||||
#include "automation_line.h"
|
||||
#include "control_point.h"
|
||||
#include "gui_thread.h"
|
||||
|
@ -90,8 +92,10 @@ AutomationLine::AutomationLine (const string& name, TimeAxisView& tv, ArdourCanv
|
|||
_height = 0;
|
||||
|
||||
group = new ArdourCanvas::Group (&parent);
|
||||
CANVAS_DEBUG_NAME (group, "region gain envelope group");
|
||||
|
||||
line = new ArdourCanvas::Curve (group);
|
||||
CANVAS_DEBUG_NAME (line, "region gain envelope line");
|
||||
line->set_data ("line", this);
|
||||
line->set_outline_width (2.0);
|
||||
|
||||
|
|
|
@ -267,12 +267,11 @@ Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, Reg
|
|||
break;
|
||||
|
||||
case GDK_ENTER_NOTIFY:
|
||||
set_entered_track (&rv->get_time_axis_view ());
|
||||
set_entered_regionview (rv);
|
||||
ret = true;
|
||||
break;
|
||||
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
set_entered_track (0);
|
||||
set_entered_regionview (0);
|
||||
break;
|
||||
|
||||
|
@ -309,6 +308,7 @@ Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, Rou
|
|||
|
||||
case GDK_ENTER_NOTIFY:
|
||||
set_entered_track (tv);
|
||||
ret = true;
|
||||
break;
|
||||
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
|
@ -462,9 +462,13 @@ Editor::canvas_fade_in_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRe
|
|||
|
||||
}
|
||||
|
||||
/* proxy for the regionview */
|
||||
/* proxy for the regionview, except enter/leave events */
|
||||
|
||||
return canvas_region_view_event (event, rv->get_canvas_group(), rv);
|
||||
if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
|
||||
return true;
|
||||
} else {
|
||||
return canvas_region_view_event (event, rv->get_canvas_group(), rv);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -497,12 +501,10 @@ Editor::canvas_fade_in_handle_event (GdkEvent *event, ArdourCanvas::Item* item,
|
|||
break;
|
||||
|
||||
case GDK_ENTER_NOTIFY:
|
||||
set_entered_regionview (rv);
|
||||
ret = enter_handler (item, event, FadeInHandleItem);
|
||||
break;
|
||||
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
set_entered_regionview (0);
|
||||
ret = leave_handler (item, event, FadeInHandleItem);
|
||||
break;
|
||||
|
||||
|
@ -544,9 +546,13 @@ Editor::canvas_fade_out_event (GdkEvent *event, ArdourCanvas::Item* item, AudioR
|
|||
|
||||
}
|
||||
|
||||
/* proxy for the regionview */
|
||||
/* proxy for the regionview, except enter/leave events */
|
||||
|
||||
return canvas_region_view_event (event, rv->get_canvas_group(), rv);
|
||||
if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
|
||||
return true;
|
||||
} else {
|
||||
return canvas_region_view_event (event, rv->get_canvas_group(), rv);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -579,12 +585,10 @@ Editor::canvas_fade_out_handle_event (GdkEvent *event, ArdourCanvas::Item* item,
|
|||
break;
|
||||
|
||||
case GDK_ENTER_NOTIFY:
|
||||
set_entered_regionview (rv);
|
||||
ret = enter_handler (item, event, FadeOutHandleItem);
|
||||
break;
|
||||
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
set_entered_regionview (0);
|
||||
ret = leave_handler (item, event, FadeOutHandleItem);
|
||||
break;
|
||||
|
||||
|
@ -783,12 +787,10 @@ Editor::canvas_frame_handle_event (GdkEvent* event, ArdourCanvas::Item* item, Re
|
|||
ret = motion_handler (item, event);
|
||||
break;
|
||||
case GDK_ENTER_NOTIFY:
|
||||
set_entered_regionview (rv);
|
||||
ret = enter_handler (item, event, type);
|
||||
break;
|
||||
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
set_entered_regionview (0);
|
||||
ret = leave_handler (item, event, type);
|
||||
break;
|
||||
|
||||
|
@ -827,12 +829,10 @@ Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas::
|
|||
ret = true; // force this to avoid progagating the event into the regionview
|
||||
break;
|
||||
case GDK_ENTER_NOTIFY:
|
||||
set_entered_regionview (rv);
|
||||
ret = enter_handler (item, event, RegionViewNameHighlight);
|
||||
break;
|
||||
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
set_entered_regionview (0);
|
||||
ret = leave_handler (item, event, RegionViewNameHighlight);
|
||||
break;
|
||||
|
||||
|
@ -869,12 +869,10 @@ Editor::canvas_region_view_name_event (GdkEvent *event, ArdourCanvas::Item* item
|
|||
ret = motion_handler (item, event);
|
||||
break;
|
||||
case GDK_ENTER_NOTIFY:
|
||||
set_entered_regionview (rv);
|
||||
ret = enter_handler (item, event, RegionViewName);
|
||||
break;
|
||||
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
set_entered_regionview (0);
|
||||
ret = leave_handler (item, event, RegionViewName);
|
||||
break;
|
||||
|
||||
|
|
|
@ -184,6 +184,7 @@ TimeAxisViewItem::init (ArdourCanvas::Group* parent, double fpp, Gdk::Color cons
|
|||
ArdourCanvas::Rect (0.0, 1.0,
|
||||
trackview.editor().sample_to_pixel(duration),
|
||||
trackview.current_height()));
|
||||
|
||||
CANVAS_DEBUG_NAME (frame, string_compose ("frame for %1", get_item_name()));
|
||||
|
||||
if (_recregion) {
|
||||
|
|
|
@ -234,8 +234,8 @@ Canvas::queue_draw_item_area (Item* item, Rect area)
|
|||
|
||||
/** Construct a GtkCanvas */
|
||||
GtkCanvas::GtkCanvas ()
|
||||
: _current_item (0)
|
||||
, _grabbed_item (0)
|
||||
: _grabbed_item (0)
|
||||
, _focused_item (0)
|
||||
{
|
||||
/* these are the events we want to know about */
|
||||
add_events (Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::POINTER_MOTION_MASK);
|
||||
|
@ -294,10 +294,11 @@ GtkCanvas::enter_leave_items (int state)
|
|||
void
|
||||
GtkCanvas::enter_leave_items (Duple const & point, int state)
|
||||
{
|
||||
/* find the items at the given position */
|
||||
/* we do not enter/leave items during a drag/grab */
|
||||
|
||||
vector<Item const *> items;
|
||||
_root.add_items_at_point (point, items);
|
||||
if (_grabbed_item) {
|
||||
return;
|
||||
}
|
||||
|
||||
GdkEventCrossing enter_event;
|
||||
enter_event.type = GDK_ENTER_NOTIFY;
|
||||
|
@ -310,69 +311,88 @@ GtkCanvas::enter_leave_items (Duple const & point, int state)
|
|||
enter_event.state = state;
|
||||
enter_event.x = point.x;
|
||||
enter_event.y = point.y;
|
||||
enter_event.detail = GDK_NOTIFY_UNKNOWN;
|
||||
|
||||
GdkEventCrossing leave_event = enter_event;
|
||||
leave_event.type = GDK_LEAVE_NOTIFY;
|
||||
leave_event.detail = GDK_NOTIFY_ANCESTOR;
|
||||
leave_event.subwindow = 0;
|
||||
|
||||
if (items.empty()) {
|
||||
if (_current_item) {
|
||||
/* leave event */
|
||||
// cerr << "E/L: left item " << _current_item->whatami() << '/' << _current_item->name << " for ... nada" << endl;
|
||||
_current_item->Event (reinterpret_cast<GdkEvent*> (&leave_event));
|
||||
_current_item = 0;
|
||||
/* find the items at the given position */
|
||||
|
||||
vector<Item const *> items;
|
||||
_root.add_items_at_point (point, items);
|
||||
|
||||
/* put all items at point that are event-sensitive and visible into within_items, and if this
|
||||
is a new addition, also put them into newly_entered for later deliver of enter events.
|
||||
*/
|
||||
|
||||
vector<Item const *>::const_iterator i;
|
||||
vector<Item const *> newly_entered;
|
||||
Item const * new_item;
|
||||
|
||||
for (i = items.begin(); i != items.end(); ++i) {
|
||||
|
||||
new_item = *i;
|
||||
|
||||
if (new_item->ignore_events() || !new_item->visible()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pair<set<Item const *>::iterator,bool> res = within_items.insert (new_item);
|
||||
|
||||
if (res.second) {
|
||||
newly_entered.push_back (new_item);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* items is sorted from top to bottom, so reverse through it from bottom
|
||||
* to top to find the lowest, first event-sensitive item and notify that
|
||||
* we have entered it
|
||||
*/
|
||||
/* for every item in "within_items", check that we are still within them. if not,
|
||||
send a leave event, and remove them from "within_items"
|
||||
*/
|
||||
|
||||
for (set<Item const *>::const_iterator i = within_items.begin(); i != within_items.end(); ) {
|
||||
|
||||
set<Item const *>::const_iterator tmp = i;
|
||||
++tmp;
|
||||
|
||||
new_item = *i;
|
||||
|
||||
boost::optional<Rect> bbox = new_item->bounding_box();
|
||||
|
||||
|
||||
if (bbox) {
|
||||
if (!new_item->item_to_canvas (bbox.get()).contains (point)) {
|
||||
leave_event.detail = GDK_NOTIFY_UNKNOWN;
|
||||
cerr << string_compose ("\tLeave %1 %2\n", new_item->whatami(), new_item->name);
|
||||
DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("Leave %1 %2\n", new_item->whatami(), new_item->name));
|
||||
(*i)->Event (reinterpret_cast<GdkEvent*> (&leave_event));
|
||||
within_items.erase (i);
|
||||
}
|
||||
}
|
||||
|
||||
i = tmp;
|
||||
}
|
||||
|
||||
// cerr << "E/L: " << items.size() << " to check at " << point << endl;
|
||||
#ifdef CANVAS_DEBUG
|
||||
// for (vector<Item const*>::const_reverse_iterator i = items.rbegin(); i != items.rend(); ++i) {
|
||||
// cerr << '\t' << (*i)->whatami() << ' ' << (*i)->name << " ignore ? " << (*i)->ignore_events() << " current ? " << (_current_item == (*i)) << endl;
|
||||
// }
|
||||
#endif
|
||||
// cerr << "------------\n";
|
||||
/* for every item in "newly_entered", send an enter event (and propagate it up the
|
||||
item tree until it is handled
|
||||
*/
|
||||
|
||||
for (vector<Item const*>::const_reverse_iterator i = items.rbegin(); i != items.rend(); ++i) {
|
||||
for (vector<Item const*>::const_iterator i = newly_entered.begin(); i != newly_entered.end(); ++i) {
|
||||
new_item = *i;
|
||||
|
||||
Item const * new_item = *i;
|
||||
#ifdef CANVAS_DEBUG
|
||||
// cerr << "\tE/L check out " << new_item->whatami() << ' ' << new_item->name << " ignore ? " << new_item->ignore_events() << " current ? " << (_current_item == new_item) << endl;
|
||||
#endif
|
||||
if (new_item->ignore_events()) {
|
||||
// cerr << "continue1\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_current_item == new_item) {
|
||||
// cerr << "continue2\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_current_item) {
|
||||
/* leave event */
|
||||
DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("Leave %1 %2\n", _current_item->whatami(), _current_item->name));
|
||||
_current_item->Event (reinterpret_cast<GdkEvent*> (&leave_event));
|
||||
queue_draw ();
|
||||
}
|
||||
|
||||
if (new_item && _current_item != new_item) {
|
||||
/* enter event */
|
||||
_current_item = new_item;
|
||||
DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("Enter %1 %2\n", _current_item->whatami(), _current_item->name));
|
||||
_current_item->Event (reinterpret_cast<GdkEvent*> (&enter_event));
|
||||
queue_draw ();
|
||||
if (new_item->Event (reinterpret_cast<GdkEvent*> (&enter_event))) {
|
||||
cerr << string_compose ("\tEntered %1 %2\n", new_item->whatami(), new_item->name);
|
||||
DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("Enter %1 %2\n", new_item->whatami(), new_item->name));
|
||||
break;
|
||||
}
|
||||
|
||||
// cerr << "Loop around again\n";
|
||||
}
|
||||
|
||||
#if 0
|
||||
cerr << "Within:\n";
|
||||
for (set<Item const *>::const_iterator i = within_items.begin(); i != within_items.end(); ++i) {
|
||||
cerr << '\t' << (*i)->whatami() << '/' << (*i)->name << endl;
|
||||
}
|
||||
cerr << "----\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Deliver an event to the appropriate item; either the grabbed item, or
|
||||
|
@ -451,15 +471,19 @@ GtkCanvas::item_going_away (Item* item, boost::optional<Rect> bounding_box)
|
|||
queue_draw_item_area (item, bounding_box.get ());
|
||||
}
|
||||
|
||||
if (_current_item == item) {
|
||||
_current_item = 0;
|
||||
queue_draw ();
|
||||
}
|
||||
/* no need to send a leave event to this item, since it is going away
|
||||
*/
|
||||
|
||||
within_items.erase (item);
|
||||
|
||||
if (_grabbed_item == item) {
|
||||
_grabbed_item = 0;
|
||||
}
|
||||
|
||||
if (_focused_item == item) {
|
||||
_focused_item = 0;
|
||||
}
|
||||
|
||||
enter_leave_items (0); // no mouse state
|
||||
|
||||
}
|
||||
|
@ -549,6 +573,22 @@ GtkCanvas::on_motion_notify_event (GdkEventMotion* ev)
|
|||
return motion_notify_handler ((GdkEventMotion*) ©);
|
||||
}
|
||||
|
||||
bool
|
||||
GtkCanvas::on_enter_notify_event (GdkEventCrossing* ev)
|
||||
{
|
||||
Duple where = window_to_canvas (Duple (ev->x, ev->y));
|
||||
enter_leave_items (where, ev->state);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GtkCanvas::on_leave_notify_event (GdkEventCrossing* /*ev*/)
|
||||
{
|
||||
cerr << "Clear all within items as we leave\n";
|
||||
within_items.clear ();
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Called to request a redraw of our canvas.
|
||||
* @param area Area to redraw, in canvas coordinates.
|
||||
*/
|
||||
|
@ -591,6 +631,7 @@ GtkCanvas::grab (Item* item)
|
|||
_grabbed_item = item;
|
||||
}
|
||||
|
||||
|
||||
/** `Ungrab' any item that was previously grabbed */
|
||||
void
|
||||
GtkCanvas::ungrab ()
|
||||
|
@ -599,6 +640,24 @@ GtkCanvas::ungrab ()
|
|||
_grabbed_item = 0;
|
||||
}
|
||||
|
||||
/** Set keyboard focus on an item, so that all keyboard events are sent to that item until the focus
|
||||
* moves elsewhere.
|
||||
* @param item Item to grab.
|
||||
*/
|
||||
void
|
||||
GtkCanvas::focus (Item* item)
|
||||
{
|
||||
_focused_item = item;
|
||||
}
|
||||
|
||||
void
|
||||
GtkCanvas::unfocus (Item* item)
|
||||
{
|
||||
if (item == _focused_item) {
|
||||
_focused_item = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** @return The visible area of the canvas, in canvas coordinates */
|
||||
Rect
|
||||
GtkCanvas::visible_area () const
|
||||
|
|
|
@ -24,11 +24,14 @@
|
|||
#ifndef __CANVAS_CANVAS_H__
|
||||
#define __CANVAS_CANVAS_H__
|
||||
|
||||
#include <set>
|
||||
|
||||
#include <gdkmm/window.h>
|
||||
#include <gtkmm/eventbox.h>
|
||||
#include <gtkmm/alignment.h>
|
||||
#include <cairomm/surface.h>
|
||||
#include <cairomm/context.h>
|
||||
|
||||
#include "pbd/signals.h"
|
||||
#include "canvas/root_group.h"
|
||||
|
||||
|
@ -63,6 +66,11 @@ public:
|
|||
/** called to ask the canvas' host to `ungrab' any grabbed item */
|
||||
virtual void ungrab () = 0;
|
||||
|
||||
/** called to ask the canvas' host to keyboard focus on an item */
|
||||
virtual void focus (Item *) = 0;
|
||||
/** called to ask the canvas' host to drop keyboard focus on an item */
|
||||
virtual void unfocus (Item*) = 0;
|
||||
|
||||
void render (Rect const &, Cairo::RefPtr<Cairo::Context> const &) const;
|
||||
|
||||
/** @return root group */
|
||||
|
@ -126,6 +134,8 @@ public:
|
|||
void request_size (Duple);
|
||||
void grab (Item *);
|
||||
void ungrab ();
|
||||
void focus (Item *);
|
||||
void unfocus (Item*);
|
||||
|
||||
Cairo::RefPtr<Cairo::Context> context ();
|
||||
|
||||
|
@ -136,6 +146,8 @@ protected:
|
|||
bool on_button_press_event (GdkEventButton *);
|
||||
bool on_button_release_event (GdkEventButton* event);
|
||||
bool on_motion_notify_event (GdkEventMotion *);
|
||||
bool on_enter_notify_event (GdkEventCrossing*);
|
||||
bool on_leave_notify_event (GdkEventCrossing*);
|
||||
|
||||
bool button_handler (GdkEventButton *);
|
||||
bool motion_notify_handler (GdkEventMotion *);
|
||||
|
@ -148,11 +160,12 @@ private:
|
|||
void item_going_away (Item *, boost::optional<Rect>);
|
||||
bool send_leave_event (Item const *, double, double) const;
|
||||
|
||||
|
||||
/** the item that the mouse is currently over, or 0 */
|
||||
Item const * _current_item;
|
||||
/** Items that the pointer is currently within */
|
||||
std::set<Item const *> within_items;
|
||||
/** the item that is currently grabbed, or 0 */
|
||||
Item const * _grabbed_item;
|
||||
/** the item that currently has key focus or 0 */
|
||||
Item const * _focused_item;
|
||||
};
|
||||
|
||||
/** A GTK::Alignment with a GtkCanvas inside it plus some Gtk::Adjustments for
|
||||
|
|
|
@ -88,6 +88,21 @@ public:
|
|||
Group* parent () const {
|
||||
return _parent;
|
||||
}
|
||||
|
||||
uint32_t depth() const;
|
||||
const Item* closest_ancestor_with (const Item& other) const;
|
||||
bool common_ancestor_within (uint32_t, const Item& other) const;
|
||||
|
||||
/** returns true if this item is an ancestor of @param candidate,
|
||||
* and false otherwise.
|
||||
*/
|
||||
bool is_ancestor_of (const Item& candidate) const {
|
||||
return candidate.is_descendant_of (*this);
|
||||
}
|
||||
/** returns true if this Item is a descendant of @param candidate,
|
||||
* and false otherwise.
|
||||
*/
|
||||
bool is_descendant_of (const Item& candidate) const;
|
||||
|
||||
void set_position (Duple);
|
||||
void set_x_position (Coord);
|
||||
|
|
|
@ -74,8 +74,6 @@ Group::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
|
|||
ensure_lut ();
|
||||
vector<Item*> items = _lut->get (area);
|
||||
|
||||
++render_depth;
|
||||
|
||||
#ifdef CANVAS_DEBUG
|
||||
if (DEBUG_ENABLED(PBD::DEBUG::CanvasRender)) {
|
||||
cerr << string_compose ("%1GROUP %2 render %5 %3 items out of %4\n",
|
||||
|
@ -83,6 +81,8 @@ Group::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
|
|||
}
|
||||
#endif
|
||||
|
||||
++render_depth;
|
||||
|
||||
for (vector<Item*>::const_iterator i = items.begin(); i != items.end(); ++i) {
|
||||
|
||||
if (!(*i)->visible ()) {
|
||||
|
@ -112,16 +112,18 @@ Group::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
|
|||
if (draw) {
|
||||
#ifdef CANVAS_DEBUG
|
||||
if (DEBUG_ENABLED(PBD::DEBUG::CanvasRender)) {
|
||||
cerr << _canvas->render_indent() << " render "
|
||||
<< ' '
|
||||
<< (*i)->whatami()
|
||||
<< ' '
|
||||
<< (*i)->name
|
||||
<< " item = "
|
||||
<< item
|
||||
<< " intersect = "
|
||||
<< draw.get()
|
||||
<< endl;
|
||||
if (dynamic_cast<Group*>(*i) == 0) {
|
||||
cerr << _canvas->render_indent() << "render "
|
||||
<< ' '
|
||||
<< (*i)->whatami()
|
||||
<< ' '
|
||||
<< (*i)->name
|
||||
<< " item = "
|
||||
<< item
|
||||
<< " intersect = "
|
||||
<< draw.get()
|
||||
<< endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -287,6 +287,103 @@ Item::reparent (Group* new_parent)
|
|||
_parent->add (this);
|
||||
}
|
||||
|
||||
bool
|
||||
Item::common_ancestor_within (uint32_t limit, const Item& other) const
|
||||
{
|
||||
uint32_t d1 = depth();
|
||||
uint32_t d2 = other.depth();
|
||||
const Item* i1 = this;
|
||||
const Item* i2 = &other;
|
||||
|
||||
/* move towards root until we are at the same level
|
||||
for both items
|
||||
*/
|
||||
|
||||
while (d1 != d2) {
|
||||
if (d1 > d2) {
|
||||
i1 = i1->parent();
|
||||
d1--;
|
||||
limit--;
|
||||
} else {
|
||||
i2 = i2->parent();
|
||||
d2--;
|
||||
limit--;
|
||||
}
|
||||
if (limit == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* now see if there is a common parent */
|
||||
|
||||
while (i1 != i2) {
|
||||
if (i1) {
|
||||
i1 = i1->parent();
|
||||
}
|
||||
if (i2) {
|
||||
i2 = i2->parent ();
|
||||
}
|
||||
|
||||
limit--;
|
||||
if (limit == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const Item*
|
||||
Item::closest_ancestor_with (const Item& other) const
|
||||
{
|
||||
uint32_t d1 = depth();
|
||||
uint32_t d2 = other.depth();
|
||||
const Item* i1 = this;
|
||||
const Item* i2 = &other;
|
||||
|
||||
/* move towards root until we are at the same level
|
||||
for both items
|
||||
*/
|
||||
|
||||
while (d1 != d2) {
|
||||
if (d1 > d2) {
|
||||
i1 = i1->parent();
|
||||
d1--;
|
||||
} else {
|
||||
i2 = i2->parent();
|
||||
d2--;
|
||||
}
|
||||
}
|
||||
|
||||
/* now see if there is a common parent */
|
||||
|
||||
while (i1 != i2) {
|
||||
if (i1) {
|
||||
i1 = i1->parent();
|
||||
}
|
||||
if (i2) {
|
||||
i2 = i2->parent ();
|
||||
}
|
||||
}
|
||||
|
||||
return i1;
|
||||
}
|
||||
|
||||
bool
|
||||
Item::is_descendant_of (const Item& candidate) const
|
||||
{
|
||||
Item const * i = _parent;
|
||||
|
||||
while (i) {
|
||||
if (i == &candidate) {
|
||||
return true;
|
||||
}
|
||||
i = i->parent();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
Item::grab_focus ()
|
||||
{
|
||||
|
@ -437,9 +534,22 @@ Item::whatami () const
|
|||
return type.substr (type.find_last_of (':') + 1);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
Item::depth () const
|
||||
{
|
||||
Item* i = _parent;
|
||||
int d = 0;
|
||||
while (i) {
|
||||
++d;
|
||||
i = i->parent();
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
ostream&
|
||||
ArdourCanvas::operator<< (ostream& o, const Item& i)
|
||||
{
|
||||
i.dump (o);
|
||||
return o;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue