All Downloads are FREE. Search and download functionalities are using the official Maven repository.

tornadofx.control.Fieldset Maven / Gradle / Ivy

package tornadofx.control;

import javafx.beans.DefaultProperty;
import javafx.beans.binding.ObjectBinding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.ListChangeListener;
import javafx.css.PseudoClass;
import javafx.geometry.Orientation;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import tornadofx.util.NodeHelper;

import java.util.List;

import static javafx.beans.binding.Bindings.createObjectBinding;
import static javafx.geometry.Orientation.HORIZONTAL;
import static javafx.geometry.Orientation.VERTICAL;
import static javafx.scene.layout.Priority.SOMETIMES;

@SuppressWarnings("unused")
@DefaultProperty("children")
public class Fieldset extends VBox {

    private static final PseudoClass HORIZONTAL_PSEUDOCLASS_STATE = PseudoClass.getPseudoClass("horizontal");
    private static final PseudoClass VERTICAL_PSEUDOCLASS_STATE = PseudoClass.getPseudoClass("vertical");

    private SimpleStringProperty text = new SimpleStringProperty();
    private ObjectProperty inputGrow = new SimpleObjectProperty<>(SOMETIMES);
	private ObjectProperty labelPosition = new SimpleObjectProperty<>();
	private ObjectProperty wrapWidth = new SimpleObjectProperty<>();
    private ObjectProperty icon = new SimpleObjectProperty<>();
    private Label legend;

    public Fieldset(String text) {
        this(text, Orientation.HORIZONTAL);
    }

    public Fieldset(String text, Orientation labelPosition){
        this();
        setText(text);
        setLabelPosition(labelPosition);
    }

    public void add( Node child ){
        getChildren().add( child );
    }

    public Field field(String text, Orientation orientation, Node... inputs){
        Field field = new Field( text, orientation, false, inputs );
        getChildren().add(field);
        return field;
    }

    public Field field(String text, Node... inputs) {
        Field field = new Field(text, inputs);
        getChildren().add(field);
        return field;
    }

    public Field field() {
        Field field = new Field();
        getChildren().add(field);
        return field;
    }

    public Field field(Node... inputs) {
        Field field = new Field(null, inputs);
        getChildren().add(field);
        return field;
    }

    public Fieldset() {

        getStyleClass().add("fieldset");

        syncOrientationState();

        // Add legend label when text is populated
        textProperty().addListener((observable, oldValue, newValue) -> {
            if (newValue != null && !newValue.isEmpty() ) addLegend();
        });

        // Add legend when icon is populated
        iconProperty().addListener(((observable1, oldValue1, newValue) -> {
            if (newValue != null) addLegend();
        }));

        // Make sure input children get the configured HBox.hgrow property
        syncHgrow();

        // Register/deregister with parent Form
	    parentProperty().addListener( (observable, oldParent, newParent) -> {
	        if( !(oldParent instanceof Form) ) {
                Form oldParentForm = NodeHelper.findParentOfType(oldParent, Form.class);
                if( oldParentForm != null ) {
                    oldParentForm.getChildren().remove(this);
                }
            }
            if( !(newParent instanceof Form ) ) {
                Form newParentForm = NodeHelper.findParentOfType(newParent, Form.class);
                if( newParentForm != null ) {
                    newParentForm.getChildren().remove(this);
                }
            }

        });
    }

    private void syncHgrow(){
        getChildren().addListener((ListChangeListener) c -> {
            while (c.next()) {
                if (c.wasAdded()) {
                    c.getAddedSubList().forEach( this::configureHgrow );
                }
            }
        });

        // Change HGrow for unconfigured children when inputGrow changes
        inputGrowProperty().addListener((observable, oldValue, newValue) -> {
            getChildren().stream().forEach(this::configureHgrow);
        });
    }

    private void syncOrientationState() {
        // Apply pseudo classes when orientation changes
        labelPosition.addListener((observable, oldValue, newValue) -> {
            if (newValue == HORIZONTAL) {
                pseudoClassStateChanged(VERTICAL_PSEUDOCLASS_STATE, false);
                pseudoClassStateChanged(HORIZONTAL_PSEUDOCLASS_STATE, true);
            } else {
                pseudoClassStateChanged(HORIZONTAL_PSEUDOCLASS_STATE, false);
                pseudoClassStateChanged(VERTICAL_PSEUDOCLASS_STATE, true);
            }
        });

        // Setup listeneres for wrapping
        wrapWidth.addListener(((observable, oldValue, newValue) -> {
            ObjectBinding responsiveOrientation =
                    createObjectBinding(() -> getWidth() < newValue ? VERTICAL : HORIZONTAL, widthProperty());

            if (labelPositionProperty().isBound())
                labelPositionProperty().unbind();

            labelPositionProperty().bind(responsiveOrientation);
        }));
    }

    private void addLegend() {
        if (legend == null) {
            legend = new Label();
            legend.textProperty().bind(textProperty());
            legend.getStyleClass().add("legend");
            getChildren().add(0, legend);
        }

        legend.setGraphic(getIcon());
    }

    private void configureHgrow(Node node) {
        HBox.setHgrow(node, getInputGrow());
        if( node instanceof Field ){
            ((Field)node).configureHGrow( getInputGrow() );
        } else if ( node instanceof Pane){
            ((Pane)node).getChildren().forEach( child -> configureHgrow( child ));
        }
    }


    public Form getForm() {
        return NodeHelper.findParentOfType(this,Form.class);
    }

    protected List getFields(){
        return NodeHelper.findChildrenOfType(this,Field.class );
    }

    public Priority getInputGrow() {
        return inputGrow.get();
    }

    public ObjectProperty inputGrowProperty() {
        return inputGrow;
    }

    public void setInputGrow(Priority inputGrow) {
        this.inputGrow.set(inputGrow);
    }

    public String getText() {
        return text.get();
    }

    public SimpleStringProperty textProperty() {
        return text;
    }

    public void setText(String text) {
        this.text.set(text);
    }

    @Deprecated
    public Orientation getOrientation() {return getLabelPosition(); }

    public Orientation getLabelPosition() { return labelPosition.get(); }

    public ObjectProperty labelPositionProperty() { return labelPosition; }

    @Deprecated
    public ObjectProperty orientationProperty() {
        return labelPosition;
    }

    @Deprecated
    public void setOrientation(Orientation orientation) {
        setLabelPosition(orientation);
    }

    public void setLabelPosition(Orientation orientation) { this.labelPosition.set(orientation); }

    public Double getWrapWidth() {
        return wrapWidth.get();
    }

    public ObjectProperty wrapWidthProperty() {
        return wrapWidth;
    }

    public void setWrapWidth(Double wrapWidth) {
        this.wrapWidth.set(wrapWidth);
    }

    public Node getIcon() {
        return icon.get();
    }

    public ObjectProperty iconProperty() {
        return icon;
    }

    public void setIcon(Node icon) {
        this.icon.set(icon);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy