package tornadofx.control; import javafx.beans.DefaultProperty; import javafx.beans.property.SimpleStringProperty; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; import javafx.geometry.Orientation; import javafx.scene.Node; import javafx.scene.layout.*; import tornadofx.util.NodeHelper; @DefaultProperty("inputs") public class Field extends AbstractField { private Pane inputContainer = null; private Orientation orientation; public Field() { this(null); } public Field( String text ){ this( text, Orientation.HORIZONTAL ); } public Field( String text, Orientation orientation ){ this( text, orientation, false,null ); } public Field( String text, Orientation orientation, Node... inputs ){ this( text, orientation, false,inputs ); } public Field(String text, Node... inputs){ this( text, Orientation.HORIZONTAL, false, inputs ); } public Field(String text, Orientation orientation, boolean forceLabelIndent, Node... inputs) { super(text, forceLabelIndent); this.orientation = orientation; getStyleClass().add("field"); parentProperty().addListener( (obs, oldParent, newParent) -> { if( !(oldParent instanceof Fieldset) ) { Fieldset oldFieldSet = NodeHelper.findParentOfType(oldParent, Fieldset.class); if (oldFieldSet != null) { oldFieldSet.getFields().remove(this); } } if( !(newParent instanceof Fieldset) ) { Fieldset newFieldSet = NodeHelper.findParentOfType(newParent, Fieldset.class); if (newFieldSet != null ) { newFieldSet.getFields().add(this); } } syncVgrowConstraints(); }); getChildren().add( getInputContainer() ); if( inputs != null ) { getInputs().addAll(inputs); } for ( Node input : getInputs() ) { configureMnemonicTarget( input ); } // Add listener to support inputs added later getInputContainer().getChildren().addListener((ListChangeListener<Node>) c1 -> { while (c1.next()) if (c1.wasAdded()) c1.getAddedSubList().forEach( node -> { if( VBox.getVgrow(node) != null ) { syncVgrowConstraints(node); } configureMnemonicTarget(node); }); }); } public Fieldset getFieldset() { return NodeHelper.findParentOfType( this, Fieldset.class); } public Pane getInputContainer() { if( inputContainer == null ){ inputContainer = Orientation.HORIZONTAL.equals( orientation ) ? new HBox() : new VBox(); inputContainer.getStyleClass().add("input-container"); NodeHelper.addPseudoClass( inputContainer, this.orientation.name().toLowerCase() ); } return inputContainer; } protected void syncVgrowConstraints(){ getInputContainer().getChildren().stream() .filter( n -> VBox.getVgrow(n) != null ) .findFirst( ) .ifPresent( Field.this::syncVgrowConstraints); } private void syncVgrowConstraints(Node inputNode){ Priority priority = VBox.getVgrow(inputNode); Field parentField = NodeHelper.findParentOfType(inputNode,Field.class); if( parentField != null ){ VBox.setVgrow( parentField, priority ); if( parentField.getFieldSet() != null ){ VBox.setVgrow( parentField.getFieldset(), priority ); } } } public void configureHGrow( Priority priority ){ // Configure hgrow for current children getInputContainer().getChildren().forEach( node -> HBox.setHgrow(node, priority)); // Add listener to support inputs added later getInputContainer().getChildren().addListener((ListChangeListener<Node>) c1 -> { while (c1.next()) if (c1.wasAdded()) c1.getAddedSubList().forEach( node -> { HBox.setHgrow(node, priority); syncVgrowConstraints( node ); }); }); } private void configureMnemonicTarget( Node target ){ if( target.getProperties().containsKey("mnemonicTarget") ){ getLabel().setMnemonicParsing(true); getLabel().setLabelFor(target); } } public static void setMnemonicTarget( Node target ){ Field parent = NodeHelper.findParentOfType( target, Field.class); if( parent != null ){ parent.getLabel().setMnemonicParsing(true); parent.getLabel().setLabelFor(target); } else { // we will detect this when this target is added as an input target.getProperties().put("mnemonicTarget",Boolean.TRUE); } } public ObservableList<Node> getInputs() { return getInputContainer().getChildren(); } public String getText() { return textProperty.get(); } public SimpleStringProperty textProperty() { return textProperty; } public void setText(String text) { this.textProperty.set(text); } public void setOrientation( Orientation orientation ){ this.orientation = orientation; } }