summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2013-12-12 10:03:33 -0500
committerPaul Davis <paul@linuxaudiosystems.com>2013-12-12 10:03:33 -0500
commit88732abd0177f9ee9f4be780e3ffe724ef798c64 (patch)
treebb5d57d21d42b26875298c09cc054a30e594d931
parent9fb3247350ffbfe0dda0ec31f8562bf1afad2d34 (diff)
change event propagation to be based on parent/child lineage, not z-axis stacking, plus some more alterations to try to get enter/leave working
-rw-r--r--libs/canvas/canvas.cc182
-rw-r--r--libs/canvas/canvas/canvas.h10
-rw-r--r--libs/canvas/canvas/group.h2
-rw-r--r--libs/canvas/canvas/lookup_table.h65
-rw-r--r--libs/canvas/curve.cc1
-rw-r--r--libs/canvas/group.cc12
-rw-r--r--libs/canvas/lookup_table.cc67
-rw-r--r--libs/canvas/polygon.cc2
8 files changed, 213 insertions, 128 deletions
diff --git a/libs/canvas/canvas.cc b/libs/canvas/canvas.cc
index 325fa77b98..7c0fa28bf0 100644
--- a/libs/canvas/canvas.cc
+++ b/libs/canvas/canvas.cc
@@ -22,6 +22,7 @@
* @brief Implementation of the main canvas classes.
*/
+#include <list>
#include <cassert>
#include <gtkmm/adjustment.h>
#include <gtkmm/label.h>
@@ -256,7 +257,9 @@ Canvas::queue_draw_item_area (Item* item, Rect area)
/** Construct a GtkCanvas */
GtkCanvas::GtkCanvas ()
- : _grabbed_item (0)
+ : _current_item (0)
+ , _new_current_item (0)
+ , _grabbed_item (0)
, _focused_item (0)
{
/* these are the events we want to know about */
@@ -299,12 +302,10 @@ GtkCanvas::enter_leave_items (Duple const & point, int state)
enter_event.send_event = 0;
enter_event.subwindow = 0;
enter_event.mode = GDK_CROSSING_NORMAL;
- enter_event.detail = GDK_NOTIFY_NONLINEAR;
enter_event.focus = FALSE;
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;
@@ -314,72 +315,86 @@ GtkCanvas::enter_leave_items (Duple const & point, int state)
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.
+ /* put all items at point that are event-sensitive and visible and NOT
+ groups into within_items. Note that items is sorted from bottom to
+ top, but we're going to reverse that for within_items so that its
+ first item is the upper-most item that can be chosen as _current_item.
*/
vector<Item const *>::const_iterator i;
- vector<Item const *> newly_entered;
- Item const * new_item;
+ list<Item const *> within_items;
for (i = items.begin(); i != items.end(); ++i) {
- new_item = *i;
+ Item const * new_item = *i;
- if (new_item->ignore_events() || !new_item->visible()) {
+ if (new_item->ignore_events() || dynamic_cast<Group const *>(new_item) != 0) {
continue;
}
+
+ within_items.push_front (new_item);
+ }
- pair<set<Item const *>::iterator,bool> res = within_items.insert (new_item);
-
- if (res.second) {
- newly_entered.push_back (new_item);
+ if (within_items.empty()) {
+ /* no items at point */
+ if (_current_item) {
+ leave_event.detail = GDK_NOTIFY_UNKNOWN;
+ DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("Leave %1 %2\n", _current_item->whatami(), _current_item->name));
+ deliver_event (reinterpret_cast<GdkEvent*> (&leave_event));
+ _current_item = 0;
}
+ return;
+ }
+
+ if (within_items.front() == _current_item) {
+ /* uppermost item at point is already _current_item */
+ return;
}
- /* 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_current_item = within_items.front();
+
+ if (_current_item) {
+
+ if (_new_current_item->is_descendant_of (*_current_item)) {
+ leave_event.detail = GDK_NOTIFY_INFERIOR;
+ enter_event.detail = GDK_NOTIFY_ANCESTOR;
+ } else if (_current_item->is_descendant_of (*_new_current_item)) {
+ leave_event.detail = GDK_NOTIFY_ANCESTOR;
+ enter_event.detail = GDK_NOTIFY_INFERIOR;
+ } else {
+ leave_event.detail = GDK_NOTIFY_UNKNOWN;
+ enter_event.detail = GDK_NOTIFY_UNKNOWN;
+ }
- new_item = *i;
+ std::cerr << "CROSS from "
+ << _current_item->whatami() << '/' << _current_item->name
+ << " to "
+ << _new_current_item->whatami() << '/' << _new_current_item->name
+ << " detail = " << leave_event.detail
+ << '\n';
+
+ DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("Leave %1 %2\n", _current_item->whatami(), _current_item->name));
+ deliver_event (reinterpret_cast<GdkEvent*> (&leave_event));
+ _current_item = 0;
- boost::optional<Rect> bbox = new_item->bounding_box();
+ } else {
- if (bbox) {
- if (!new_item->item_to_canvas (bbox.get()).contains (point)) {
- leave_event.detail = GDK_NOTIFY_UNKNOWN;
- 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);
- }
- }
+ enter_event.detail = GDK_NOTIFY_UNKNOWN;
- i = tmp;
}
- /* 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_iterator i = newly_entered.begin(); i != newly_entered.end(); ++i) {
- new_item = *i;
-
- new_item->Event (reinterpret_cast<GdkEvent*> (&enter_event));
- DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("Enter %1 %2\n", new_item->whatami(), new_item->name));
+ /* _new_current_item could potentially have been reset when handling
+ * the leave event. if it has, there is nothing to do here.
+ */
+
+ if (!_new_current_item) {
+ return;
}
-#if 1
- 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
+ _current_item = _new_current_item;
+ deliver_event (reinterpret_cast<GdkEvent*> (&enter_event));
+
+ DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("Enter %1 %2\n", _current_item->whatami(), _current_item->name));
}
/** Deliver an event to the appropriate item; either the grabbed item, or
@@ -388,7 +403,7 @@ GtkCanvas::enter_leave_items (Duple const & point, int state)
* @param event The event.
*/
bool
-GtkCanvas::deliver_event (Duple point, GdkEvent* event)
+GtkCanvas::deliver_event (GdkEvent* event)
{
/* Point in in canvas coordinate space */
@@ -399,51 +414,35 @@ GtkCanvas::deliver_event (Duple point, GdkEvent* event)
return _grabbed_item->Event (event);
}
- /* find the items that exist at the event's position */
- vector<Item const *> items;
- _root.add_items_at_point (point, items);
+ if (!_current_item) {
+ return false;
+ }
- DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("%1 possible items at %2 to deliver event to\n", items.size(), point));
+ /* run through the items from child to parent, until one claims the event */
- /* run through the items under the event, from top to bottom, until one claims the event */
- vector<Item const *>::const_reverse_iterator i = items.rbegin ();
- while (i != items.rend()) {
+ for (Item* item = const_cast<Item*> (_current_item); item; item = item->parent()) {
- if ((*i)->ignore_events ()) {
+ if (item->ignore_events ()) {
// DEBUG_TRACE (
// PBD::DEBUG::CanvasEvents,
- // string_compose ("canvas event ignored by %1 %2\n", (*i)->whatami(), (*i)->name.empty() ? "[unknown]" : (*i)->name)
+ // string_compose ("canvas event ignored by %1 %2\n", item->whatami(), item->name.empty() ? "[unknown]" : item->name)
// );
- ++i;
continue;
}
- if ((*i)->Event (event)) {
+ if (item->Event (event)) {
/* this item has just handled the event */
DEBUG_TRACE (
PBD::DEBUG::CanvasEvents,
- string_compose ("canvas event handled by %1 %2\n", (*i)->whatami(), (*i)->name.empty() ? "[unknown]" : (*i)->name)
+ string_compose ("canvas event handled by %1 %2\n", item->whatami(), item->name.empty() ? "[unknown]" : item->name)
);
return true;
}
- DEBUG_TRACE (
- PBD::DEBUG::CanvasEvents,
- string_compose ("canvas event left unhandled by %1 %2\n", (*i)->whatami(), (*i)->name.empty() ? "[unknown]" : (*i)->name)
- );
-
- ++i;
+ DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("canvas event left unhandled by %1 %2\n", item->whatami(), item->name.empty() ? "[unknown]" : item->name));
}
- /* debugging */
- if (PBD::debug_bits & PBD::DEBUG::CanvasEvents) {
- while (i != items.rend()) {
- DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("canvas event not seen by %1\n", (*i)->name.empty() ? "[unknown]" : (*i)->name));
- ++i;
- }
- }
-
return false;
}
@@ -461,7 +460,13 @@ GtkCanvas::item_going_away (Item* item, boost::optional<Rect> bounding_box)
/* no need to send a leave event to this item, since it is going away
*/
- within_items.erase (item);
+ if (_new_current_item == item) {
+ _new_current_item = 0;
+ }
+
+ if (_current_item == item) {
+ _current_item = 0;
+ }
if (_grabbed_item == item) {
_grabbed_item = 0;
@@ -520,8 +525,9 @@ GtkCanvas::on_button_press_event (GdkEventButton* ev)
for scroll if this GtkCanvas is in a GtkCanvasViewport.
*/
+ enter_leave_items (where, ev->state);
DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("canvas button press @ %1, %2 => %3\n", ev->x, ev->y, where));
- return deliver_event (where, reinterpret_cast<GdkEvent*>(&copy));
+ return deliver_event (reinterpret_cast<GdkEvent*>(&copy));
}
/** Handler for GDK button release events.
@@ -545,8 +551,9 @@ GtkCanvas::on_button_release_event (GdkEventButton* ev)
for scroll if this GtkCanvas is in a GtkCanvasViewport.
*/
+ enter_leave_items (where, ev->state);
DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("canvas button release @ %1, %2 => %3\n", ev->x, ev->y, where));
- return deliver_event (where, reinterpret_cast<GdkEvent*>(&copy));
+ return deliver_event (reinterpret_cast<GdkEvent*>(&copy));
}
/** Handler for GDK motion events.
@@ -568,7 +575,7 @@ GtkCanvas::on_motion_notify_event (GdkEventMotion* ev)
/* Coordinates in "copy" will be canvas coordinates,
*/
- DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("canvas motion @ %1, %2\n", ev->x, ev->y));
+ // DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("canvas motion @ %1, %2\n", ev->x, ev->y));
if (_grabbed_item) {
/* if we have a grabbed item, it gets just the motion event,
@@ -587,7 +594,7 @@ GtkCanvas::on_motion_notify_event (GdkEventMotion* ev)
recompute the list in deliver_event.
*/
- return deliver_event (point, reinterpret_cast<GdkEvent*> (&copy));
+ return deliver_event (reinterpret_cast<GdkEvent*> (&copy));
}
bool
@@ -601,10 +608,23 @@ GtkCanvas::on_enter_notify_event (GdkEventCrossing* ev)
bool
GtkCanvas::on_leave_notify_event (GdkEventCrossing* /*ev*/)
{
- within_items.clear ();
+ _current_item = 0;
+ _new_current_item = 0;
return true;
}
+bool
+GtkCanvas::on_key_press_event (GdkEventKey* ev)
+{
+ return false;
+}
+
+bool
+GtkCanvas::on_key_release_event (GdkEventKey* ev)
+{
+ return false;
+}
+
/** Called to request a redraw of our canvas.
* @param area Area to redraw, in canvas coordinates.
*/
diff --git a/libs/canvas/canvas/canvas.h b/libs/canvas/canvas/canvas.h
index 981ea05346..3a6659b7f2 100644
--- a/libs/canvas/canvas/canvas.h
+++ b/libs/canvas/canvas/canvas.h
@@ -150,10 +150,12 @@ protected:
bool on_motion_notify_event (GdkEventMotion *);
bool on_enter_notify_event (GdkEventCrossing*);
bool on_leave_notify_event (GdkEventCrossing*);
+ bool on_key_press_event (GdkEventKey*);
+ bool on_key_release_event (GdkEventKey*);
bool button_handler (GdkEventButton *);
bool motion_notify_handler (GdkEventMotion *);
- bool deliver_event (Duple, GdkEvent *);
+ bool deliver_event (GdkEvent *);
void enter_leave_items (int state);
void enter_leave_items (Duple const &, int state);
@@ -162,8 +164,10 @@ private:
void item_going_away (Item *, boost::optional<Rect>);
bool send_leave_event (Item const *, double, double) const;
- /** Items that the pointer is currently within */
- std::set<Item const *> within_items;
+ /** Item currently chosen for event delivery based on pointer position */
+ Item const * _current_item;
+ /** Item pending as _current_item */
+ Item const * _new_current_item;
/** the item that is currently grabbed, or 0 */
Item const * _grabbed_item;
/** the item that currently has key focus or 0 */
diff --git a/libs/canvas/canvas/group.h b/libs/canvas/canvas/group.h
index 9a72d50873..12319c615e 100644
--- a/libs/canvas/canvas/group.h
+++ b/libs/canvas/canvas/group.h
@@ -44,7 +44,7 @@ public:
std::list<Item*> const & items () const {
return _items;
}
-
+
void raise_child_to_top (Item *);
void raise_child (Item *, int);
void lower_child_to_bottom (Item *);
diff --git a/libs/canvas/canvas/lookup_table.h b/libs/canvas/canvas/lookup_table.h
index 4ab69b6167..c9a1265051 100644
--- a/libs/canvas/canvas/lookup_table.h
+++ b/libs/canvas/canvas/lookup_table.h
@@ -34,50 +34,53 @@ class Group;
class LookupTable
{
public:
- LookupTable (Group const &);
- virtual ~LookupTable ();
-
- virtual std::vector<Item*> get (Rect const &) = 0;
- virtual std::vector<Item*> items_at_point (Duple) const = 0;
+ LookupTable (Group const &);
+ virtual ~LookupTable ();
+
+ virtual std::vector<Item*> get (Rect const &) = 0;
+ virtual std::vector<Item*> items_at_point (Duple const &) const = 0;
+ virtual bool has_item_at_point (Duple const & point) const = 0;
protected:
- Group const & _group;
+ Group const & _group;
};
class DumbLookupTable : public LookupTable
{
public:
- DumbLookupTable (Group const &);
-
- std::vector<Item*> get (Rect const &);
- std::vector<Item*> items_at_point (Duple) const;
+ DumbLookupTable (Group const &);
+
+ std::vector<Item*> get (Rect const &);
+ std::vector<Item*> items_at_point (Duple const &) const;
+ bool has_item_at_point (Duple const & point) const;
};
class OptimizingLookupTable : public LookupTable
{
public:
- OptimizingLookupTable (Group const &, int);
- ~OptimizingLookupTable ();
- std::vector<Item*> get (Rect const &);
- std::vector<Item*> items_at_point (Duple) const;
-
- static int default_items_per_cell;
-
-private:
-
- void area_to_indices (Rect const &, int &, int &, int &, int &) const;
- void point_to_indices (Duple, int &, int &) const;
-
- friend class ::OptimizingLookupTableTest;
-
- typedef std::vector<Item*> Cell;
- int _items_per_cell;
- int _dimension;
- Duple _cell_size;
- Duple _offset;
- Cell** _cells;
- bool _added;
+ OptimizingLookupTable (Group const &, int);
+ ~OptimizingLookupTable ();
+ std::vector<Item*> get (Rect const &);
+ std::vector<Item*> items_at_point (Duple const &) const;
+ bool has_item_at_point (Duple const & point) const;
+
+ static int default_items_per_cell;
+
+ private:
+
+ void area_to_indices (Rect const &, int &, int &, int &, int &) const;
+ void point_to_indices (Duple, int &, int &) const;
+
+ friend class ::OptimizingLookupTableTest;
+
+ typedef std::vector<Item*> Cell;
+ int _items_per_cell;
+ int _dimension;
+ Duple _cell_size;
+ Duple _offset;
+ Cell** _cells;
+ bool _added;
};
}
diff --git a/libs/canvas/curve.cc b/libs/canvas/curve.cc
index 09fb5669a1..de988ee4b2 100644
--- a/libs/canvas/curve.cc
+++ b/libs/canvas/curve.cc
@@ -225,7 +225,6 @@ Curve::covers (Duple const & pc) const
const Coord dy2 = dy * dy;
if ((dx2 < 2.0 && dy2 < 2.0) || (dx2 + dy2 < 4.0)) {
- std::cerr << whatami() << '/' << name << " COVERS " << point << '\n';
return true;
}
}
diff --git a/libs/canvas/group.cc b/libs/canvas/group.cc
index 6293155021..bcea16dd76 100644
--- a/libs/canvas/group.cc
+++ b/libs/canvas/group.cc
@@ -293,22 +293,24 @@ Group::child_changed ()
void
Group::add_items_at_point (Duple const point, vector<Item const *>& items) const
{
- /* Point is in canvas coordinate system */
-
boost::optional<Rect> const bbox = bounding_box ();
+ /* Point is in canvas coordinate system */
+
if (!bbox || !item_to_canvas (bbox.get()).contains (point)) {
return;
}
- /* this adds this group itself to the list of items at point */
- Item::add_items_at_point (point, items);
-
/* now recurse and add any items within our group that contain point */
ensure_lut ();
vector<Item*> our_items = _lut->items_at_point (point);
+ if (!our_items.empty()) {
+ /* this adds this group itself to the list of items at point */
+ Item::add_items_at_point (point, items);
+ }
+
for (vector<Item*>::iterator i = our_items.begin(); i != our_items.end(); ++i) {
(*i)->add_items_at_point (point, items);
}
diff --git a/libs/canvas/lookup_table.cc b/libs/canvas/lookup_table.cc
index 8fd929d325..f88531537a 100644
--- a/libs/canvas/lookup_table.cc
+++ b/libs/canvas/lookup_table.cc
@@ -50,7 +50,26 @@ DumbLookupTable::get (Rect const &)
}
vector<Item *>
-DumbLookupTable::items_at_point (Duple point) const
+DumbLookupTable::items_at_point (Duple const & point) const
+{
+ /* Point is in canvas coordinate system */
+
+ list<Item *> const & items (_group.items ());
+ vector<Item *> vitems;
+
+ for (list<Item *>::const_iterator i = items.begin(); i != items.end(); ++i) {
+
+ if ((*i)->covers (point)) {
+ // std::cerr << "\t\t" << (*i)->whatami() << '/' << (*i)->name << " covers " << point << std::endl;
+ vitems.push_back (*i);
+ }
+ }
+
+ return vitems;
+}
+
+bool
+DumbLookupTable::has_item_at_point (Duple const & point) const
{
/* Point is in canvas coordinate system */
@@ -64,12 +83,13 @@ DumbLookupTable::items_at_point (Duple point) const
}
if ((*i)->covers (point)) {
- std::cerr << "\t\t" << (*i)->whatami() << '/' << (*i)->name << " covers " << point << std::endl;
- vitems.push_back (*i);
+ // std::cerr << "\t\t" << (*i)->whatami() << '/' << (*i)->name << " covers " << point << std::endl;
+ return true;
+
}
}
- return vitems;
+ return false;
}
OptimizingLookupTable::OptimizingLookupTable (Group const & group, int items_per_cell)
@@ -191,7 +211,7 @@ OptimizingLookupTable::point_to_indices (Duple point, int& x, int& y) const
}
vector<Item*>
-OptimizingLookupTable::items_at_point (Duple point) const
+OptimizingLookupTable::items_at_point (Duple const & point) const
{
int x;
int y;
@@ -226,6 +246,43 @@ OptimizingLookupTable::items_at_point (Duple point) const
return items;
}
+
+bool
+OptimizingLookupTable::has_item_at_point (Duple const & point) const
+{
+ int x;
+ int y;
+ point_to_indices (point, x, y);
+
+ if (x >= _dimension) {
+ cout << "WARNING: x=" << x << ", dim=" << _dimension << ", px=" << point.x << " cellsize=" << _cell_size << "\n";
+ }
+
+ if (y >= _dimension) {
+ cout << "WARNING: y=" << y << ", dim=" << _dimension << ", py=" << point.y << " cellsize=" << _cell_size << "\n";
+ }
+
+ /* XXX: hmm */
+ x = min (_dimension - 1, x);
+ y = min (_dimension - 1, y);
+
+ assert (x >= 0);
+ assert (y >= 0);
+
+ Cell const & cell = _cells[x][y];
+ vector<Item*> items;
+ for (Cell::const_iterator i = cell.begin(); i != cell.end(); ++i) {
+ boost::optional<Rect> const item_bbox = (*i)->bounding_box ();
+ if (item_bbox) {
+ Rect parent_bbox = (*i)->item_to_parent (item_bbox.get ());
+ if (parent_bbox.contains (point)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
/** @param area Area in our owning group's coordinates */
vector<Item*>
diff --git a/libs/canvas/polygon.cc b/libs/canvas/polygon.cc
index 37046f4d4a..2e81823616 100644
--- a/libs/canvas/polygon.cc
+++ b/libs/canvas/polygon.cc
@@ -118,7 +118,7 @@ Polygon::covers (Duple const & point) const
}
j = i;
}
-
+
return oddNodes;
}