tripleplay.ui.Selector Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of tripleplay Show documentation
Show all versions of tripleplay Show documentation
Utilities for use in PlayN-based games.
//
// Triple Play - utilities for use in PlayN-based games
// Copyright (c) 2011-2014, Three Rings Design, Inc. - All rights reserved.
// http://github.com/threerings/tripleplay/blob/master/LICENSE
package tripleplay.ui;
import react.Slot;
import react.Value;
import react.ValueView;
/**
* Maintains a single selected item among a specified set of {@code Element} instances. The
* elements may be added individually, or the children of an {@code Elements} may be tracked
* automatically.
*
* A click on a tracked element that implements {@code Clickable} makes it the selected item, or
* {@code selected} can be used to manually control the selected item.
*/
public class Selector
{
/** The selected item. May be updated to set the selection manually. */
public final Value> selected = Value.create(null);
/** Create a selector with a null initial selection. */
public Selector () {
selected.connect(new ValueView.Listener> () {
@Override public void onChange (Element> selected, Element> deselected) {
if (deselected != null) get(deselected).update(false);
if (selected != null) get(selected).update(true);
}
});
}
/** Creates a selector containing the children of elements with initialSelection selected. */
public Selector (Elements> elements, Element> initialSelection) {
this();
add(elements);
if (initialSelection instanceof Togglable>) {
selected.update(initialSelection);
}
}
/**
* Tracks the children of {@code elements} for setting the selection. Children subsequently
* added or removed from {@code elements} are automatically handled appropriately.
*/
public Selector add (Elements> elements) {
for (Element> child : elements) {
_addSlot.onEmit(child);
}
elements.childAdded().connect(_addSlot);
elements.childRemoved().connect(_removeSlot);
return this;
}
/** Prevent a deselection (null {@link #selected}.get()) occurring as a result of toggling
* the currently selected button off. */
public Selector preventDeselection () {
_preventDeselection = true;
return this;
}
/**
* Stops tracking the children of {@code elements} for setting the selection.
*/
public Selector remove (Elements> elements) {
for (Element> child : elements) {
_removeSlot.onEmit(child);
}
elements.childAdded().disconnect(_addSlot);
elements.childRemoved().disconnect(_removeSlot);
return this;
}
/**
* Tracks one or more elements.
*/
public Selector add (Element> elem, Element>... more) {
_addSlot.onEmit(elem);
for (Element> e : more) {
_addSlot.onEmit(e);
}
return this;
}
/**
* Stops tracking one or more elements.
*/
public Selector remove (Element> elem, Element>... more) {
_removeSlot.onEmit(elem);
for (Element> e : more) {
_removeSlot.onEmit(e);
}
return this;
}
/**
* Internal method to get the selection value of an element (non-null).
*/
protected Value get (Element> elem) {
return ((Togglable>)elem).selected();
}
protected final Slot> _addSlot = new Slot>() {
@Override public void onEmit (Element> child) {
if (child instanceof Togglable>) {
((Togglable>)child).clicked().connect(_clickSlot);
}
}
};
protected final Slot> _removeSlot = new Slot>() {
@Override public void onEmit (Element> removed) {
if (removed instanceof Togglable>) {
((Togglable>)removed).clicked().disconnect(_clickSlot);
}
if (selected.get() == removed) selected.update(null);
}
};
protected final Slot> _clickSlot = new Slot>() {
@Override public void onEmit (Element> clicked) {
final Value sel = get(clicked);
if (_preventDeselection) {
if (!sel.get()) {
sel.update(true);
return;
}
}
selected.update(sel.get() ? clicked : null);
}
};
protected boolean _preventDeselection;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy