UIForSeparator.java

package swingtree;

import sprouts.Val;

import javax.swing.*;
import java.awt.*;
import java.util.Objects;

/**
 *  A SwingTree builder node designed for configuring {@link JSeparator} instances.
 * 	<p>
 * 	<b>Please take a look at the <a href="https://globaltcad.github.io/swing-tree/">living swing-tree documentation</a>
 * 	where you can browse a large collection of examples demonstrating how to use the API of this class.</b>
 */
public final class UIForSeparator<S extends JSeparator> extends UIForAnySwing<UIForSeparator<S>, S>
{
    private final BuilderState<S> _state;

    /**
     * Instances of ths {@link UIForSeparator} always wrap
     * a single {@link JSeparator} for which they are responsible and expose helpful utility methods.
     *
     * @param state The state of the builder.
     */
    UIForSeparator( BuilderState<S> state ) {
        Objects.requireNonNull(state);
        _state = state;
    }

    @Override
    protected BuilderState<S> _state() {
        return _state;
    }
    
    @Override
    protected UIForSeparator<S> _newBuilderWithState(BuilderState<S> newState ) {
        return new UIForSeparator<>(newState);
    }

    /**
     * Sets the orientation of the separator which can be either
     * {@link SwingConstants#HORIZONTAL} or {@link SwingConstants#VERTICAL}.
     * This method is a convenience method for {@link JSeparator#setOrientation(int)}
     * which receives the {@link UI.Align} enum instead of an integer.
     *
     * @param align The orientation of the separator.
     * @return This very instance, which enables builder-style method chaining.
     * @throws IllegalArgumentException if {@code align} is {@code null}.
     */
    public final UIForSeparator<S> withOrientation( UI.Align align ) {
        NullUtil.nullArgCheck( align, "align", Val.class );
        return _with( thisComponent -> {
                    thisComponent.setOrientation( align.forSeparator() );
                })
                ._this();
    }

    /**
     *  Binds the supplied alignment property to the orientation of the separator,
     *  so that whenever the property changes, the orientation of the separator will be updated accordingly.
     *
     * @param align The alignment property used to dynamically update the alignment of the separator.
     * @return This very instance, which enables builder-style method chaining.
     * @throws IllegalArgumentException if {@code align} is {@code null}.
     */
    public final UIForSeparator<S> withOrientation( Val<UI.Align> align ) {
        NullUtil.nullArgCheck( align, "align", Val.class );
        NullUtil.nullPropertyCheck( align, "align", "Null is not a valid alignment." );
        return _withOnShow( align, (c,v) -> {
                    c.setOrientation( v.forSeparator() );
                })
                ._with( thisComponent -> {
                    thisComponent.setOrientation( align.orElseThrow().forSeparator() );
                })
                ._this();
    }

    /**
     *  Sets the length of the separation line either horizontally or vertically
     *  depending on the orientation of the separator.
     *  This method is an alignment aware convenience method for
     *  {@link JSeparator#setPreferredSize(Dimension)}.
     *
     * @param separatorLength The length of the separation line.
     * @return This very builder to allow for method chaining.
     */
    public final UIForSeparator<S> withLength( int separatorLength ) {
        return _with( thisComponent -> {
                    _setLength( thisComponent, separatorLength );
                })
                ._this();
    }

    private void _setLength( S thisComponent, int separatorLength ) {
        Dimension d = thisComponent.getPreferredSize();
        if ( thisComponent.getOrientation() == JSeparator.VERTICAL )
            d.height = UI.scale(separatorLength);
        else if ( thisComponent.getOrientation() == JSeparator.HORIZONTAL )
            d.width = UI.scale(separatorLength);
        thisComponent.setPreferredSize(d);
    }

    /**
     *  Binds the provided integer property to the length of the separation line.,
     *  which means that whenever the property changes, the length of the separation line will be updated accordingly.
     *
     * @param separatorLength The property dynamically determining the length of the separation line.
     * @return This very builder to allow for method chaining.
     */
    public UIForSeparator<S> withLength( Val<Integer> separatorLength ) {
        NullUtil.nullArgCheck( separatorLength, "separatorLength", Val.class );
        NullUtil.nullPropertyCheck( separatorLength, "separatorLength", "Null is not a valid separator length." );
        return _withOnShow( separatorLength, (thisComponent,it) -> {
                    _setLength( thisComponent, it );
                })
                ._with( thisComponent -> {
                    _setLength( thisComponent, separatorLength.orElseThrow() );
                })
                ._this();
    }
}