mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-16 03:36:32 +01:00
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
This commit is contained in:
parent
9fb3247350
commit
88732abd01
8 changed files with 217 additions and 132 deletions
|
|
@ -22,6 +22,7 @@
|
||||||
* @brief Implementation of the main canvas classes.
|
* @brief Implementation of the main canvas classes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <list>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <gtkmm/adjustment.h>
|
#include <gtkmm/adjustment.h>
|
||||||
#include <gtkmm/label.h>
|
#include <gtkmm/label.h>
|
||||||
|
|
@ -256,7 +257,9 @@ Canvas::queue_draw_item_area (Item* item, Rect area)
|
||||||
|
|
||||||
/** Construct a GtkCanvas */
|
/** Construct a GtkCanvas */
|
||||||
GtkCanvas::GtkCanvas ()
|
GtkCanvas::GtkCanvas ()
|
||||||
: _grabbed_item (0)
|
: _current_item (0)
|
||||||
|
, _new_current_item (0)
|
||||||
|
, _grabbed_item (0)
|
||||||
, _focused_item (0)
|
, _focused_item (0)
|
||||||
{
|
{
|
||||||
/* these are the events we want to know about */
|
/* 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.send_event = 0;
|
||||||
enter_event.subwindow = 0;
|
enter_event.subwindow = 0;
|
||||||
enter_event.mode = GDK_CROSSING_NORMAL;
|
enter_event.mode = GDK_CROSSING_NORMAL;
|
||||||
enter_event.detail = GDK_NOTIFY_NONLINEAR;
|
|
||||||
enter_event.focus = FALSE;
|
enter_event.focus = FALSE;
|
||||||
enter_event.state = state;
|
enter_event.state = state;
|
||||||
enter_event.x = point.x;
|
enter_event.x = point.x;
|
||||||
enter_event.y = point.y;
|
enter_event.y = point.y;
|
||||||
enter_event.detail = GDK_NOTIFY_UNKNOWN;
|
|
||||||
|
|
||||||
GdkEventCrossing leave_event = enter_event;
|
GdkEventCrossing leave_event = enter_event;
|
||||||
leave_event.type = GDK_LEAVE_NOTIFY;
|
leave_event.type = GDK_LEAVE_NOTIFY;
|
||||||
|
|
@ -314,72 +315,86 @@ GtkCanvas::enter_leave_items (Duple const & point, int state)
|
||||||
vector<Item const *> items;
|
vector<Item const *> items;
|
||||||
_root.add_items_at_point (point, 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
|
/* put all items at point that are event-sensitive and visible and NOT
|
||||||
is a new addition, also put them into newly_entered for later deliver of enter events.
|
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 *>::const_iterator i;
|
||||||
vector<Item const *> newly_entered;
|
list<Item const *> within_items;
|
||||||
Item const * new_item;
|
|
||||||
|
|
||||||
for (i = items.begin(); i != items.end(); ++i) {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
pair<set<Item const *>::iterator,bool> res = within_items.insert (new_item);
|
within_items.push_front (new_item);
|
||||||
|
|
||||||
if (res.second) {
|
|
||||||
newly_entered.push_back (new_item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* for every item in "within_items", check that we are still within them. if not,
|
if (within_items.empty()) {
|
||||||
send a leave event, and remove them from "within_items"
|
/* no items at point */
|
||||||
*/
|
if (_current_item) {
|
||||||
|
leave_event.detail = GDK_NOTIFY_UNKNOWN;
|
||||||
for (set<Item const *>::const_iterator i = within_items.begin(); i != within_items.end(); ) {
|
DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("Leave %1 %2\n", _current_item->whatami(), _current_item->name));
|
||||||
|
deliver_event (reinterpret_cast<GdkEvent*> (&leave_event));
|
||||||
set<Item const *>::const_iterator tmp = i;
|
_current_item = 0;
|
||||||
++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;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
i = tmp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* for every item in "newly_entered", send an enter event (and propagate it up the
|
if (within_items.front() == _current_item) {
|
||||||
item tree until it is handled
|
/* uppermost item at point is already _current_item */
|
||||||
*/
|
return;
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 1
|
_new_current_item = within_items.front();
|
||||||
cerr << "Within:\n";
|
|
||||||
for (set<Item const *>::const_iterator i = within_items.begin(); i != within_items.end(); ++i) {
|
if (_current_item) {
|
||||||
cerr << '\t' << (*i)->whatami() << '/' << (*i)->name << endl;
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
enter_event.detail = GDK_NOTIFY_UNKNOWN;
|
||||||
|
|
||||||
}
|
}
|
||||||
cerr << "----\n";
|
|
||||||
#endif
|
/* _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;
|
||||||
|
}
|
||||||
|
|
||||||
|
_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
|
/** 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.
|
* @param event The event.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
GtkCanvas::deliver_event (Duple point, GdkEvent* event)
|
GtkCanvas::deliver_event (GdkEvent* event)
|
||||||
{
|
{
|
||||||
/* Point in in canvas coordinate space */
|
/* Point in in canvas coordinate space */
|
||||||
|
|
||||||
|
|
@ -399,51 +414,35 @@ GtkCanvas::deliver_event (Duple point, GdkEvent* event)
|
||||||
return _grabbed_item->Event (event);
|
return _grabbed_item->Event (event);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* find the items that exist at the event's position */
|
if (!_current_item) {
|
||||||
vector<Item const *> items;
|
return false;
|
||||||
_root.add_items_at_point (point, items);
|
}
|
||||||
|
|
||||||
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 */
|
for (Item* item = const_cast<Item*> (_current_item); item; item = item->parent()) {
|
||||||
vector<Item const *>::const_reverse_iterator i = items.rbegin ();
|
|
||||||
while (i != items.rend()) {
|
|
||||||
|
|
||||||
if ((*i)->ignore_events ()) {
|
if (item->ignore_events ()) {
|
||||||
// DEBUG_TRACE (
|
// DEBUG_TRACE (
|
||||||
// PBD::DEBUG::CanvasEvents,
|
// 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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((*i)->Event (event)) {
|
if (item->Event (event)) {
|
||||||
/* this item has just handled the event */
|
/* this item has just handled the event */
|
||||||
DEBUG_TRACE (
|
DEBUG_TRACE (
|
||||||
PBD::DEBUG::CanvasEvents,
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_TRACE (
|
DEBUG_TRACE (PBD::DEBUG::CanvasEvents, string_compose ("canvas event left unhandled by %1 %2\n", item->whatami(), item->name.empty() ? "[unknown]" : item->name));
|
||||||
PBD::DEBUG::CanvasEvents,
|
|
||||||
string_compose ("canvas event left unhandled by %1 %2\n", (*i)->whatami(), (*i)->name.empty() ? "[unknown]" : (*i)->name)
|
|
||||||
);
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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;
|
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
|
/* 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) {
|
if (_grabbed_item == item) {
|
||||||
_grabbed_item = 0;
|
_grabbed_item = 0;
|
||||||
|
|
@ -520,8 +525,9 @@ GtkCanvas::on_button_press_event (GdkEventButton* ev)
|
||||||
for scroll if this GtkCanvas is in a GtkCanvasViewport.
|
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));
|
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.
|
/** 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.
|
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));
|
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.
|
/** Handler for GDK motion events.
|
||||||
|
|
@ -568,7 +575,7 @@ GtkCanvas::on_motion_notify_event (GdkEventMotion* ev)
|
||||||
/* Coordinates in "copy" will be canvas coordinates,
|
/* 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 (_grabbed_item) {
|
||||||
/* if we have a grabbed item, it gets just the motion event,
|
/* 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.
|
recompute the list in deliver_event.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return deliver_event (point, reinterpret_cast<GdkEvent*> (©));
|
return deliver_event (reinterpret_cast<GdkEvent*> (©));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
@ -601,10 +608,23 @@ GtkCanvas::on_enter_notify_event (GdkEventCrossing* ev)
|
||||||
bool
|
bool
|
||||||
GtkCanvas::on_leave_notify_event (GdkEventCrossing* /*ev*/)
|
GtkCanvas::on_leave_notify_event (GdkEventCrossing* /*ev*/)
|
||||||
{
|
{
|
||||||
within_items.clear ();
|
_current_item = 0;
|
||||||
|
_new_current_item = 0;
|
||||||
return true;
|
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.
|
/** Called to request a redraw of our canvas.
|
||||||
* @param area Area to redraw, in canvas coordinates.
|
* @param area Area to redraw, in canvas coordinates.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -150,10 +150,12 @@ protected:
|
||||||
bool on_motion_notify_event (GdkEventMotion *);
|
bool on_motion_notify_event (GdkEventMotion *);
|
||||||
bool on_enter_notify_event (GdkEventCrossing*);
|
bool on_enter_notify_event (GdkEventCrossing*);
|
||||||
bool on_leave_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 button_handler (GdkEventButton *);
|
||||||
bool motion_notify_handler (GdkEventMotion *);
|
bool motion_notify_handler (GdkEventMotion *);
|
||||||
bool deliver_event (Duple, GdkEvent *);
|
bool deliver_event (GdkEvent *);
|
||||||
|
|
||||||
void enter_leave_items (int state);
|
void enter_leave_items (int state);
|
||||||
void enter_leave_items (Duple const &, int state);
|
void enter_leave_items (Duple const &, int state);
|
||||||
|
|
@ -162,8 +164,10 @@ private:
|
||||||
void item_going_away (Item *, boost::optional<Rect>);
|
void item_going_away (Item *, boost::optional<Rect>);
|
||||||
bool send_leave_event (Item const *, double, double) const;
|
bool send_leave_event (Item const *, double, double) const;
|
||||||
|
|
||||||
/** Items that the pointer is currently within */
|
/** Item currently chosen for event delivery based on pointer position */
|
||||||
std::set<Item const *> within_items;
|
Item const * _current_item;
|
||||||
|
/** Item pending as _current_item */
|
||||||
|
Item const * _new_current_item;
|
||||||
/** the item that is currently grabbed, or 0 */
|
/** the item that is currently grabbed, or 0 */
|
||||||
Item const * _grabbed_item;
|
Item const * _grabbed_item;
|
||||||
/** the item that currently has key focus or 0 */
|
/** the item that currently has key focus or 0 */
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ public:
|
||||||
std::list<Item*> const & items () const {
|
std::list<Item*> const & items () const {
|
||||||
return _items;
|
return _items;
|
||||||
}
|
}
|
||||||
|
|
||||||
void raise_child_to_top (Item *);
|
void raise_child_to_top (Item *);
|
||||||
void raise_child (Item *, int);
|
void raise_child (Item *, int);
|
||||||
void lower_child_to_bottom (Item *);
|
void lower_child_to_bottom (Item *);
|
||||||
|
|
|
||||||
|
|
@ -34,50 +34,53 @@ class Group;
|
||||||
class LookupTable
|
class LookupTable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LookupTable (Group const &);
|
LookupTable (Group const &);
|
||||||
virtual ~LookupTable ();
|
virtual ~LookupTable ();
|
||||||
|
|
||||||
virtual std::vector<Item*> get (Rect const &) = 0;
|
virtual std::vector<Item*> get (Rect const &) = 0;
|
||||||
virtual std::vector<Item*> items_at_point (Duple) 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:
|
protected:
|
||||||
|
|
||||||
Group const & _group;
|
Group const & _group;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DumbLookupTable : public LookupTable
|
class DumbLookupTable : public LookupTable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DumbLookupTable (Group const &);
|
DumbLookupTable (Group const &);
|
||||||
|
|
||||||
std::vector<Item*> get (Rect const &);
|
std::vector<Item*> get (Rect const &);
|
||||||
std::vector<Item*> items_at_point (Duple) const;
|
std::vector<Item*> items_at_point (Duple const &) const;
|
||||||
|
bool has_item_at_point (Duple const & point) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class OptimizingLookupTable : public LookupTable
|
class OptimizingLookupTable : public LookupTable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OptimizingLookupTable (Group const &, int);
|
OptimizingLookupTable (Group const &, int);
|
||||||
~OptimizingLookupTable ();
|
~OptimizingLookupTable ();
|
||||||
std::vector<Item*> get (Rect const &);
|
std::vector<Item*> get (Rect const &);
|
||||||
std::vector<Item*> items_at_point (Duple) 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;
|
|
||||||
|
static int default_items_per_cell;
|
||||||
private:
|
|
||||||
|
private:
|
||||||
void area_to_indices (Rect const &, int &, int &, int &, int &) const;
|
|
||||||
void point_to_indices (Duple, int &, int &) const;
|
void area_to_indices (Rect const &, int &, int &, int &, int &) const;
|
||||||
|
void point_to_indices (Duple, int &, int &) const;
|
||||||
friend class ::OptimizingLookupTableTest;
|
|
||||||
|
friend class ::OptimizingLookupTableTest;
|
||||||
typedef std::vector<Item*> Cell;
|
|
||||||
int _items_per_cell;
|
typedef std::vector<Item*> Cell;
|
||||||
int _dimension;
|
int _items_per_cell;
|
||||||
Duple _cell_size;
|
int _dimension;
|
||||||
Duple _offset;
|
Duple _cell_size;
|
||||||
Cell** _cells;
|
Duple _offset;
|
||||||
bool _added;
|
Cell** _cells;
|
||||||
|
bool _added;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -225,7 +225,6 @@ Curve::covers (Duple const & pc) const
|
||||||
const Coord dy2 = dy * dy;
|
const Coord dy2 = dy * dy;
|
||||||
|
|
||||||
if ((dx2 < 2.0 && dy2 < 2.0) || (dx2 + dy2 < 4.0)) {
|
if ((dx2 < 2.0 && dy2 < 2.0) || (dx2 + dy2 < 4.0)) {
|
||||||
std::cerr << whatami() << '/' << name << " COVERS " << point << '\n';
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -293,22 +293,24 @@ Group::child_changed ()
|
||||||
void
|
void
|
||||||
Group::add_items_at_point (Duple const point, vector<Item const *>& items) const
|
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 ();
|
boost::optional<Rect> const bbox = bounding_box ();
|
||||||
|
|
||||||
|
/* Point is in canvas coordinate system */
|
||||||
|
|
||||||
if (!bbox || !item_to_canvas (bbox.get()).contains (point)) {
|
if (!bbox || !item_to_canvas (bbox.get()).contains (point)) {
|
||||||
return;
|
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 */
|
/* now recurse and add any items within our group that contain point */
|
||||||
|
|
||||||
ensure_lut ();
|
ensure_lut ();
|
||||||
vector<Item*> our_items = _lut->items_at_point (point);
|
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) {
|
for (vector<Item*>::iterator i = our_items.begin(); i != our_items.end(); ++i) {
|
||||||
(*i)->add_items_at_point (point, items);
|
(*i)->add_items_at_point (point, items);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,26 @@ DumbLookupTable::get (Rect const &)
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<Item *>
|
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 */
|
/* Point is in canvas coordinate system */
|
||||||
|
|
||||||
|
|
@ -64,12 +83,13 @@ DumbLookupTable::items_at_point (Duple point) const
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((*i)->covers (point)) {
|
if ((*i)->covers (point)) {
|
||||||
std::cerr << "\t\t" << (*i)->whatami() << '/' << (*i)->name << " covers " << point << std::endl;
|
// std::cerr << "\t\t" << (*i)->whatami() << '/' << (*i)->name << " covers " << point << std::endl;
|
||||||
vitems.push_back (*i);
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return vitems;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
OptimizingLookupTable::OptimizingLookupTable (Group const & group, int items_per_cell)
|
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*>
|
vector<Item*>
|
||||||
OptimizingLookupTable::items_at_point (Duple point) const
|
OptimizingLookupTable::items_at_point (Duple const & point) const
|
||||||
{
|
{
|
||||||
int x;
|
int x;
|
||||||
int y;
|
int y;
|
||||||
|
|
@ -226,6 +246,43 @@ OptimizingLookupTable::items_at_point (Duple point) const
|
||||||
|
|
||||||
return items;
|
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 */
|
/** @param area Area in our owning group's coordinates */
|
||||||
vector<Item*>
|
vector<Item*>
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,7 @@ Polygon::covers (Duple const & point) const
|
||||||
}
|
}
|
||||||
j = i;
|
j = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
return oddNodes;
|
return oddNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue