diff --git a/gemsfx-demo/src/main/java/com/dlsc/gemsfx/demo/SelectionBoxApp.java b/gemsfx-demo/src/main/java/com/dlsc/gemsfx/demo/SelectionBoxApp.java index 661cd520..c888cadb 100644 --- a/gemsfx-demo/src/main/java/com/dlsc/gemsfx/demo/SelectionBoxApp.java +++ b/gemsfx-demo/src/main/java/com/dlsc/gemsfx/demo/SelectionBoxApp.java @@ -2,8 +2,10 @@ import com.dlsc.gemsfx.SelectionBox; import com.dlsc.gemsfx.demo.fake.SimpleControlPane; +import com.dlsc.gemsfx.util.SimpleStringConverter; import fr.brouillard.oss.cssfx.CSSFX; import javafx.application.Application; +import javafx.beans.binding.Bindings; import javafx.collections.FXCollections; import javafx.scene.Node; import javafx.scene.Scene; @@ -13,9 +15,11 @@ import javafx.scene.control.Label; import javafx.scene.control.SelectionMode; import javafx.scene.control.SplitPane; +import javafx.scene.layout.Priority; import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; +import javafx.scene.paint.Color; import javafx.stage.Stage; import javafx.util.StringConverter; @@ -106,24 +110,27 @@ private Node getControlPanel() { } }); + // placeholder + CheckBox placeholderCheckBox = new CheckBox("Add a placeholder when no items"); + placeholderCheckBox.setSelected(true); + selectionBox.placeholderProperty().bind(Bindings.createObjectBinding(() -> { + if (placeholderCheckBox.isSelected()) { + Label label = new Label("No items available"); + label.setStyle("-fx-text-fill: #969696;"); + StackPane stackPane = new StackPane(label); + stackPane.setStyle("-fx-background-color: #fcfcfc; -fx-padding: 20px;"); + return stackPane; + } else { + return null; + } + }, placeholderCheckBox.selectedProperty())); + // use custom string converter CheckBox useCustomStringConverterCheckBox = new CheckBox("Use Custom String Converter"); - useCustomStringConverterCheckBox.selectedProperty().addListener((obs, oldVal, newVal) -> { + useCustomStringConverterCheckBox.setSelected(true); + useCustomStringConverterCheckBox.selectedProperty().subscribe(newVal -> { if (newVal) { - selectionBox.setSelectedItemsConverter(new StringConverter<>() { - @Override - public String toString(List object) { - if (object == null || object.isEmpty()) { - return "Empty"; - } - return object.stream().map(s -> ">> " + s).reduce((s1, s2) -> s1 + ", " + s2).orElse(""); - } - - @Override - public List fromString(String string) { - return List.of(); - } - }); + selectionBox.setSelectedItemsConverter(new SimpleStringConverter<>(selectedItems -> selectedItems.size() + " items selected", "Empty")); } else { selectionBox.setSelectedItemsConverter(null); } @@ -239,6 +246,7 @@ public List fromString(String string) { new SimpleControlPane.ControlItem("Show Popup", showButton), new SimpleControlPane.ControlItem("Selection Mode", selectionModeComboBox), new SimpleControlPane.ControlItem("Show Extra Nodes", showExtraNodesCheckBox), + new SimpleControlPane.ControlItem("Show Placeholder", placeholderCheckBox), new SimpleControlPane.ControlItem("Enable Animation", animationEnabledCheckBox), new SimpleControlPane.ControlItem("Change Prompt Text", promptTextCheckBox), new SimpleControlPane.ControlItem("Use Custom String Converter", useCustomStringConverterCheckBox), diff --git a/gemsfx/src/main/java/com/dlsc/gemsfx/DayOfWeekPicker.java b/gemsfx/src/main/java/com/dlsc/gemsfx/DayOfWeekPicker.java index 5e389636..175e543f 100644 --- a/gemsfx/src/main/java/com/dlsc/gemsfx/DayOfWeekPicker.java +++ b/gemsfx/src/main/java/com/dlsc/gemsfx/DayOfWeekPicker.java @@ -79,8 +79,6 @@ public DayOfWeekPicker() { private VBox createExtraButtonsBox() { Button clearButton = createExtraButton("Clear", () -> getSelectionModel().clearSelection()); clearButton.getStyleClass().add("clear-button"); - clearButton.managedProperty().bind(clearButton.visibleProperty()); - clearButton.visibleProperty().bind(itemsProperty().isNotNull().and(itemsProperty().emptyProperty().not())); Button todayButton = createExtraButton("Today", () -> getSelectionModel().clearAndSelect(getItems().indexOf(LocalDate.now().getDayOfWeek()))); todayButton.getStyleClass().add("today-button"); @@ -114,6 +112,8 @@ private VBox createExtraButtonsBox() { VBox extraButtonsBox = new VBox(clearButton, todayButton, allButton, weekdaysButton, weekendsButton); extraButtonsBox.getStyleClass().addAll("extra-buttons-box"); + extraButtonsBox.managedProperty().bind(extraButtonsBox.visibleProperty()); + extraButtonsBox.visibleProperty().bind(itemsProperty().emptyProperty().not()); return extraButtonsBox; } diff --git a/gemsfx/src/main/java/com/dlsc/gemsfx/SelectionBox.java b/gemsfx/src/main/java/com/dlsc/gemsfx/SelectionBox.java index 4688fa34..11f388a4 100644 --- a/gemsfx/src/main/java/com/dlsc/gemsfx/SelectionBox.java +++ b/gemsfx/src/main/java/com/dlsc/gemsfx/SelectionBox.java @@ -109,8 +109,6 @@ public SelectionBox(T... items) { private Node createExtraButtonsBox() { Button clearButton = createExtraButton("Clear", () -> getSelectionModel().clearSelection()); clearButton.getStyleClass().add("clear-button"); - clearButton.managedProperty().bind(clearButton.visibleProperty()); - clearButton.visibleProperty().bind(itemsProperty().isNotNull().and(itemsProperty().emptyProperty().not())); Button selectAllButton = createExtraButton("Select All", () -> getSelectionModel().selectAll()); selectAllButton.managedProperty().bind(selectAllButton.visibleProperty()); @@ -119,6 +117,8 @@ private Node createExtraButtonsBox() { VBox extraButtonsBox = new VBox(clearButton, selectAllButton); extraButtonsBox.getStyleClass().addAll("extra-buttons-box"); + extraButtonsBox.managedProperty().bind(extraButtonsBox.visibleProperty()); + extraButtonsBox.visibleProperty().bind(itemsProperty().emptyProperty().not()); return extraButtonsBox; } @@ -232,6 +232,27 @@ public final void setRight(Node right) { rightProperty().set(right); } + // placeholder + + private final ObjectProperty placeholder = new SimpleObjectProperty<>(this, "placeholder"); + + /** + * Returns the property holding the placeholder node, which is displayed when there are no items. + * + * @return the placeholder property + */ + public final ObjectProperty placeholderProperty() { + return placeholder; + } + + public final Node getPlaceholder() { + return placeholderProperty().get(); + } + + public final void setPlaceholder(Node placeholder) { + placeholderProperty().set(placeholder); + } + /** * Creates an extra button with the specified text and action. * The button will be styled with the "extra-button" class and will adjust its visibility diff --git a/gemsfx/src/main/java/com/dlsc/gemsfx/TimeRangePicker.java b/gemsfx/src/main/java/com/dlsc/gemsfx/TimeRangePicker.java index 13014a61..db69c32e 100644 --- a/gemsfx/src/main/java/com/dlsc/gemsfx/TimeRangePicker.java +++ b/gemsfx/src/main/java/com/dlsc/gemsfx/TimeRangePicker.java @@ -69,8 +69,6 @@ public TimeRangePicker(TimeRange... ranges) { private Node createExtraButtonsBox() { Button clearButton = createExtraButton("Clear", getSelectionModel()::clearSelection); clearButton.getStyleClass().add("clear-button"); - clearButton.managedProperty().bind(clearButton.visibleProperty()); - clearButton.visibleProperty().bind(itemsProperty().isNotNull().and(itemsProperty().emptyProperty().not())); Button selectAllButton = createExtraButton("Select All", getSelectionModel()::selectAll); selectAllButton.getStyleClass().add("select-all-button"); @@ -79,6 +77,8 @@ private Node createExtraButtonsBox() { VBox extraButtonsBox = new VBox(clearButton, selectAllButton); extraButtonsBox.getStyleClass().addAll("extra-buttons-box"); + extraButtonsBox.managedProperty().bind(extraButtonsBox.visibleProperty()); + extraButtonsBox.visibleProperty().bind(itemsProperty().emptyProperty().not()); return extraButtonsBox; } diff --git a/gemsfx/src/main/java/com/dlsc/gemsfx/skins/SelectionBoxSkin.java b/gemsfx/src/main/java/com/dlsc/gemsfx/skins/SelectionBoxSkin.java index 84bbb58b..6e61acc7 100644 --- a/gemsfx/src/main/java/com/dlsc/gemsfx/skins/SelectionBoxSkin.java +++ b/gemsfx/src/main/java/com/dlsc/gemsfx/skins/SelectionBoxSkin.java @@ -460,8 +460,6 @@ public String getUserAgentStylesheet() { optionsBox.getStyleClass().add("options-box"); optionsBox.setFillWidth(true); optionsBox.setMinWidth(Region.USE_PREF_SIZE); - optionsBox.managedProperty().bind(optionsBox.visibleProperty()); - optionsBox.visibleProperty().bind(popup.getOwner().itemsProperty().emptyProperty().not()); contentPane.topProperty().bind(control.topProperty()); contentPane.bottomProperty().bind(control.bottomProperty()); @@ -478,7 +476,13 @@ public String getUserAgentStylesheet() { } }); - contentPane.setCenter(scrollPane); + // Center If there are no items, show the placeholder, otherwise show the scroll pane + contentPane.centerProperty().bind(Bindings.createObjectBinding(() -> { + if (popup.getOwner().getItems().isEmpty()) { + return popup.getOwner().getPlaceholder(); + } + return scrollPane; + }, popup.getOwner().itemsProperty(), popup.getOwner().placeholderProperty())); // Initialize the popup content updatePopupContent();