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.Priority;
import javafx.scene.layout.VBox;

import java.util.stream.Stream;

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 orientation = new SimpleObjectProperty<>();
	private ObjectProperty wrapWidth = new SimpleObjectProperty<>();
    private ObjectProperty icon = new SimpleObjectProperty<>();
    private Label legend;

    public Fieldset(String text) {
        this();
        setText(text);
    }

    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) addLegend();
        });

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

        // Make sure input children gets the configured HBox.hgrow property
        getChildren().addListener((ListChangeListener) c -> {
            while (c.next()) {
                if (c.wasAdded()) {
                    c.getAddedSubList().stream().filter(added -> added instanceof Field).forEach(added -> {
                        Field field = (Field) added;

                        // Configure hgrow for current children
                        field.getInputContainer().getChildren().forEach(this::configureHgrow);

                        // Add listener to support inputs added later
                        field.getInputContainer().getChildren().addListener((ListChangeListener) c1 -> {
                            while (c1.next()) if (c1.wasAdded()) c1.getAddedSubList().forEach(this::configureHgrow);
                        });
                    });
                }
            }
        });

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

	    // Default
	    setOrientation(HORIZONTAL);
    }

    private void syncOrientationState() {
        // Apply pseudo classes when orientation changes
        orientation.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 (orientationProperty().isBound())
                orientationProperty().unbind();

            orientationProperty().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 input) {
        HBox.setHgrow(input, getInputGrow());
    }

    public Form getForm() {
        return (Form) getParent();
    }

    Stream getFields() {
        return getChildren().stream()
                .filter(c -> c instanceof Field)
                .map(c -> (Field) c);
    }

    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);
    }

    public Orientation getOrientation() {
        return orientation.get();
    }

    public ObjectProperty orientationProperty() {
        return orientation;
    }

    public void setOrientation(Orientation orientation) {
        this.orientation.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 - 2024 Weber Informatics LLC | Privacy Policy