
com.badlogic.gdx.scenes.scene2d.utils.Selection Maven / Gradle / Ivy
package com.badlogic.gdx.scenes.scene2d.utils;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener.ChangeEvent;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.OrderedSet;
import com.badlogic.gdx.utils.Pools;
import java.util.Iterator;
/** Manages selected objects. Optionally fires a {@link ChangeEvent} on an actor. Selection changes can be vetoed via
* {@link ChangeEvent#cancel()}.
* @author Nathan Sweet */
public class Selection implements Disableable, Iterable {
private Actor actor;
final OrderedSet selected = new OrderedSet();
private final OrderedSet old = new OrderedSet();
boolean isDisabled;
private boolean toggle;
boolean multiple;
boolean required;
private boolean programmaticChangeEvents = true;
T lastSelected;
/** @param actor An actor to fire {@link ChangeEvent} on when the selection changes, or null. */
public void setActor (Actor actor) {
this.actor = actor;
}
/** Selects or deselects the specified item based on how the selection is configured, whether ctrl is currently pressed, etc.
* This is typically invoked by user interaction. */
public void choose (T item) {
if (item == null) throw new IllegalArgumentException("item cannot be null.");
if (isDisabled) return;
snapshot();
try {
if ((toggle || (!required && selected.size == 1) || UIUtils.ctrl()) && selected.contains(item)) {
if (required && selected.size == 1) return;
selected.remove(item);
lastSelected = null;
} else {
boolean modified = false;
if (!multiple || (!toggle && !UIUtils.ctrl())) {
if (selected.size == 1 && selected.contains(item)) return;
modified = selected.size > 0;
selected.clear();
}
if (!selected.add(item) && !modified) return;
lastSelected = item;
}
if (fireChangeEvent())
revert();
else
changed();
} finally {
cleanup();
}
}
public boolean hasItems () {
return selected.size > 0;
}
public boolean isEmpty () {
return selected.size == 0;
}
public int size () {
return selected.size;
}
public OrderedSet items () {
return selected;
}
/** Returns the first selected item, or null. */
public T first () {
return selected.size == 0 ? null : selected.first();
}
void snapshot () {
old.clear();
old.addAll(selected);
}
void revert () {
selected.clear();
selected.addAll(old);
}
void cleanup () {
old.clear(32);
}
/** Sets the selection to only the specified item. */
public void set (T item) {
if (item == null) throw new IllegalArgumentException("item cannot be null.");
if (selected.size == 1 && selected.first() == item) return;
snapshot();
selected.clear();
selected.add(item);
if (programmaticChangeEvents && fireChangeEvent())
revert();
else {
lastSelected = item;
changed();
}
cleanup();
}
public void setAll (Array items) {
boolean added = false;
snapshot();
lastSelected = null;
selected.clear();
for (int i = 0, n = items.size; i < n; i++) {
T item = items.get(i);
if (item == null) throw new IllegalArgumentException("item cannot be null.");
if (selected.add(item)) added = true;
}
if (added) {
if (programmaticChangeEvents && fireChangeEvent())
revert();
else if (items.size > 0) {
lastSelected = items.peek();
changed();
}
}
cleanup();
}
/** Adds the item to the selection. */
public void add (T item) {
if (item == null) throw new IllegalArgumentException("item cannot be null.");
if (!selected.add(item)) return;
if (programmaticChangeEvents && fireChangeEvent())
selected.remove(item);
else {
lastSelected = item;
changed();
}
}
public void addAll (Array items) {
boolean added = false;
snapshot();
for (int i = 0, n = items.size; i < n; i++) {
T item = items.get(i);
if (item == null) throw new IllegalArgumentException("item cannot be null.");
if (selected.add(item)) added = true;
}
if (added) {
if (programmaticChangeEvents && fireChangeEvent())
revert();
else {
lastSelected = items.peek();
changed();
}
}
cleanup();
}
public void remove (T item) {
if (item == null) throw new IllegalArgumentException("item cannot be null.");
if (!selected.remove(item)) return;
if (programmaticChangeEvents && fireChangeEvent())
selected.add(item);
else {
lastSelected = null;
changed();
}
}
public void removeAll (Array items) {
boolean removed = false;
snapshot();
for (int i = 0, n = items.size; i < n; i++) {
T item = items.get(i);
if (item == null) throw new IllegalArgumentException("item cannot be null.");
if (selected.remove(item)) removed = true;
}
if (removed) {
if (programmaticChangeEvents && fireChangeEvent())
revert();
else {
lastSelected = null;
changed();
}
}
cleanup();
}
public void clear () {
if (selected.size == 0) return;
snapshot();
selected.clear();
if (programmaticChangeEvents && fireChangeEvent())
revert();
else {
lastSelected = null;
changed();
}
cleanup();
}
/** Called after the selection changes. The default implementation does nothing. */
protected void changed () {
}
/** Fires a change event on the selection's actor, if any. Called internally when the selection changes, depending on
* {@link #setProgrammaticChangeEvents(boolean)}.
* @return true if the change should be undone. */
public boolean fireChangeEvent () {
if (actor == null) return false;
ChangeEvent changeEvent = Pools.obtain(ChangeEvent.class);
try {
return actor.fire(changeEvent);
} finally {
Pools.free(changeEvent);
}
}
public boolean contains (T item) {
if (item == null) return false;
return selected.contains(item);
}
/** Makes a best effort to return the last item selected, else returns an arbitrary item or null if the selection is empty. */
public T getLastSelected () {
if (lastSelected != null) {
return lastSelected;
} else if (selected.size > 0) {
return selected.first();
}
return null;
}
public Iterator iterator () {
return selected.iterator();
}
public Array toArray () {
return selected.iterator().toArray();
}
public Array toArray (Array array) {
return selected.iterator().toArray(array);
}
/** If true, prevents {@link #choose(Object)} from changing the selection. Default is false. */
public void setDisabled (boolean isDisabled) {
this.isDisabled = isDisabled;
}
public boolean isDisabled () {
return isDisabled;
}
public boolean getToggle () {
return toggle;
}
/** If true, prevents {@link #choose(Object)} from clearing the selection. Default is false. */
public void setToggle (boolean toggle) {
this.toggle = toggle;
}
public boolean getMultiple () {
return multiple;
}
/** If true, allows {@link #choose(Object)} to select multiple items. Default is false. */
public void setMultiple (boolean multiple) {
this.multiple = multiple;
}
public boolean getRequired () {
return required;
}
/** If true, prevents {@link #choose(Object)} from selecting none. Default is false. */
public void setRequired (boolean required) {
this.required = required;
}
/** If false, only {@link #choose(Object)} will fire a change event. Default is true. */
public void setProgrammaticChangeEvents (boolean programmaticChangeEvents) {
this.programmaticChangeEvents = programmaticChangeEvents;
}
public String toString () {
return selected.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy