diff options
-rw-r--r-- | libs/canvas/canvas.cc | 182 | ||||
-rw-r--r-- | libs/canvas/canvas/canvas.h | 10 | ||||
-rw-r--r-- | libs/canvas/canvas/group.h | 2 | ||||
-rw-r--r-- | libs/canvas/canvas/lookup_table.h | 65 | ||||
-rw-r--r-- | libs/canvas/curve.cc | 1 | ||||
-rw-r--r-- | libs/canvas/group.cc | 12 | ||||
-rw-r--r-- | libs/canvas/lookup_table.cc | 67 | ||||
-rw-r--r-- | libs/canvas/polygon.cc | 2 |
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*>(©)); + return deliver_event (reinterpret_cast<GdkEvent*>(©)); } /** 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*>(©)); + return deliver_event (reinterpret_cast<GdkEvent*>(©)); } /** 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*> (©)); + return deliver_event (reinterpret_cast<GdkEvent*> (©)); } 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; } |