/** * Configures this layer as reactive to clicks and touches, or not. You usually don't have to do * this automatically because a layer is automatically marked as interactive (along with all of * its parents) when a listener is added to its {@link #events} signal. * * <p>A {@link GroupLayer} will be made non-interactive automatically if an event is dispatched * to it and it discovers that it no longer has any interactive children. Manual management of * interactivity is thus generally only useful for "leaf" nodes in the scene graph. * * @return a reference to this layer for call chaining. */ public Layer setInteractive(boolean interactive) { if (interactive() != interactive) { // if we're being made interactive, active our parent as well, if we have one if (interactive && parent != null) parent.setInteractive(interactive); setFlag(Flag.INTERACTIVE, interactive); } return this; }
/** * Adds a layer to the bottom of the group. Because the {@link Layer} hierarchy is a tree, if * {@code child} is already a child of another {@link GroupLayer}, it will be removed before * being added to this {@link GroupLayer}. */ public void add(Layer child) { // optimization if we're requested to add a child that's already added GroupLayer parent = child.parent(); if (parent == this) return; // if this child has equal or greater depth to the last child, we can append directly and avoid // a log(N) search; this is helpful when all children have the same depth int count = children.size(), index; if (count == 0 || children.get(count-1).depth() <= child.depth()) index = count; // otherwise find the appropriate insertion point via binary search else index = findInsertion(child.depth()); // remove the child from any existing parent, preventing multiple parents if (parent != null) parent.remove(child); children.add(index, child); child.setParent(this); if (state.get() == State.ADDED) child.onAdd(); // if this child is active, we need to become active if (child.interactive()) setInteractive(true); }
@Override public Layer hitTestDefault(Point point) { float x = point.x, y = point.y; boolean sawInteractiveChild = false; // we check back to front as children are ordered "lowest" first for (int ii = children.size()-1; ii >= 0; ii--) { Layer child = children.get(ii); if (!child.interactive()) continue; // ignore non-interactive children sawInteractiveChild = true; // note that we saw an interactive child if (!child.visible()) continue; // ignore invisible children try { // transform the point into the child's coordinate system child.transform().inverseTransform(point.set(x, y), point); point.x += child.originX(); point.y += child.originY(); Layer l = child.hitTest(point); if (l != null) return l; } catch (NoninvertibleTransformException nte) { // Degenerate transform means no hit continue; } } // if we saw no interactive children and we don't have listeners registered directly on this // group, clear our own interactive flag; this lazily deactivates this group after its // interactive children have been deactivated or removed if (!sawInteractiveChild && !hasEventListeners()) setInteractive(false); return super.hitTestDefault(point); }