<commit_before>//
// Triple Play - utilities for use in PlayN-based games
// Copyright (c) 2011, 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 the children of <code>Elements</code>.<p>
 *
 * A click on a child that implements <code>Clickable</code> makes it the selected item, or
 * <code>setSelected</code> can be used to manually control the selected item.
 */
public class Selector
{
    public Selector () {
        _selected.connect(new ValueView.Listener<Element<?>> () {
            @Override public void onChange (Element<?> selected, Element<?> deselected) {
                if (deselected != null) {
                    deselected.set(Element.Flag.SELECTED, false);
                    deselected.invalidate();
                }
                if (selected != null) {
                    selected.set(Element.Flag.SELECTED, true);
                    selected.invalidate();
                }
            }
        });
    }

    /** Returns a ValueView that emits changes when the selected item changes. */
    public ValueView<Element<?>> selectedChanged () { return _selected; }

    /** Returns the selected item or null if no item is selected. */
    public Element<?> selected () { return _selected.get(); }

    /** Sets the selected item. */
    public Selector setSelected (Element<?> selected) {
       _selected.update(selected);
       return this;
    }

    /**
     * Tracks the children of <code>elements</code> for setting the selection.
     */
    public Selector add (Elements<?> elements) {
        for (Element<?> child : elements) {
            _childAddSlot.onEmit(child);
        }
        elements.childAdded().connect(_childAddSlot);
        elements.childRemoved().connect(_childRemoveSlot);
        return this;
    }

    /**
     * Stops tracking the children of <code>elements</code> for setting the selection.
    */
    public Selector remove (Elements<?> elements) {
        for (Element<?> child : elements) {
            _childRemoveSlot.onEmit(child);
        }
        elements.childAdded().disconnect(_childAddSlot);
        elements.childRemoved().disconnect(_childRemoveSlot);
        return this;
    }

    protected final Slot<Element<?>> _childAddSlot = new Slot<Element<?>>() {
        @Override public void onEmit (Element<?> child) {
            if (child instanceof Clickable<?>) {
                ((Clickable<?>)child).clicked().connect(_clickSlot);
            }
        }
    };

    protected final Slot<Element<?>> _childRemoveSlot = new Slot<Element<?>>() {
        @Override public void onEmit (Element<?> removed) {
            if (removed instanceof Clickable<?>) {
                ((Clickable<?>)removed).clicked().disconnect(_clickSlot);
            }
        }<commit_msg>Deselect the item if it's removed from its parent<commit_after>//
// Triple Play - utilities for use in PlayN-based games
// Copyright (c) 2011, 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 the children of <code>Elements</code>.<p>
 *
 * A click on a child that implements <code>Clickable</code> makes it the selected item, or
 * <code>setSelected</code> can be used to manually control the selected item.
 */
public class Selector
{
    public Selector () {
        _selected.connect(new ValueView.Listener<Element<?>> () {
            @Override public void onChange (Element<?> selected, Element<?> deselected) {
                if (deselected != null) {
                    deselected.set(Element.Flag.SELECTED, false);
                    deselected.invalidate();
                }
                if (selected != null) {
                    selected.set(Element.Flag.SELECTED, true);
                    selected.invalidate();
                }
            }
        });
    }

    /** Returns a ValueView that emits changes when the selected item changes. */
    public ValueView<Element<?>> selectedChanged () { return _selected; }

    /** Returns the selected item or null if no item is selected. */
    public Element<?> selected () { return _selected.get(); }

    /** Sets the selected item. */
    public Selector setSelected (Element<?> selected) {
       _selected.update(selected);
       return this;
    }

    /**
     * Tracks the children of <code>elements</code> for setting the selection.
     */
    public Selector add (Elements<?> elements) {
        for (Element<?> child : elements) {
            _childAddSlot.onEmit(child);
        }
        elements.childAdded().connect(_childAddSlot);
        elements.childRemoved().connect(_childRemoveSlot);
        return this;
    }

    /**
     * Stops tracking the children of <code>elements</code> for setting the selection.
    */
    public Selector remove (Elements<?> elements) {
        for (Element<?> child : elements) {
            _childRemoveSlot.onEmit(child);
        }
        elements.childAdded().disconnect(_childAddSlot);
        elements.childRemoved().disconnect(_childRemoveSlot);
        return this;
    }

    protected final Slot<Element<?>> _childAddSlot = new Slot<Element<?>>() {
        @Override public void onEmit (Element<?> child) {
            if (child instanceof Clickable<?>) {
                ((Clickable<?>)child).clicked().connect(_clickSlot);
            }
        }
    };

    protected final Slot<Element<?>> _childRemoveSlot = new Slot<Element<?>>() {
        @Override public void onEmit (Element<?> removed) {
            if (removed instanceof Clickable<?>) {
                ((Clickable<?>)removed).clicked().disconnect(_clickSlot);
            }
            if (_selected.get() == removed) _selected.update(null);
        }
{'fraction_non_alphanumeric': 0.12283044058744993, 'fraction_numerical': 0.0013351134846461949, 'mean_word_length': 2.3630751964085297, 'pattern_counts': {'":': 0, '<': 77, '<?xml version=': 0, '>': 77, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6634572', 'n_tokens_mistral': 1588, 'n_tokens_neox': 1564, 'n_words': 440}