Improve samples visual design

This commit is contained in:
mkpaz 2022-09-20 21:44:48 +04:00
parent 978577dc6a
commit 79a9a9cfc2
47 changed files with 1606 additions and 1672 deletions

@ -2,16 +2,13 @@
package atlantafx.sampler.page;
import atlantafx.sampler.layout.Overlay;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.layout.*;
import net.datafaker.Faker;
import org.kordamp.ikonli.feather.Feather;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.function.Supplier;
@ -25,34 +22,32 @@ public abstract class AbstractPage extends BorderPane implements Page {
protected static final Faker FAKER = new Faker();
protected static final Random RANDOM = new Random();
protected static final EventHandler<ActionEvent> PRINT_SOURCE = System.out::println;
protected VBox userContent;
protected final StackPane userContent = new StackPane();
protected Overlay overlay;
protected boolean isRendered = false;
protected AbstractPage() {
super();
userContent.getStyleClass().add("user-content");
getStyleClass().add("page");
createPageLayout();
}
protected void createPageLayout() {
userContent = new VBox();
userContent.getStyleClass().add("user-content");
var userContentWrapper = new StackPane();
userContentWrapper.getStyleClass().add("wrapper");
userContentWrapper.getChildren().setAll(userContent);
var scrollPane = new ScrollPane(userContentWrapper);
var scrollPane = new ScrollPane(userContent);
setScrollConstraints(scrollPane, AS_NEEDED, true, AS_NEEDED, true);
scrollPane.setMaxHeight(10_000);
setCenter(scrollPane);
}
protected void setUserContent(Node content) {
userContent.getChildren().setAll(content);
}
@Override
public Pane getView() {
return this;
@ -91,6 +86,12 @@ public abstract class AbstractPage extends BorderPane implements Page {
///////////////////////////////////////////////////////////////////////////
protected HBox expandingHBox(Node... nodes) {
var box = new HBox(PAGE_HGAP, nodes);
Arrays.stream(nodes).forEach(n -> HBox.setHgrow(n, Priority.ALWAYS));
return box;
}
protected <T> List<T> generate(Supplier<T> supplier, int count) {
return Stream.generate(supplier).limit(count).collect(Collectors.toList());
}

@ -5,6 +5,9 @@ import javafx.scene.Parent;
public interface Page {
int PAGE_HGAP = 30;
int PAGE_VGAP = 30;
String getName();
Parent getView();

@ -3,40 +3,59 @@ package atlantafx.sampler.page;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
public class SampleBlock {
import java.util.Objects;
public class SampleBlock extends VBox {
public static final int BLOCK_HGAP = 20;
public static final int BLOCK_VGAP = 10;
protected final VBox root;
protected final Label titleLabel;
protected final Node content;
protected final Node content; // can be either Pane or Control
protected TextFlow descriptionText;
public SampleBlock(String title, Node content) {
this.titleLabel = new Label(title);
this.titleLabel.getStyleClass().add("title");
this.content = content;
VBox.setVgrow(content, Priority.ALWAYS);
this.root = new VBox(titleLabel, content);
this.root.getStyleClass().add("sample-block");
this(title, content, null);
}
public Pane getRoot() {
return root;
public SampleBlock(String title, Node content, String description) {
titleLabel = new Label(Objects.requireNonNull(title));
titleLabel.getStyleClass().add("title");
this.content = Objects.requireNonNull(content);
content.getStyleClass().add("content");
getChildren().setAll(titleLabel, content);
if (description != null && !description.isBlank()) {
descriptionText = new TextFlow(new Text(description));
getChildren().add(descriptionText);
}
public String getText() {
getStyleClass().add("sample-block");
}
public String getTitle() {
return titleLabel.getText();
}
public void setText(String text) {
public void setTitle(String text) {
titleLabel.setText(text);
}
public Node getContent() {
return content;
}
public void setFillHeight(boolean fillHeight) {
if (fillHeight) {
VBox.setVgrow(content, Priority.ALWAYS);
} else {
VBox.setVgrow(content, Priority.NEVER);
}
}
}

@ -4,10 +4,12 @@ package atlantafx.sampler.page.components;
import atlantafx.base.controls.ToggleSwitch;
import atlantafx.sampler.Resources;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.SampleBlock;
import javafx.application.Platform;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Accordion;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
@ -31,17 +33,32 @@ public class AccordionPage extends AbstractPage {
public AccordionPage() {
super();
createView();
var sample = new SampleBlock(
"Playground",
new VBox(SampleBlock.BLOCK_VGAP, createControls(), createPlayground())
);
sample.setFillHeight(true);
setUserContent(sample);
}
private void createView() {
userContent.getChildren().addAll(new VBox(10,
controls(),
playground()
));
private HBox createControls() {
var animatedToggle = new ToggleSwitch("Animated");
animatedProperty.bind(animatedToggle.selectedProperty());
animatedToggle.setSelected(true);
var expandedToggle = new ToggleSwitch("Always expanded");
expandedProperty.bind(expandedToggle.selectedProperty());
expandedToggle.setSelected(true);
var controls = new HBox(SampleBlock.BLOCK_HGAP, animatedToggle, expandedToggle);
controls.setAlignment(Pos.CENTER);
controls.setPadding(new Insets(0, 0, 0, 2));
return controls;
}
private Accordion playground() {
private Accordion createPlayground() {
var textBlockContent = new Label(FAKER.chuckNorris().fact());
var textBlock = new TitledPane("_Quote", textBlockContent);
textBlock.setMnemonicParsing(true);
@ -74,30 +91,16 @@ public class AccordionPage extends AbstractPage {
disabledBlock,
imageBlock
);
// prevents accordion from being completely collapsed
accordion.expandedPaneProperty().addListener((obs, old, val) -> {
// make sure the accordion can never be completely collapsed
boolean hasExpanded = accordion.getPanes().stream().anyMatch(TitledPane::isExpanded);
if (expandedProperty.get() && !hasExpanded && old != null) {
Platform.runLater(() -> accordion.setExpandedPane(old));
}
});
accordion.setExpandedPane(accordion.getPanes().get(0));
accordion.setExpandedPane(accordion.getPanes().get(1));
return accordion;
}
private HBox controls() {
var animatedToggle = new ToggleSwitch("Animated");
animatedProperty.bind(animatedToggle.selectedProperty());
animatedToggle.setSelected(true);
var expandedToggle = new ToggleSwitch("Always expanded");
expandedProperty.bind(expandedToggle.selectedProperty());
expandedToggle.setSelected(true);
var controls = new HBox(20, animatedToggle, expandedToggle);
controls.setPadding(new Insets(0, 0, 0, 2));
return controls;
}
}

@ -4,11 +4,13 @@ package atlantafx.sampler.page.components;
import atlantafx.base.controls.Breadcrumbs;
import atlantafx.base.theme.Styles;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.Page;
import atlantafx.sampler.page.SampleBlock;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.TreeItem;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.util.Callback;
import org.kordamp.ikonli.feather.Feather;
import org.kordamp.ikonli.javafx.FontIcon;
@ -22,18 +24,14 @@ public class BreadcrumbsPage extends AbstractPage {
public BreadcrumbsPage() {
super();
createView();
}
private void createView() {
userContent.getChildren().addAll(
defaultSample().getRoot(),
customCrumbSample().getRoot()
);
setUserContent(new VBox(Page.PAGE_VGAP,
defaultSample(),
customCrumbSample()
));
}
private SampleBlock defaultSample() {
return new SampleBlock("Basic", breadcrumbs(null));
return new SampleBlock("Basic", createBreadcrumbs(null));
}
private SampleBlock customCrumbSample() {
@ -47,10 +45,10 @@ public class BreadcrumbsPage extends AbstractPage {
return btn;
};
return new SampleBlock("Custom crumb factory", breadcrumbs(crumbFactory));
return new SampleBlock("Flat", createBreadcrumbs(crumbFactory));
}
private HBox breadcrumbs(Callback<TreeItem<String>, Button> crumbFactory) {
private HBox createBreadcrumbs(Callback<TreeItem<String>, Button> crumbFactory) {
int count = 5;
TreeItem<String> model = Breadcrumbs.buildTreeModel(
generate(() -> FAKER.science().element(), count).toArray(String[]::new)
@ -76,7 +74,7 @@ public class BreadcrumbsPage extends AbstractPage {
}
});
var box = new HBox(60, nextBtn, breadcrumbs);
var box = new HBox(40, nextBtn, breadcrumbs);
box.setAlignment(Pos.CENTER_LEFT);
return box;

@ -2,6 +2,7 @@
package atlantafx.sampler.page.components;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.Page;
import atlantafx.sampler.page.SampleBlock;
import javafx.scene.control.Button;
import javafx.scene.control.ContentDisplay;
@ -12,6 +13,7 @@ import org.kordamp.ikonli.feather.Feather;
import org.kordamp.ikonli.javafx.FontIcon;
import static atlantafx.base.theme.Styles.*;
import static atlantafx.sampler.page.SampleBlock.BLOCK_HGAP;
public class ButtonPage extends AbstractPage {
@ -29,36 +31,31 @@ public class ButtonPage extends AbstractPage {
private void createView() {
var grid = new GridPane();
grid.setHgap(40);
grid.setVgap(40);
grid.add(basicSamples().getRoot(), 0, 0);
grid.add(iconOnlySamples().getRoot(), 1, 0);
grid.add(coloredSamples().getRoot(), 0, 1);
grid.add(circularButtons().getRoot(), 1, 1);
grid.add(outlinedSamples().getRoot(), 0, 2);
grid.add(roundedSamples().getRoot(), 1, 2);
grid.add(disabledSample().getRoot(), 0, 3);
grid.setHgap(Page.PAGE_HGAP);
grid.setVgap(Page.PAGE_VGAP);
grid.add(basicSamples(), 0, 0);
grid.add(iconButtonSamples(), 1, 0);
grid.add(coloredSamples(), 0, 1);
grid.add(circularButtons(), 1, 1);
grid.add(outlinedSamples(), 0, 2);
grid.add(roundedSamples(), 1, 2);
grid.add(disabledSample(), 0, 3);
userContent.getChildren().addAll(grid);
setUserContent(grid);
}
private SampleBlock basicSamples() {
var basicBtn = new Button("_Basic");
basicBtn.setMnemonicParsing(true);
basicBtn.setOnAction(PRINT_SOURCE);
var defaultBtn = new Button("_Default");
defaultBtn.setDefaultButton(true);
defaultBtn.setMnemonicParsing(true);
defaultBtn.setOnAction(PRINT_SOURCE);
var flatBtn = new Button("_Flat");
flatBtn.getStyleClass().add(FLAT);
flatBtn.setOnAction(PRINT_SOURCE);
var content = new HBox(10);
content.getChildren().addAll(basicBtn, defaultBtn, flatBtn);
var content = new HBox(BLOCK_HGAP, basicBtn, defaultBtn, flatBtn);
return new SampleBlock("Basic", content);
}
@ -66,26 +63,21 @@ public class ButtonPage extends AbstractPage {
var accentBtn = new Button("_Accent");
accentBtn.getStyleClass().add(ACCENT);
accentBtn.setMnemonicParsing(true);
accentBtn.setOnAction(PRINT_SOURCE);
var successBtn = new Button("_Success", new FontIcon(Feather.CHECK));
successBtn.getStyleClass().add(SUCCESS);
successBtn.setMnemonicParsing(true);
successBtn.setOnAction(PRINT_SOURCE);
var dangerBtn = new Button("Da_nger", new FontIcon(Feather.TRASH));
dangerBtn.getStyleClass().add(DANGER);
dangerBtn.setContentDisplay(ContentDisplay.RIGHT);
dangerBtn.setMnemonicParsing(true);
dangerBtn.setOnAction(PRINT_SOURCE);
var content = new HBox(10);
content.getChildren().addAll(accentBtn, successBtn, dangerBtn);
var content = new HBox(BLOCK_HGAP, accentBtn, successBtn, dangerBtn);
return new SampleBlock("Colored", content);
}
private SampleBlock iconOnlySamples() {
private SampleBlock iconButtonSamples() {
var basicBtn = new Button("", new FontIcon(Feather.MORE_HORIZONTAL));
basicBtn.getStyleClass().addAll(BUTTON_ICON);
@ -107,12 +99,11 @@ public class ButtonPage extends AbstractPage {
var flatDangerBtn = new Button("", new FontIcon(Feather.CROSSHAIR));
flatDangerBtn.getStyleClass().addAll(BUTTON_ICON, FLAT, DANGER);
var content = new HBox(10);
content.getChildren().addAll(basicBtn, accentBtn, successBtn, dangerBtn,
var content = new HBox(BLOCK_HGAP,
basicBtn, accentBtn, successBtn, dangerBtn,
flatAccentBtn, flatSuccessBtn, flatDangerBtn
);
return new SampleBlock("Icon only", content);
return new SampleBlock("Icon", content);
}
private SampleBlock circularButtons() {
@ -144,11 +135,10 @@ public class ButtonPage extends AbstractPage {
flatDangerBtn.getStyleClass().addAll(BUTTON_CIRCLE, FLAT, DANGER);
flatDangerBtn.setShape(new Circle(50));
var content = new HBox(10);
content.getChildren().addAll(basicBtn, accentBtn, successBtn, dangerBtn,
var content = new HBox(BLOCK_HGAP,
basicBtn, accentBtn, successBtn, dangerBtn,
flatAccentBtn, flatSuccessBtn, flatDangerBtn
);
return new SampleBlock("Circular", content);
}
@ -156,21 +146,17 @@ public class ButtonPage extends AbstractPage {
var accentBtn = new Button("Accen_t");
accentBtn.getStyleClass().addAll(BUTTON_OUTLINED, ACCENT);
accentBtn.setMnemonicParsing(true);
accentBtn.setOnAction(PRINT_SOURCE);
var successBtn = new Button("S_uccess", new FontIcon(Feather.CHECK));
successBtn.getStyleClass().addAll(BUTTON_OUTLINED, SUCCESS);
successBtn.setMnemonicParsing(true);
successBtn.setOnAction(PRINT_SOURCE);
var dangerBtn = new Button("Dan_ger", new FontIcon(Feather.TRASH));
dangerBtn.getStyleClass().addAll(BUTTON_OUTLINED, DANGER);
dangerBtn.setContentDisplay(ContentDisplay.RIGHT);
dangerBtn.setMnemonicParsing(true);
dangerBtn.setOnAction(PRINT_SOURCE);
var content = new HBox(10);
content.getChildren().addAll(accentBtn, successBtn, dangerBtn);
var content = new HBox(BLOCK_HGAP, accentBtn, successBtn, dangerBtn);
return new SampleBlock("Outlined", content);
}
@ -178,19 +164,14 @@ public class ButtonPage extends AbstractPage {
private SampleBlock roundedSamples() {
var basicBtn = new Button("Basic");
basicBtn.getStyleClass().add(ROUNDED);
basicBtn.setOnAction(PRINT_SOURCE);
var accentBtn = new Button("Accent");
accentBtn.getStyleClass().addAll(ROUNDED, ACCENT);
accentBtn.setOnAction(PRINT_SOURCE);
var successBtn = new Button("Success", new FontIcon(Feather.CHECK));
successBtn.getStyleClass().addAll(ROUNDED, BUTTON_OUTLINED, SUCCESS);
successBtn.setOnAction(PRINT_SOURCE);
var content = new HBox(10);
content.getChildren().addAll(basicBtn, accentBtn, successBtn);
var content = new HBox(BLOCK_HGAP, basicBtn, accentBtn, successBtn);
return new SampleBlock("Rounded", content);
}
@ -210,9 +191,7 @@ public class ButtonPage extends AbstractPage {
iconBtn.getStyleClass().addAll(BUTTON_ICON);
iconBtn.setDisable(true);
var content = new HBox(10);
content.getChildren().addAll(basicBtn, defaultBtn, flatBtn, iconBtn);
var content = new HBox(BLOCK_HGAP, basicBtn, defaultBtn, flatBtn, iconBtn);
return new SampleBlock("Disabled", content);
}
}

@ -1,17 +1,17 @@
/* SPDX-License-Identifier: MIT */
package atlantafx.sampler.page.components;
import atlantafx.base.controls.ToggleSwitch;
import atlantafx.base.controls.Spacer;
import atlantafx.base.controls.ToggleSwitch;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.SampleBlock;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.chart.*;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.Separator;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.util.StringConverter;
@ -31,38 +31,30 @@ public class ChartPage extends AbstractPage {
@Override
public String getName() { return NAME; }
private VBox playground;
private ComboBox<Example> exampleSelect;
private final BorderPane chartWrapper = new BorderPane();
private final ComboBox<Example> exampleSelect = new ComboBox<>();
public ChartPage() {
super();
createView();
setUserContent(new VBox(
new SampleBlock("Playground", createPlayground())
));
}
private void createView() {
playground = new VBox(10);
playground.setMinHeight(100);
// === SELECT ===
exampleSelect = new ComboBox<>();
private VBox createPlayground() {
exampleSelect.setMaxWidth(Double.MAX_VALUE);
exampleSelect.getItems().setAll(Example.values());
exampleSelect.getSelectionModel().selectedItemProperty().addListener((obs, old, val) -> {
if (val == null) { return; }
if (playground.getChildren().size() != 5) {
throw new RuntimeException("Unexpected container size.");
}
Chart newChart = createChart(val);
// copy existing properties to the new chart
findDisplayedChart().ifPresent(ch -> newChart.setDisable(ch.isDisable()));
findDisplayedChart().ifPresent(chart -> newChart.setDisable(chart.isDisable()));
playground.getChildren().set(2, newChart);
chartWrapper.setCenter(newChart);
});
exampleSelect.setConverter(new StringConverter<>() {
@Override
public String toString(Example example) {
return example == null ? "" : example.getName();
@ -74,31 +66,22 @@ public class ChartPage extends AbstractPage {
}
});
// === CONTROLS ===
var disableToggle = new ToggleSwitch("Disable");
disableToggle.selectedProperty().addListener((obs, old, val) -> findDisplayedChart().ifPresent(ch -> {
if (val != null) { ch.setDisable(val); }
}));
var controls = new HBox(20,
new Spacer(),
disableToggle,
new Spacer()
);
var controls = new HBox(disableToggle);
controls.setAlignment(Pos.CENTER);
// ~
VBox playground = new VBox(SampleBlock.BLOCK_VGAP);
playground.getChildren().setAll(
new Label("Select an example:"),
new HBox(new Label("Select an example:"), new Spacer(), disableToggle),
exampleSelect,
new Spacer(Orientation.VERTICAL),
new Separator(),
controls
chartWrapper
);
userContent.getChildren().setAll(playground);
return playground;
}
@Override
@ -108,10 +91,9 @@ public class ChartPage extends AbstractPage {
}
private Optional<Chart> findDisplayedChart() {
return playground.getChildren().stream()
.filter(c -> c instanceof Chart)
.findFirst()
.map(c -> (Chart) c);
return chartWrapper.getChildren().size() > 0 ?
Optional.of((Chart) chartWrapper.getChildren().get(0)) :
Optional.empty();
}
private Chart createChart(Example example) {

@ -4,6 +4,7 @@ package atlantafx.sampler.page.components;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.SampleBlock;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
@ -23,35 +24,29 @@ public class CheckBoxPage extends AbstractPage {
}
private void createView() {
userContent.getChildren().addAll(
basicSamples(),
disabledSamples()
);
setUserContent(new FlowPane(
PAGE_HGAP, PAGE_VGAP,
basicSample(),
indeterminateSample(),
disabledSample()
));
}
private HBox basicSamples() {
private SampleBlock basicSample() {
basicCheck = new CheckBox("_Check Me");
basicCheck.setMnemonicParsing(true);
basicCheck.setOnAction(PRINT_SOURCE);
var basicBlock = new SampleBlock("Basic", basicCheck);
return new SampleBlock("Basic", basicCheck);
}
private SampleBlock indeterminateSample() {
indeterminateCheck = new CheckBox("C_heck Me");
indeterminateCheck.setAllowIndeterminate(true);
indeterminateCheck.setIndeterminate(true);
indeterminateCheck.setMnemonicParsing(true);
indeterminateCheck.setOnAction(PRINT_SOURCE);
var indeterminateBlock = new SampleBlock("Indeterminate", indeterminateCheck);
var root = new HBox(20);
root.getChildren().addAll(
basicBlock.getRoot(),
indeterminateBlock.getRoot()
);
return root;
return new SampleBlock("Indeterminate", indeterminateCheck);
}
private HBox disabledSamples() {
private SampleBlock disabledSample() {
var basicCheck = new CheckBox("Check Me");
basicCheck.setSelected(true);
basicCheck.setDisable(true);
@ -61,12 +56,10 @@ public class CheckBoxPage extends AbstractPage {
indeterminateCheck.setIndeterminate(true);
indeterminateCheck.setDisable(true);
var disabledBlock = new SampleBlock("Disabled", new HBox(10, basicCheck, indeterminateCheck));
var root = new HBox(20);
root.getChildren().addAll(disabledBlock.getRoot());
return root;
return new SampleBlock(
"Disabled",
new HBox(SampleBlock.BLOCK_HGAP, basicCheck, indeterminateCheck)
);
}
// visually compare normal and indeterminate checkboxes size
@ -80,13 +73,14 @@ public class CheckBoxPage extends AbstractPage {
((StackPane) normalBox).layout();
((StackPane) indeterminateBox).layout();
basicCheck.setText(String.format("_Check Me (size = H%.2f x W%.2f)",
System.out.printf("Basic: height = %.2f , width = %.2f\n",
normalBox.getBoundsInParent().getHeight(),
normalBox.getBoundsInParent().getWidth()
));
indeterminateCheck.setText(String.format("C_heck Me (box size = H%.2f x W%.2f)",
normalBox.getBoundsInParent().getHeight(),
normalBox.getBoundsInParent().getWidth()
));
);
System.out.printf("Indeterminate: height = %.2f , width = %.2f\n",
indeterminateBox.getBoundsInParent().getHeight(),
indeterminateBox.getBoundsInParent().getWidth()
);
}
}

@ -2,17 +2,20 @@
package atlantafx.sampler.page.components;
import atlantafx.base.controls.ToggleSwitch;
import atlantafx.base.controls.Spacer;
import atlantafx.sampler.page.AbstractPage;
import javafx.geometry.Pos;
import atlantafx.sampler.page.SampleBlock;
import javafx.geometry.HPos;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.ColorPicker;
import javafx.scene.control.Label;
import javafx.scene.control.Separator;
import javafx.scene.layout.HBox;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import static atlantafx.sampler.page.SampleBlock.BLOCK_HGAP;
import static atlantafx.sampler.page.SampleBlock.BLOCK_VGAP;
public class ColorPickerPage extends AbstractPage {
public static final String NAME = "ColorPicker";
@ -22,73 +25,72 @@ public class ColorPickerPage extends AbstractPage {
public ColorPickerPage() {
super();
createView();
setUserContent(new VBox(
new SampleBlock("Playground", createPlayground())
));
}
private void createView() {
userContent.getChildren().setAll(
playground()
);
}
private VBox playground() {
private GridPane createPlayground() {
var colorPicker = new ColorPicker();
colorPicker.setValue(Color.AQUA);
colorPicker.setValue(Color.DEEPSKYBLUE);
var pickerBox = new HBox(
new Spacer(),
colorPicker,
new Spacer()
);
var labelToggle = new ToggleSwitch("Show label");
var labelToggle = new ToggleSwitch();
labelToggle.setSelected(true);
labelToggle.selectedProperty().addListener((obs, old, val) -> {
colorPicker.setStyle("-fx-color-label-visible: false;");
if (val) { colorPicker.setStyle("-fx-color-label-visible: true;"); }
});
var disableToggle = new ToggleSwitch("Disable");
var disableToggle = new ToggleSwitch();
colorPicker.disableProperty().bind(disableToggle.selectedProperty());
var pickerStyleBox = new HBox(5, new Label("Picker Style"), pickerStyleChoice(colorPicker));
pickerStyleBox.setAlignment(Pos.CENTER);
var grid = new GridPane();
grid.setHgap(BLOCK_HGAP);
grid.setVgap(BLOCK_VGAP);
grid.add(colorPicker, 0, 0, 1, GridPane.REMAINING);
grid.add(createLabel("Show label"), 1, 0);
grid.add(labelToggle, 2, 0);
grid.add(createLabel("Picker style"), 1, 1);
grid.add(createPickerStyleChoice(colorPicker), 2, 1);
grid.add(createLabel("Disable"), 1, 2);
grid.add(disableToggle, 2, 2);
var controls = new HBox(20,
new Spacer(),
pickerStyleBox,
labelToggle,
disableToggle,
new Spacer()
);
controls.setAlignment(Pos.CENTER);
// ~
var root = new VBox(20);
root.setAlignment(Pos.CENTER);
root.getChildren().setAll(
pickerBox,
new Separator(),
controls
grid.getColumnConstraints().setAll(
new ColumnConstraints(200),
new ColumnConstraints(),
new ColumnConstraints()
);
return root;
return grid;
}
private ChoiceBox<String> pickerStyleChoice(ColorPicker colorPicker) {
private Label createLabel(String text) {
var label = new Label(text);
GridPane.setHalignment(label, HPos.RIGHT);
return label;
}
private ChoiceBox<String> createPickerStyleChoice(ColorPicker colorPicker) {
var optDefault = "Default";
var optButton = "Button";
var optSplitButton = "Split Button";
var choice = new ChoiceBox<String>();
choice.getItems().setAll(optDefault, optButton, optSplitButton);
choice.setPrefWidth(120);
choice.getSelectionModel().selectedItemProperty().addListener((obs, old, val) -> {
if (val == null) { return; }
colorPicker.getStyleClass().removeAll(ColorPicker.STYLE_CLASS_BUTTON, ColorPicker.STYLE_CLASS_SPLIT_BUTTON);
if (optButton.equals(val)) { colorPicker.getStyleClass().add(ColorPicker.STYLE_CLASS_BUTTON); }
if (optSplitButton.equals(val)) { colorPicker.getStyleClass().add(ColorPicker.STYLE_CLASS_SPLIT_BUTTON); }
colorPicker.getStyleClass().removeAll(
ColorPicker.STYLE_CLASS_BUTTON,
ColorPicker.STYLE_CLASS_SPLIT_BUTTON
);
if (optButton.equals(val)) {
colorPicker.getStyleClass().add(ColorPicker.STYLE_CLASS_BUTTON);
}
if (optSplitButton.equals(val)) {
colorPicker.getStyleClass().add(ColorPicker.STYLE_CLASS_SPLIT_BUTTON);
}
});
choice.getSelectionModel().select(optDefault);

@ -3,6 +3,7 @@ package atlantafx.sampler.page.components;
import atlantafx.base.theme.Tweaks;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.SampleBlock;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.HPos;
@ -11,7 +12,7 @@ import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import org.kordamp.ikonli.Ikon;
import org.kordamp.ikonli.javafx.FontIcon;
@ -21,6 +22,8 @@ import java.util.stream.IntStream;
import static atlantafx.base.theme.Styles.STATE_DANGER;
import static atlantafx.base.theme.Styles.STATE_SUCCESS;
import static atlantafx.sampler.page.SampleBlock.BLOCK_HGAP;
import static atlantafx.sampler.page.SampleBlock.BLOCK_VGAP;
import static atlantafx.sampler.util.Containers.H_GROW_NEVER;
import static javafx.collections.FXCollections.observableArrayList;
@ -34,49 +37,40 @@ public class ComboBoxPage extends AbstractPage {
public ComboBoxPage() {
super();
createView();
setUserContent(new VBox(
new SampleBlock("Examples", createPlayground())
));
}
private void createView() {
userContent.getChildren().setAll(
createGrid()
);
}
private Pane createGrid() {
private GridPane createPlayground() {
var grid = new GridPane();
grid.setHgap(20);
grid.setVgap(10);
grid.setHgap(BLOCK_HGAP);
grid.setVgap(BLOCK_VGAP);
grid.getColumnConstraints().setAll(H_GROW_NEVER, H_GROW_NEVER, H_GROW_NEVER);
grid.setMaxWidth((PREF_WIDTH * 3) + 100);
var comboLabel = new Label("C_omboBox");
comboLabel.setMnemonicParsing(true);
comboLabel.setStyle("-fx-font-weight: bold;");
grid.add(comboLabel, 0, 0);
var choiceLabel = new Label("C_hoiceBox");
choiceLabel.setMnemonicParsing(true);
choiceLabel.setStyle("-fx-font-weight: bold;");
grid.add(choiceLabel, 2, 0);
// default
grid.add(comboBox(), 0, 1);
grid.add(label("empty"), 1, 1);
grid.add(choiceBox(), 2, 1);
grid.add(createComboBox(), 0, 1);
grid.add(createLabel("empty"), 1, 1);
grid.add(createChoiceBox(), 2, 1);
// editable
grid.add(comboBox(c -> {
grid.add(createComboBoxWith(c -> {
c.setItems(createItems(5));
c.setEditable(true);
}), 0, 2);
grid.add(label("editable"), 1, 2);
grid.add(createLabel("editable"), 1, 2);
// placeholder
grid.add(comboBox(c -> c.setPlaceholder(new Label("Loading..."))), 0, 3);
grid.add(label("placeholder"), 1, 3);
grid.add(createComboBoxWith(c -> c.setPlaceholder(new Label("Loading..."))), 0, 3);
grid.add(createLabel("placeholder"), 1, 3);
// with icons
var badges = IntStream.range(0, 5).boxed()
@ -88,70 +82,70 @@ public class ComboBoxPage extends AbstractPage {
badgeCombo.setCellFactory(lv -> new BadgeCell());
badgeCombo.getSelectionModel().selectFirst();
grid.add(badgeCombo, 0, 4);
grid.add(label("graphic"), 1, 4);
grid.add(createLabel("graphic"), 1, 4);
// success
grid.add(comboBox(c -> {
grid.add(createComboBoxWith(c -> {
c.setItems(createItems(5));
c.pseudoClassStateChanged(STATE_SUCCESS, true);
c.getSelectionModel().selectFirst();
}), 0, 5);
grid.add(label("success"), 1, 5);
grid.add(choiceBox(c -> {
grid.add(createLabel("success"), 1, 5);
grid.add(createChoiceBoxWith(c -> {
c.setItems(createItems(5));
c.pseudoClassStateChanged(STATE_SUCCESS, true);
c.getSelectionModel().selectFirst();
}), 2, 5);
// negative
grid.add(comboBox(c -> {
grid.add(createComboBoxWith(c -> {
c.setItems(createItems(5));
c.pseudoClassStateChanged(STATE_DANGER, true);
c.getSelectionModel().selectFirst();
}), 0, 6);
grid.add(label("success"), 1, 6);
grid.add(choiceBox(c -> {
grid.add(createLabel("success"), 1, 6);
grid.add(createChoiceBoxWith(c -> {
c.setItems(createItems(5));
c.pseudoClassStateChanged(STATE_DANGER, true);
c.getSelectionModel().selectFirst();
}), 2, 6);
// alt icon
grid.add(comboBox(c -> {
grid.add(createComboBoxWith(c -> {
c.setItems(createItems(5));
c.getStyleClass().add(Tweaks.ALT_ICON);
c.getSelectionModel().selectFirst();
}), 0, 7);
grid.add(label("alt icon"), 1, 7);
grid.add(choiceBox(c -> {
grid.add(createLabel("alt icon"), 1, 7);
grid.add(createChoiceBoxWith(c -> {
c.setItems(createItems(5));
c.getStyleClass().add(Tweaks.ALT_ICON);
c.getSelectionModel().selectFirst();
}), 2, 7);
// disabled
grid.add(comboBox(c -> c.setDisable(true)), 0, 8);
grid.add(label("disabled"), 1, 8);
grid.add(choiceBox(c -> c.setDisable(true)), 2, 8);
grid.add(createComboBoxWith(c -> c.setDisable(true)), 0, 8);
grid.add(createLabel("disabled"), 1, 8);
grid.add(createChoiceBoxWith(c -> c.setDisable(true)), 2, 8);
// overflow
grid.add(comboBox(c -> {
// vertical overflow
grid.add(createComboBoxWith(c -> {
c.setItems(createItems(50));
c.getSelectionModel().selectFirst();
}), 0, 9);
grid.add(label("large list"), 1, 9);
grid.add(choiceBox(c -> {
grid.add(createLabel("large list"), 1, 9);
grid.add(createChoiceBoxWith(c -> {
c.setItems(createItems(50));
c.getSelectionModel().selectFirst();
}), 2, 9);
// overflow
grid.add(comboBox(c -> {
// horizontal overflow
grid.add(createComboBoxWith(c -> {
c.setItems(observableArrayList(generate(() -> FAKER.chuckNorris().fact(), 5)));
c.getSelectionModel().selectFirst();
}), 0, 10);
grid.add(label("wide text"), 1, 10);
grid.add(choiceBox(c -> {
grid.add(createLabel("wide text"), 1, 10);
grid.add(createChoiceBoxWith(c -> {
c.setItems(observableArrayList(generate(() -> FAKER.chuckNorris().fact(), 5)));
c.getSelectionModel().selectFirst();
}), 2, 10);
@ -159,38 +153,38 @@ public class ComboBoxPage extends AbstractPage {
return grid;
}
private ObservableList<String> createItems(int count) {
return observableArrayList(generate(() -> FAKER.hipster().word(), count));
private Label createLabel(String text) {
var label = new Label(text);
GridPane.setHalignment(label, HPos.CENTER);
return label;
}
private Label label(String text) {
return new Label(text) {{
GridPane.setHalignment(this, HPos.CENTER);
}};
private ComboBox<String> createComboBox() {
return createComboBoxWith(null);
}
private ComboBox<String> comboBox() {
return comboBox(null);
}
private ComboBox<String> comboBox(Consumer<ComboBox<String>> mutator) {
private ComboBox<String> createComboBoxWith(Consumer<ComboBox<String>> mutator) {
var c = new ComboBox<String>();
c.setPrefWidth(PREF_WIDTH);
if (mutator != null) { mutator.accept(c); }
return c;
}
private ChoiceBox<String> choiceBox() {
return choiceBox(null);
private ChoiceBox<String> createChoiceBox() {
return createChoiceBoxWith(null);
}
private ChoiceBox<String> choiceBox(Consumer<ChoiceBox<String>> mutator) {
private ChoiceBox<String> createChoiceBoxWith(Consumer<ChoiceBox<String>> mutator) {
var c = new ChoiceBox<String>();
c.setPrefWidth(PREF_WIDTH);
if (mutator != null) { mutator.accept(c); }
return c;
}
private ObservableList<String> createItems(int count) {
return observableArrayList(generate(() -> FAKER.hipster().word(), count));
}
///////////////////////////////////////////////////////////////////////////
private record Badge(String text, Ikon icon) { }

@ -14,58 +14,60 @@ import static atlantafx.base.theme.Styles.STATE_SUCCESS;
public class CustomTextFieldPage extends AbstractPage {
public static final String NAME = "CustomTextField";
private static final int PREF_WIDTH = 120;
@Override
public String getName() { return NAME; }
public CustomTextFieldPage() {
super();
createView();
setUserContent(new FlowPane(
PAGE_HGAP, PAGE_VGAP,
leftIconSample(),
rightIconSample(),
bothIconsSample(),
successSample(),
dangerSample()
));
}
private void createView() {
userContent.getChildren().setAll(samples());
}
private FlowPane samples() {
private SampleBlock leftIconSample() {
var leftIconField = new CustomTextField();
leftIconField.setPromptText("Prompt text");
leftIconField.setRight(new FontIcon(Feather.X));
var leftIconBlock = new SampleBlock("Node on the left", leftIconField);
leftIconField.setPrefWidth(PREF_WIDTH);
return new SampleBlock("Left", leftIconField);
}
private SampleBlock rightIconSample() {
var rightIconField = new CustomTextField();
rightIconField.setPromptText("Prompt text");
rightIconField.setLeft(new FontIcon(Feather.MAP_PIN));
var rightIconBlock = new SampleBlock("Node on the right", rightIconField);
rightIconField.setPrefWidth(PREF_WIDTH);
return new SampleBlock("Right", rightIconField);
}
private SampleBlock bothIconsSample() {
var bothIconField = new CustomTextField("Text");
bothIconField.setLeft(new FontIcon(Feather.MAP_PIN));
bothIconField.setRight(new FontIcon(Feather.X));
var bothIconBlock = new SampleBlock("Nodes on both sides", bothIconField);
var noSideIconsField = new CustomTextField("Text");
var noSideIconsBlock = new SampleBlock("No side nodes", noSideIconsField);
bothIconField.setPrefWidth(PREF_WIDTH);
return new SampleBlock("Both Sides", bothIconField);
}
private SampleBlock successSample() {
var successField = new CustomTextField("Text");
successField.pseudoClassStateChanged(STATE_SUCCESS, true);
successField.setRight(new FontIcon(Feather.X));
var successBlock = new SampleBlock("Success", successField);
successField.setPrefWidth(PREF_WIDTH);
return new SampleBlock("Success", successField);
}
private SampleBlock dangerSample() {
var dangerField = new CustomTextField("Text");
dangerField.pseudoClassStateChanged(STATE_DANGER, true);
dangerField.setLeft(new FontIcon(Feather.MAP_PIN));
var dangerBlock = new SampleBlock("Danger", dangerField);
var flowPane = new FlowPane(20, 20);
flowPane.getChildren().setAll(
leftIconBlock.getRoot(),
rightIconBlock.getRoot(),
bothIconBlock.getRoot(),
noSideIconsBlock.getRoot(),
successBlock.getRoot(),
dangerBlock.getRoot()
);
return flowPane;
dangerField.setPrefWidth(PREF_WIDTH);
return new SampleBlock("Danger", dangerField);
}
}

@ -6,6 +6,7 @@ import atlantafx.base.controls.Spacer;
import atlantafx.base.controls.ToggleSwitch;
import atlantafx.base.theme.Styles;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.SampleBlock;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Pos;
@ -47,20 +48,18 @@ public class DatePickerPage extends AbstractPage {
public DatePickerPage() {
super();
createView();
setUserContent(new VBox(
new SampleBlock("Playground", createPlayground())
));
}
private void createView() {
userContent.getChildren().addAll(playground());
}
private GridPane createPlayground() {
var grid = new GridPane();
grid.setHgap(40);
grid.setVgap(SampleBlock.BLOCK_VGAP);
private GridPane playground() {
var playground = new GridPane();
playground.setHgap(40);
playground.setVgap(10);
final var popupDatePicker = popupDatePicker();
final var inlineDatePicker = inlineDatePicker(null);
final var popupDatePicker = createPopupDatePicker();
final var inlineDatePicker = createInlineDatePicker(null);
var inlineValue = new Label();
inlineValue.setAlignment(Pos.CENTER);
@ -74,25 +73,27 @@ public class DatePickerPage extends AbstractPage {
weekNumToggle.setSelected(true);
var chronologyToggle = new ToggleSwitch("Second chronology");
chronologyToggle.selectedProperty().addListener((obs, old, val) ->
popupDatePicker.setChronology(val ? HijrahChronology.INSTANCE : null)
chronologyToggle.selectedProperty().addListener(
(obs, old, val) -> popupDatePicker.setChronology(val ? HijrahChronology.INSTANCE : null)
);
var editableToggle = new ToggleSwitch("Editable");
editableProperty.bind(editableToggle.selectedProperty());
// clear selected value to demonstrate prompt text
editableProperty.addListener((obs, old, val) -> popupDatePicker.setValue(val ? null : TODAY));
editableProperty.addListener(
(obs, old, val) -> popupDatePicker.setValue(val ? null : TODAY)
);
var offPastDatesToggle = new ToggleSwitch("No past dates");
offPastDatesProperty.bind(offPastDatesToggle.selectedProperty());
offPastDatesProperty.addListener((obs, old, val) -> {
popupDatePicker.setDayCellFactory(val ? dp -> new CustomDateCell() : null);
popupDatePicker.setDayCellFactory(val ? dp -> new FutureDateCell() : null);
popupDatePicker.setValue(TODAY);
// we have to create new date picker, because changing cell factory won't update existing cells
var datePicker = inlineDatePicker(val ? dp -> new CustomDateCell() : null);
playground.getChildren().removeIf(n -> n instanceof InlineDatePicker);
playground.add(datePicker, INLINE_DATE_PICKER_COL, INLINE_DATE_PICKER_ROW);
var datePicker = createInlineDatePicker(val ? dp -> new FutureDateCell() : null);
grid.getChildren().removeIf(n -> n instanceof InlineDatePicker);
grid.add(datePicker, INLINE_DATE_PICKER_COL, INLINE_DATE_PICKER_ROW);
inlineValue.textProperty().unbind();
inlineValue.textProperty().bind(datePicker.valueProperty().asString());
});
@ -100,7 +101,8 @@ public class DatePickerPage extends AbstractPage {
var disablePickerToggle = new ToggleSwitch("Disable");
disableProperty.bind(disablePickerToggle.selectedProperty());
var controls = new VBox(10,
var controls = new VBox(
SampleBlock.BLOCK_VGAP,
weekNumToggle,
chronologyToggle,
editableToggle,
@ -109,7 +111,7 @@ public class DatePickerPage extends AbstractPage {
);
controls.setAlignment(Pos.CENTER_RIGHT);
var colorSelector = new DatePickerColorSelector(playground);
var colorSelector = new DatePickerColorSelector(grid);
// == GRID ==
@ -119,19 +121,19 @@ public class DatePickerPage extends AbstractPage {
var inlineLabel = new Label("Inline");
inlineLabel.getStyleClass().add(Styles.TEXT_BOLD);
playground.add(defaultLabel, 0, 0);
playground.add(popupDatePicker, 0, 1);
playground.add(new Spacer(20), 0, 2);
playground.add(inlineLabel, 0, 3);
playground.add(inlineDatePicker, INLINE_DATE_PICKER_COL, INLINE_DATE_PICKER_ROW);
playground.add(inlineValue, 0, 5);
playground.add(colorSelector, 0, 6);
playground.add(controls, 1, 0, 1, REMAINING);
grid.add(defaultLabel, 0, 0);
grid.add(popupDatePicker, 0, 1);
grid.add(new Spacer(20), 0, 2);
grid.add(inlineLabel, 0, 3);
grid.add(inlineDatePicker, INLINE_DATE_PICKER_COL, INLINE_DATE_PICKER_ROW);
grid.add(inlineValue, 0, 5);
grid.add(colorSelector, 0, 6);
grid.add(controls, 1, 0, 1, REMAINING);
return playground;
return grid;
}
private DatePicker popupDatePicker() {
private DatePicker createPopupDatePicker() {
var datePicker = new DatePicker();
datePicker.setConverter(DATE_CONVERTER);
datePicker.setPromptText(DATE_FORMATTER_PROMPT);
@ -140,18 +142,16 @@ public class DatePickerPage extends AbstractPage {
datePicker.showWeekNumbersProperty().bind(weekNumProperty);
datePicker.editableProperty().bind(editableProperty);
datePicker.disableProperty().bind(disableProperty);
return datePicker;
}
private InlineDatePicker inlineDatePicker(Callback<InlineDatePicker, DateCell> dayCellFactory) {
private InlineDatePicker createInlineDatePicker(Callback<InlineDatePicker, DateCell> dayCellFactory) {
var datePicker = new InlineDatePicker();
datePicker.setMaxSize(USE_PREF_SIZE, USE_PREF_SIZE);
datePicker.setDayCellFactory(dayCellFactory);
datePicker.setValue(TODAY);
datePicker.showWeekNumbersProperty().bind(weekNumProperty);
datePicker.disableProperty().bind(disableProperty);
return datePicker;
}
@ -170,11 +170,13 @@ public class DatePickerPage extends AbstractPage {
if (dateString == null || dateString.trim().isEmpty()) { return null; }
try {
return LocalDate.parse(dateString, DATE_FORMATTER);
} catch (Exception e) { return null; }
} catch (Exception e) {
return null;
}
}
};
private static class CustomDateCell extends DateCell {
private static class FutureDateCell extends DateCell {
public void updateItem(LocalDate date, boolean empty) {
super.updateItem(date, empty);
@ -185,11 +187,11 @@ public class DatePickerPage extends AbstractPage {
// This class shares stylesheet with the AccentColorSelector
private static class DatePickerColorSelector extends HBox {
private final Pane root;
private final Pane parent;
public DatePickerColorSelector(Pane root) {
public DatePickerColorSelector(Pane parent) {
super();
this.root = root;
this.parent = parent;
createView();
}
@ -221,7 +223,7 @@ public class DatePickerPage extends AbstractPage {
}
private void setColorVariables(String bgColorName, String fgColorName) {
for (Node node : root.getChildren()) {
for (Node node : parent.getChildren()) {
var style = String.format("-color-date-border:%s;-color-date-month-year-bg:%s;-color-date-month-year-fg:%s;",
bgColorName,
bgColorName,
@ -236,7 +238,7 @@ public class DatePickerPage extends AbstractPage {
}
private void resetColorVariables() {
for (Node node : root.getChildren()) {
for (Node node : parent.getChildren()) {
if (node instanceof InlineDatePicker dp) {
var popup = dp.lookup(".date-picker-popup");
if (popup != null) { popup.setStyle(null); }

@ -2,7 +2,6 @@
package atlantafx.sampler.page.components;
import atlantafx.base.controls.ToggleSwitch;
import atlantafx.base.controls.Spacer;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.SampleBlock;
import javafx.beans.property.BooleanProperty;
@ -10,10 +9,7 @@ import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.layout.*;
import javafx.stage.StageStyle;
import org.kordamp.ikonli.feather.Feather;
import org.kordamp.ikonli.javafx.FontIcon;
@ -22,6 +18,7 @@ import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import static atlantafx.sampler.page.SampleBlock.BLOCK_HGAP;
import static javafx.scene.control.Alert.AlertType;
import static javafx.scene.control.ButtonBar.ButtonData;
@ -41,10 +38,6 @@ public class DialogPage extends AbstractPage {
}
private void createView() {
userContent.getChildren().setAll(playground());
}
private VBox playground() {
var showHeaderToggle = new ToggleSwitch("Show header");
showHeaderProperty.bind(showHeaderToggle.selectedProperty());
showHeaderToggle.setSelected(true);
@ -53,25 +46,30 @@ public class DialogPage extends AbstractPage {
minDecorationsProperty.bind(minDecorationsToggle.selectedProperty());
minDecorationsToggle.setSelected(true);
var controls = new HBox(20, new Spacer(), showHeaderToggle, minDecorationsToggle, new Spacer());
var controls = new HBox(BLOCK_HGAP, showHeaderToggle, minDecorationsToggle);
controls.setAlignment(Pos.CENTER);
// ~
var samples = new FlowPane(
PAGE_HGAP, PAGE_VGAP,
infoDialogSample(),
warningDialogSample(),
errorDialogSample(),
exceptionDialogSample(),
confirmationDialogSample(),
textInputDialogSample(),
choiceDialogSample()
);
var row1 = new HBox(40, infoDialogButton().getRoot(), warnDialogButton().getRoot(), errorDialogButton().getRoot());
var row2 = new HBox(40, exceptionDialogButton().getRoot(), confirmationDialogButton().getRoot(), textInputDialogButton().getRoot(), choiceDialogButton().getRoot());
var playground = new VBox(20);
playground.setMinHeight(100);
playground.getChildren().setAll(controls, new Separator(Orientation.HORIZONTAL), row1, row2);
return playground;
setUserContent(new VBox(
10,
controls,
new Separator(Orientation.HORIZONTAL),
samples
));
}
private SampleBlock infoDialogButton() {
var button = new Button("Click");
button.setGraphic(new FontIcon(Feather.INFO));
private SampleBlock infoDialogSample() {
var button = new Button("Click", new FontIcon(Feather.INFO));
button.setOnAction(e -> {
var alert = new Alert(AlertType.INFORMATION);
alert.setTitle("Information Dialog");
@ -85,9 +83,8 @@ public class DialogPage extends AbstractPage {
return new SampleBlock("Information", button);
}
private SampleBlock warnDialogButton() {
var button = new Button("Click");
button.setGraphic(new FontIcon(Feather.ALERT_TRIANGLE));
private SampleBlock warningDialogSample() {
var button = new Button("Click", new FontIcon(Feather.ALERT_TRIANGLE));
button.setOnAction(e -> {
var alert = new Alert(AlertType.WARNING);
alert.setTitle("Warning Dialog");
@ -101,9 +98,8 @@ public class DialogPage extends AbstractPage {
return new SampleBlock("Warning", button);
}
private SampleBlock errorDialogButton() {
var button = new Button("Click");
button.setGraphic(new FontIcon(Feather.X_CIRCLE));
private SampleBlock errorDialogSample() {
var button = new Button("Click", new FontIcon(Feather.X_CIRCLE));
button.setOnAction(e -> {
var alert = new Alert(AlertType.ERROR);
alert.setTitle("Error Dialog");
@ -117,10 +113,8 @@ public class DialogPage extends AbstractPage {
return new SampleBlock("Error", button);
}
private SampleBlock exceptionDialogButton() {
var button = new Button("Click");
button.setGraphic(new FontIcon(Feather.MEH));
private SampleBlock exceptionDialogSample() {
var button = new Button("Click", new FontIcon(Feather.MEH));
button.setOnAction(e -> {
var alert = new Alert(AlertType.ERROR);
alert.setTitle("Error Dialog");
@ -157,10 +151,8 @@ public class DialogPage extends AbstractPage {
return new SampleBlock("Exception", button);
}
private SampleBlock confirmationDialogButton() {
var button = new Button("Click");
button.setGraphic(new FontIcon(Feather.CHECK_SQUARE));
private SampleBlock confirmationDialogSample() {
var button = new Button("Click", new FontIcon(Feather.CHECK_SQUARE));
button.setOnAction(e -> {
var alert = new Alert(AlertType.CONFIRMATION);
alert.setTitle("Confirmation Dialog");
@ -181,10 +173,8 @@ public class DialogPage extends AbstractPage {
return new SampleBlock("Confirmation", button);
}
private SampleBlock textInputDialogButton() {
var button = new Button("Click");
button.setGraphic(new FontIcon(Feather.EDIT_2));
private SampleBlock textInputDialogSample() {
var button = new Button("Click", new FontIcon(Feather.EDIT_2));
button.setOnAction(e -> {
var dialog = new TextInputDialog();
dialog.setTitle("Text Input Dialog");
@ -198,10 +188,8 @@ public class DialogPage extends AbstractPage {
return new SampleBlock("Text Input", button);
}
private SampleBlock choiceDialogButton() {
var button = new Button("Click");
button.setGraphic(new FontIcon(Feather.LIST));
private SampleBlock choiceDialogSample() {
var button = new Button("Click", new FontIcon(Feather.LIST));
button.setOnAction(e -> {
var choices = new ArrayList<>();
choices.add("A");

@ -2,27 +2,28 @@
package atlantafx.sampler.page.components;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.SampleBlock;
import javafx.scene.layout.VBox;
import javafx.scene.web.HTMLEditor;
public class HTMLEditorPage extends AbstractPage {
public static final String NAME = "HTMLEditor";
@Override
public String getName() { return NAME; }
public HTMLEditorPage() {
super();
createView();
setUserContent(new VBox(
editorSample()
));
}
private void createView() {
private SampleBlock editorSample() {
var editor = new HTMLEditor();
editor.setPrefHeight(400);
editor.setHtmlText(String.join("<br/><br/>", FAKER.lorem().paragraphs(5)));
userContent.getChildren().setAll(editor);
}
@Override
public String getName() {
return NAME;
editor.setHtmlText(String.join("<br/><br/>", FAKER.lorem().paragraphs(10)));
return new SampleBlock("Playground", editor);
}
}

@ -3,11 +3,12 @@ package atlantafx.sampler.page.components;
import atlantafx.base.theme.Styles;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.Page;
import atlantafx.sampler.page.SampleBlock;
import javafx.geometry.Pos;
import javafx.scene.control.*;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import org.kordamp.ikonli.feather.Feather;
import org.kordamp.ikonli.javafx.FontIcon;
@ -22,16 +23,10 @@ public class InputGroupPage extends AbstractPage {
public InputGroupPage() {
super();
createView();
}
private void createView() {
userContent.getChildren().addAll(new FlowPane(
20, 20,
httpMethodSample().getRoot(),
passwordSample().getRoot(),
networkSample().getRoot(),
dropdownSample().getRoot()
setUserContent(new VBox(
Page.PAGE_VGAP,
expandingHBox(httpMethodSample(), passwordSample()),
expandingHBox(networkSample(), dropdownSample())
));
}
@ -47,11 +42,11 @@ public class InputGroupPage extends AbstractPage {
var box = new HBox(leftCombo, rightText);
box.setAlignment(Pos.CENTER_LEFT);
return new SampleBlock("ComboBox + TextField", box);
return new SampleBlock("ComboBox & TextField", box);
}
private SampleBlock passwordSample() {
var leftPassword = new PasswordField();
var leftPassword = new TextField();
leftPassword.setText(FAKER.internet().password());
leftPassword.getStyleClass().add(Styles.LEFT_PILL);
@ -63,19 +58,21 @@ public class InputGroupPage extends AbstractPage {
var box = new HBox(leftPassword, rightBtn);
box.setAlignment(Pos.CENTER_LEFT);
return new SampleBlock("Password Field + Button", box);
return new SampleBlock("Text Field & Button", box);
}
private SampleBlock networkSample() {
var leftText = new TextField("192.168.1.10");
leftText.getStyleClass().add(Styles.LEFT_PILL);
leftText.setPrefWidth(140);
var centerText = new TextField("24");
centerText.getStyleClass().add(Styles.CENTER_PILL);
centerText.setPrefWidth(50);
centerText.setPrefWidth(70);
var rightText = new TextField("192.168.1.10");
var rightText = new TextField("192.168.1.1");
rightText.getStyleClass().add(Styles.RIGHT_PILL);
rightText.setPrefWidth(140);
var box = new HBox(leftText, centerText, rightText);
box.setAlignment(Pos.CENTER_LEFT);
@ -84,21 +81,26 @@ public class InputGroupPage extends AbstractPage {
}
private SampleBlock dropdownSample() {
var leftMenu = new MenuButton(FAKER.harryPotter().character());
leftMenu.getItems().addAll(
new MenuItem(FAKER.harryPotter().spell()),
new MenuItem(FAKER.harryPotter().spell()),
new MenuItem(FAKER.harryPotter().spell())
);
leftMenu.getStyleClass().add(Styles.LEFT_PILL);
var rightText = new TextField();
var rightText = new TextField(FAKER.harryPotter().spell());
rightText.getStyleClass().add(Styles.RIGHT_PILL);
var spellItem = new MenuItem("Spell");
spellItem.setOnAction(e -> rightText.setText(FAKER.harryPotter().spell()));
var characterItem = new MenuItem("Character");
characterItem.setOnAction(e -> rightText.setText(FAKER.harryPotter().character()));
var locationItem = new MenuItem("Location");
locationItem.setOnAction(e -> rightText.setText(FAKER.harryPotter().location()));
var leftMenu = new MenuButton("Generate");
leftMenu.getItems().addAll(spellItem, characterItem, locationItem);
leftMenu.getStyleClass().add(Styles.LEFT_PILL);
var box = new HBox(leftMenu, rightText);
box.setAlignment(Pos.CENTER_LEFT);
return new SampleBlock("MenuButton + TextField", box);
return new SampleBlock("MenuButton & TextField", box);
}
}

@ -6,14 +6,16 @@ import atlantafx.base.controls.ToggleSwitch;
import atlantafx.base.theme.Tweaks;
import atlantafx.sampler.fake.domain.Book;
import atlantafx.sampler.page.AbstractPage;
import javafx.geometry.Orientation;
import atlantafx.sampler.page.SampleBlock;
import javafx.geometry.Pos;
import javafx.scene.control.*;
import javafx.scene.control.cell.CheckBoxListCell;
import javafx.scene.control.cell.ChoiceBoxListCell;
import javafx.scene.control.cell.ComboBoxListCell;
import javafx.scene.control.cell.TextFieldListCell;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.util.StringConverter;
import org.kordamp.ikonli.feather.Feather;
@ -27,6 +29,8 @@ import java.util.function.Consumer;
import java.util.stream.Collectors;
import static atlantafx.base.theme.Styles.*;
import static atlantafx.sampler.page.SampleBlock.BLOCK_HGAP;
import static atlantafx.sampler.page.SampleBlock.BLOCK_VGAP;
public class ListPage extends AbstractPage {
@ -35,54 +39,20 @@ public class ListPage extends AbstractPage {
@Override
public String getName() { return NAME; }
private VBox playground;
private ComboBox<Example> exampleSelect;
private final List<Book> dataList = generate(() -> Book.random(FAKER), 50);
private final StringConverter<Book> bookStringConverter = new StringConverter<>() {
@Override
public String toString(Book book) {
if (book == null) { return null; }
return String.format("\"%s\" by %s", book.getTitle(), book.getAuthor());
}
@Override
public Book fromString(String s) {
if (s == null) { return null; }
int sep = s.indexOf("\" by");
String title = s.substring(1, sep);
String author = s.substring(sep + "\" by".length());
return dataList.stream()
.filter(b -> Objects.equals(b.getTitle(), title) && Objects.equals(b.getAuthor(), author))
.findFirst()
.orElse(null);
}
};
private final StringConverter<Book> bookStringConverter = new BookStringConverter(dataList);
private final BorderPane listWrapper = new BorderPane();
private final ComboBox<Example> exampleSelect = createExampleSelect();
public ListPage() {
super();
createView();
var sample = new SampleBlock("Playground", createPlayground());
sample.setFillHeight(true);
setUserContent(sample);
}
private void createView() {
exampleSelect = exampleSelect();
playground = playground(exampleSelect);
userContent.getChildren().setAll(playground);
}
@Override
protected void onRendered() {
super.onRendered();
exampleSelect.getSelectionModel().selectFirst();
}
private VBox playground(ComboBox<Example> exampleSelect) {
var playground = new VBox(10);
playground.setMinHeight(100);
private VBox createPlayground() {
var borderedToggle = new ToggleSwitch("Bordered");
borderedToggle.selectedProperty().addListener((obs, old, value) -> toggleListProperty(lv -> toggleStyleClass(lv, BORDERED)));
@ -100,37 +70,30 @@ public class ListPage extends AbstractPage {
if (val != null) { lv.setDisable(val); }
}));
var controls = new HBox(20,
new Spacer(),
borderedToggle,
denseToggle,
stripedToggle,
edge2edgeToggle,
disableToggle,
new Spacer()
);
var controls = new HBox(BLOCK_HGAP, borderedToggle, denseToggle, stripedToggle, edge2edgeToggle);
controls.setAlignment(Pos.CENTER);
playground.getChildren().setAll(
new Label("Select an example:"),
VBox.setVgrow(listWrapper, Priority.ALWAYS);
var playground = new VBox(
BLOCK_VGAP,
new HBox(new Label("Select an example:"), new Spacer(), disableToggle),
exampleSelect,
new Spacer(Orientation.VERTICAL), // placeholder for ListView<?>
listWrapper,
controls
);
playground.setMinHeight(100);
return playground;
}
private ComboBox<Example> exampleSelect() {
private ComboBox<Example> createExampleSelect() {
var select = new ComboBox<Example>();
select.setMaxWidth(Double.MAX_VALUE);
select.getItems().setAll(Example.values());
select.getSelectionModel().selectedItemProperty().addListener((obs, old, val) -> {
if (val == null) { return; }
if (playground.getChildren().size() != 4) {
throw new RuntimeException("Unexpected container size.");
}
ListView<?> newList = createList(val);
@ -139,15 +102,13 @@ public class ListPage extends AbstractPage {
List<String> currentStyles = lv.getStyleClass();
currentStyles.remove("list-view");
newList.getStyleClass().addAll(currentStyles);
newList.setDisable(lv.isDisable());
});
playground.getChildren().set(2, newList);
listWrapper.setCenter(newList);
});
select.setConverter(new StringConverter<>() {
@Override
public String toString(Example example) {
return example == null ? "" : example.getName();
@ -162,12 +123,16 @@ public class ListPage extends AbstractPage {
return select;
}
@Override
protected void onRendered() {
super.onRendered();
exampleSelect.getSelectionModel().selectFirst();
}
private Optional<ListView<?>> findDisplayedList() {
if (playground == null) { return Optional.empty(); }
return playground.getChildren().stream()
.filter(c -> c instanceof ListView<?>)
.findFirst()
.map(c -> (ListView<?>) c);
return listWrapper.getChildren().size() > 0 ?
Optional.of((ListView<?>) listWrapper.getChildren().get(0)) :
Optional.empty();
}
private void toggleListProperty(Consumer<ListView<?>> consumer) {
@ -263,6 +228,35 @@ public class ListPage extends AbstractPage {
}
}
private static class BookStringConverter extends StringConverter<Book> {
private final List<Book> dataList;
public BookStringConverter(List<Book> dataList) {
this.dataList = dataList;
}
@Override
public String toString(Book book) {
if (book == null) { return null; }
return String.format("\"%s\" by %s", book.getTitle(), book.getAuthor());
}
@Override
public Book fromString(String s) {
if (s == null) { return null; }
int sep = s.indexOf("\" by");
String title = s.substring(1, sep);
String author = s.substring(sep + "\" by".length());
return dataList.stream()
.filter(b -> Objects.equals(b.getTitle(), title) && Objects.equals(b.getAuthor(), author))
.findFirst()
.orElse(null);
}
}
private static class NestedControlsListCell extends ListCell<Book> {
private final HBox root;

@ -3,64 +3,63 @@ package atlantafx.sampler.page.components;
import atlantafx.base.theme.Tweaks;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.Page;
import atlantafx.sampler.page.SampleBlock;
import javafx.geometry.Side;
import javafx.scene.control.MenuButton;
import javafx.scene.control.MenuItem;
import javafx.scene.control.SplitMenuButton;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import org.kordamp.ikonli.feather.Feather;
import org.kordamp.ikonli.javafx.FontIcon;
import java.util.stream.IntStream;
import static atlantafx.base.theme.Styles.*;
import static atlantafx.sampler.page.SampleBlock.BLOCK_HGAP;
import static atlantafx.sampler.page.SampleBlock.BLOCK_VGAP;
public class MenuButtonPage extends AbstractPage {
public static final String NAME = "MenuButton";
private static final int PREF_WIDTH = 150;
@Override
public String getName() { return NAME; }
public MenuButtonPage() {
super();
createView();
}
setUserContent(new VBox(
Page.PAGE_VGAP,
expandingHBox(basicSample(), iconOnlySample()),
expandingHBox(coloredSample(), outlinedSample()),
expandingHBox(popupSideSample(), noArrowSample()),
disabledSample()
private void createView() {
userContent.getChildren().addAll(
basicSample().getRoot(),
coloredSample().getRoot(),
popupSideSample().getRoot(),
iconOnlySample().getRoot(),
outlinedSample().getRoot(),
disabledSample().getRoot(),
noArrowSample().getRoot()
);
));
}
private SampleBlock basicSample() {
var basicMenuBtn = new MenuButton("_Menu Button");
basicMenuBtn.getItems().setAll(menuItems(5));
basicMenuBtn.getItems().setAll(createItems(5));
basicMenuBtn.setMnemonicParsing(true);
basicMenuBtn.setOnAction(PRINT_SOURCE);
var basicSplitBtn = new SplitMenuButton(menuItems(5));
var basicSplitBtn = new SplitMenuButton(createItems(5));
basicSplitBtn.setText("_Split Menu Button");
basicSplitBtn.setMnemonicParsing(true);
basicSplitBtn.setOnAction(PRINT_SOURCE);
var flatMenuBtn = new MenuButton("Flat");
flatMenuBtn.getItems().setAll(menuItems(5));
flatMenuBtn.getItems().setAll(createItems(5));
flatMenuBtn.getStyleClass().add(FLAT);
var flatSplitBtn = new SplitMenuButton(menuItems(5));
var flatSplitBtn = new SplitMenuButton(createItems(5));
flatSplitBtn.setText("Flat");
flatSplitBtn.getStyleClass().add(FLAT);
var content = new HBox(10);
var content = new FlowPane(BLOCK_HGAP, BLOCK_VGAP);
content.getChildren().addAll(basicMenuBtn, basicSplitBtn, flatMenuBtn, flatSplitBtn);
return new SampleBlock("Basic", content);
@ -68,72 +67,76 @@ public class MenuButtonPage extends AbstractPage {
private SampleBlock coloredSample() {
var accentMenuBtn = new MenuButton("_Accent");
accentMenuBtn.getItems().setAll(menuItems(5));
accentMenuBtn.getItems().setAll(createItems(5));
accentMenuBtn.getStyleClass().add(ACCENT);
accentMenuBtn.setMnemonicParsing(true);
accentMenuBtn.setOnAction(PRINT_SOURCE);
accentMenuBtn.setPrefWidth(PREF_WIDTH);
var accentSplitBtn = new SplitMenuButton(menuItems(5));
var accentSplitBtn = new SplitMenuButton(createItems(5));
accentSplitBtn.setText("Accent");
accentSplitBtn.getStyleClass().add(ACCENT);
accentSplitBtn.setPrefWidth(PREF_WIDTH);
var successMenuBtn = new MenuButton("Success");
successMenuBtn.getItems().setAll(menuItems(5));
successMenuBtn.getItems().setAll(createItems(5));
successMenuBtn.setGraphic(new FontIcon(Feather.CHECK));
successMenuBtn.getStyleClass().add(SUCCESS);
successMenuBtn.setPrefWidth(PREF_WIDTH);
var successSplitBtn = new SplitMenuButton(menuItems(5));
successMenuBtn.setGraphic(new FontIcon(Feather.CHECK));
var successSplitBtn = new SplitMenuButton(createItems(5));
successSplitBtn.setGraphic(new FontIcon(Feather.CHECK));
successSplitBtn.setText("_Success");
successSplitBtn.getStyleClass().add(SUCCESS);
successSplitBtn.setMnemonicParsing(true);
successSplitBtn.setOnAction(PRINT_SOURCE);
successSplitBtn.setPrefWidth(PREF_WIDTH);
var dangerMenuBtn = new MenuButton("Danger");
dangerMenuBtn.setGraphic(new FontIcon(Feather.TRASH));
dangerMenuBtn.getItems().setAll(menuItems(5));
dangerMenuBtn.getItems().setAll(createItems(5));
dangerMenuBtn.getStyleClass().add(DANGER);
dangerMenuBtn.setPrefWidth(PREF_WIDTH);
var dangerSplitBtn = new SplitMenuButton(menuItems(5));
var dangerSplitBtn = new SplitMenuButton(createItems(5));
dangerSplitBtn.setGraphic(new FontIcon(Feather.TRASH));
dangerSplitBtn.setText("_Danger");
dangerSplitBtn.getStyleClass().add(DANGER);
dangerSplitBtn.setMnemonicParsing(true);
dangerSplitBtn.setOnAction(PRINT_SOURCE);
dangerSplitBtn.setPrefWidth(PREF_WIDTH);
var content = new HBox(10);
content.getChildren().addAll(
accentMenuBtn, accentSplitBtn,
successMenuBtn, successSplitBtn,
dangerMenuBtn, dangerSplitBtn
);
var content = new GridPane();
content.setHgap(BLOCK_HGAP);
content.setVgap(BLOCK_VGAP);
content.add(accentMenuBtn, 0, 0);
content.add(accentSplitBtn, 1, 0);
content.add(successMenuBtn, 0, 1);
content.add(successSplitBtn, 1, 1);
content.add(dangerMenuBtn, 0, 2);
content.add(dangerSplitBtn, 1, 2);
return new SampleBlock("Colored", content);
}
private SampleBlock popupSideSample() {
var topMenuBtn = new MenuButton("Top");
topMenuBtn.getItems().setAll(menuItems(5));
topMenuBtn.getItems().setAll(createItems(5));
topMenuBtn.setPopupSide(Side.TOP);
var rightMenuBtn = new MenuButton("Right");
rightMenuBtn.getItems().setAll(menuItems(5));
rightMenuBtn.getItems().setAll(createItems(5));
rightMenuBtn.setPopupSide(Side.RIGHT);
rightMenuBtn.getStyleClass().add(ACCENT);
var bottomMenuBtn = new MenuButton("Bottom");
bottomMenuBtn.setGraphic(new FontIcon(Feather.CHECK));
bottomMenuBtn.getItems().setAll(menuItems(5));
bottomMenuBtn.getItems().setAll(createItems(5));
bottomMenuBtn.setPopupSide(Side.BOTTOM);
bottomMenuBtn.getStyleClass().add(SUCCESS);
var leftMenuBtn = new MenuButton("Left");
leftMenuBtn.setGraphic(new FontIcon(Feather.TRASH));
leftMenuBtn.getItems().setAll(menuItems(5));
leftMenuBtn.getItems().setAll(createItems(5));
leftMenuBtn.setPopupSide(Side.LEFT);
leftMenuBtn.getStyleClass().add(DANGER);
var content = new FlowPane(10, 10);
var content = new FlowPane(BLOCK_HGAP, BLOCK_VGAP);
content.getChildren().addAll(topMenuBtn, rightMenuBtn, bottomMenuBtn, leftMenuBtn);
return new SampleBlock("Popup Side", content);
@ -142,23 +145,23 @@ public class MenuButtonPage extends AbstractPage {
private SampleBlock iconOnlySample() {
var basicMenuBtn = new MenuButton();
basicMenuBtn.setGraphic(new FontIcon(Feather.MORE_HORIZONTAL));
basicMenuBtn.getItems().setAll(menuItems(5));
basicMenuBtn.getItems().setAll(createItems(5));
basicMenuBtn.getStyleClass().addAll(BUTTON_ICON);
var basicSplitBtn = new SplitMenuButton(menuItems(5));
var basicSplitBtn = new SplitMenuButton(createItems(5));
basicSplitBtn.setGraphic(new FontIcon(Feather.MORE_HORIZONTAL));
basicSplitBtn.getStyleClass().addAll(BUTTON_ICON);
var accentMenuBtn = new MenuButton();
accentMenuBtn.setGraphic(new FontIcon(Feather.MENU));
accentMenuBtn.getItems().setAll(menuItems(5));
accentMenuBtn.getItems().setAll(createItems(5));
accentMenuBtn.getStyleClass().addAll(BUTTON_ICON, ACCENT);
var accentSplitBtn = new SplitMenuButton(menuItems(5));
var accentSplitBtn = new SplitMenuButton(createItems(5));
accentSplitBtn.setGraphic(new FontIcon(Feather.MENU));
accentSplitBtn.getStyleClass().addAll(BUTTON_ICON, ACCENT);
var content = new FlowPane(10, 10);
var content = new FlowPane(BLOCK_HGAP, BLOCK_VGAP);
content.getChildren().addAll(basicMenuBtn, basicSplitBtn, accentMenuBtn, accentSplitBtn);
return new SampleBlock("Icons", content);
@ -166,71 +169,77 @@ public class MenuButtonPage extends AbstractPage {
private SampleBlock outlinedSample() {
var accentMenuBtn = new MenuButton("Accen_t");
accentMenuBtn.getItems().setAll(menuItems(5));
accentMenuBtn.getItems().setAll(createItems(5));
accentMenuBtn.getStyleClass().addAll(BUTTON_OUTLINED, ACCENT);
accentMenuBtn.setMnemonicParsing(true);
accentMenuBtn.setOnAction(PRINT_SOURCE);
accentMenuBtn.setPrefWidth(PREF_WIDTH);
var accentSplitBtn = new SplitMenuButton(menuItems(5));
var accentSplitBtn = new SplitMenuButton(createItems(5));
accentSplitBtn.setText("Accent");
accentSplitBtn.getStyleClass().addAll(BUTTON_OUTLINED, ACCENT);
accentSplitBtn.setPrefWidth(PREF_WIDTH);
var successMenuBtn = new MenuButton("S_uccess");
successMenuBtn.getItems().setAll(menuItems(5));
successMenuBtn.getItems().setAll(createItems(5));
successMenuBtn.setGraphic(new FontIcon(Feather.CHECK));
successMenuBtn.getStyleClass().addAll(BUTTON_OUTLINED, SUCCESS);
successMenuBtn.setMnemonicParsing(true);
successMenuBtn.setOnAction(PRINT_SOURCE);
successMenuBtn.setPrefWidth(PREF_WIDTH);
var successSplitBtn = new SplitMenuButton(menuItems(5));
successMenuBtn.setGraphic(new FontIcon(Feather.CHECK));
var successSplitBtn = new SplitMenuButton(createItems(5));
successSplitBtn.setGraphic(new FontIcon(Feather.CHECK));
successSplitBtn.setText("Success");
successSplitBtn.getStyleClass().addAll(BUTTON_OUTLINED, SUCCESS);
successSplitBtn.setPrefWidth(PREF_WIDTH);
var dangerMenuBtn = new MenuButton("Danger");
dangerMenuBtn.setGraphic(new FontIcon(Feather.TRASH));
dangerMenuBtn.getItems().setAll(menuItems(5));
dangerMenuBtn.getItems().setAll(createItems(5));
dangerMenuBtn.getStyleClass().addAll(BUTTON_OUTLINED, DANGER);
dangerMenuBtn.setPrefWidth(PREF_WIDTH);
var dangerSplitBtn = new SplitMenuButton(menuItems(5));
var dangerSplitBtn = new SplitMenuButton(createItems(5));
dangerSplitBtn.setGraphic(new FontIcon(Feather.TRASH));
dangerSplitBtn.setText("Dan_ger");
dangerSplitBtn.getStyleClass().addAll(BUTTON_OUTLINED, DANGER);
dangerSplitBtn.setMnemonicParsing(true);
dangerSplitBtn.setOnAction(PRINT_SOURCE);
dangerSplitBtn.setPrefWidth(PREF_WIDTH);
var content = new HBox(10);
content.getChildren().addAll(
accentMenuBtn, accentSplitBtn,
successMenuBtn, successSplitBtn,
dangerMenuBtn, dangerSplitBtn
);
var content = new GridPane();
content.setHgap(BLOCK_HGAP);
content.setVgap(BLOCK_VGAP);
content.add(accentMenuBtn, 0, 0);
content.add(accentSplitBtn, 1, 0);
content.add(successMenuBtn, 0, 1);
content.add(successSplitBtn, 1, 1);
content.add(dangerMenuBtn, 0, 2);
content.add(dangerSplitBtn, 1, 2);
return new SampleBlock("Outlined", content);
}
private SampleBlock disabledSample() {
var basicMenuBtn = new MenuButton("Menu Button");
basicMenuBtn.getItems().setAll(menuItems(5));
basicMenuBtn.getItems().setAll(createItems(5));
basicMenuBtn.setDisable(true);
var accentSplitBtn = new SplitMenuButton();
accentSplitBtn.setText("Accent");
accentSplitBtn.getItems().setAll(menuItems(5));
accentSplitBtn.getItems().setAll(createItems(5));
accentSplitBtn.getStyleClass().addAll(ACCENT);
accentSplitBtn.setDisable(true);
var flatMenuBtn = new MenuButton("Flat");
flatMenuBtn.getItems().setAll(menuItems(5));
flatMenuBtn.getItems().setAll(createItems(5));
flatMenuBtn.getStyleClass().addAll(FLAT);
flatMenuBtn.setDisable(true);
var iconMenuBtn = new MenuButton();
iconMenuBtn.getItems().setAll(menuItems(5));
iconMenuBtn.getItems().setAll(createItems(5));
iconMenuBtn.getStyleClass().addAll(BUTTON_ICON);
iconMenuBtn.setDisable(true);
var sample = new HBox(10);
var sample = new HBox(BLOCK_HGAP);
sample.getChildren().addAll(basicMenuBtn, accentSplitBtn, flatMenuBtn, iconMenuBtn);
return new SampleBlock("Disabled", sample);
@ -238,26 +247,26 @@ public class MenuButtonPage extends AbstractPage {
private SampleBlock noArrowSample() {
var basicMenuBtn = new MenuButton("_Menu Button");
basicMenuBtn.getItems().setAll(menuItems(5));
basicMenuBtn.getItems().setAll(createItems(5));
basicMenuBtn.getStyleClass().addAll(Tweaks.NO_ARROW);
var flatMenuBtn = new MenuButton("Flat");
flatMenuBtn.getItems().setAll(menuItems(5));
flatMenuBtn.getItems().setAll(createItems(5));
flatMenuBtn.getStyleClass().addAll(FLAT, Tweaks.NO_ARROW);
var iconMenuBtn = new MenuButton();
iconMenuBtn.setGraphic(new FontIcon(Feather.MORE_HORIZONTAL));
iconMenuBtn.getItems().setAll(menuItems(5));
iconMenuBtn.getItems().setAll(createItems(5));
iconMenuBtn.getStyleClass().addAll(BUTTON_ICON, Tweaks.NO_ARROW);
var content = new HBox(10);
var content = new HBox(BLOCK_HGAP);
content.getChildren().addAll(basicMenuBtn, flatMenuBtn, iconMenuBtn);
return new SampleBlock("No Arrow", content);
}
@SuppressWarnings("SameParameterValue")
private MenuItem[] menuItems(int count) {
private MenuItem[] createItems(int count) {
return IntStream.range(0, count)
.mapToObj(i -> new MenuItem(FAKER.babylon5().character()))
.toArray(MenuItem[]::new);

@ -4,6 +4,7 @@ package atlantafx.sampler.page.components;
import atlantafx.base.theme.Styles;
import atlantafx.sampler.fake.SampleMenuBar;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.Page;
import atlantafx.sampler.page.SampleBlock;
import atlantafx.sampler.util.Controls;
import javafx.geometry.Pos;
@ -12,9 +13,9 @@ import javafx.scene.control.Label;
import javafx.scene.control.SeparatorMenuItem;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.layout.VBox;
import org.kordamp.ikonli.feather.Feather;
import static atlantafx.sampler.util.Controls.menuItem;
import static javafx.scene.input.KeyCombination.CONTROL_DOWN;
public class MenuPage extends AbstractPage {
@ -26,14 +27,10 @@ public class MenuPage extends AbstractPage {
public MenuPage() {
super();
createView();
}
private void createView() {
userContent.getChildren().addAll(
menuBarSample().getRoot(),
contextMenuExample().getRoot()
);
setUserContent(new VBox(Page.PAGE_VGAP,
menuBarSample(),
contextMenuExample()
));
}
private SampleBlock menuBarSample() {
@ -45,11 +42,9 @@ public class MenuPage extends AbstractPage {
var undoItem = Controls.menuItem("_Undo", Feather.CORNER_DOWN_LEFT, new KeyCodeCombination(KeyCode.Z, CONTROL_DOWN));
undoItem.setMnemonicParsing(true);
undoItem.setOnAction(PRINT_SOURCE);
var redoItem = Controls.menuItem("_Redo", Feather.CORNER_DOWN_RIGHT, new KeyCodeCombination(KeyCode.Y, CONTROL_DOWN));
redoItem.setMnemonicParsing(true);
redoItem.setOnAction(PRINT_SOURCE);
contextMenu.getItems().addAll(
undoItem,
@ -60,13 +55,13 @@ public class MenuPage extends AbstractPage {
Controls.menuItem("Paste", null, new KeyCodeCombination(KeyCode.V, CONTROL_DOWN))
);
var sample = new Label("Right-Click Here");
sample.setAlignment(Pos.CENTER);
sample.setMinSize(400, 80);
sample.setMaxSize(200, 80);
sample.setContextMenu(contextMenu);
sample.getStyleClass().add(Styles.BORDERED);
var content = new Label("Right-Click Here");
content.setAlignment(Pos.CENTER);
content.setMinSize(400, 80);
content.setMaxSize(400, 80);
content.setContextMenu(contextMenu);
content.getStyleClass().add(Styles.BORDERED);
return new SampleBlock("Context menu", sample);
return new SampleBlock("Context Menu", content);
}
}

@ -19,6 +19,8 @@ import java.time.LocalDate;
import java.util.stream.IntStream;
import static atlantafx.base.theme.Styles.*;
import static atlantafx.sampler.page.SampleBlock.BLOCK_HGAP;
import static atlantafx.sampler.page.SampleBlock.BLOCK_VGAP;
public class OverviewPage extends AbstractPage {
@ -26,44 +28,25 @@ public class OverviewPage extends AbstractPage {
private static final int BUTTON_WIDTH = 120;
private static final int COMBO_BOX_WIDTH = 150;
private static final int H_GAP = 20;
private static final int V_GAP = 10;
@Override
public String getName() { return NAME; }
public OverviewPage() {
super();
createView();
}
private void createView() {
userContent.getChildren().setAll(
buttonSample().getRoot(),
new HBox(H_GAP * 2,
iconButtonSample().getRoot(),
dropdownMenuSample().getRoot()
),
new HBox(H_GAP * 2,
checkBoxSample().getRoot(),
radioButtonSample().getRoot(),
toggleSwitchSample().getRoot()
),
comboBoxSample().getRoot(),
sliderSample().getRoot(),
new HBox(H_GAP * 2,
textFieldSample().getRoot(),
spinnerSample().getRoot()
),
textAreaSample().getRoot()
);
setUserContent(new VBox(
PAGE_VGAP,
buttonSample(),
expandingHBox(iconButtonSample(), dropdownMenuSample()),
expandingHBox(checkBoxSample(), radioButtonSample(), toggleSwitchSample()),
comboBoxSample(),
sliderSample(),
expandingHBox(textFieldSample(), spinnerSample()),
textAreaSample()
));
}
private SampleBlock buttonSample() {
var grid = new GridPane();
grid.setVgap(V_GAP);
grid.setHgap(H_GAP);
var basicBtn = new Button("Basic");
basicBtn.setPrefWidth(BUTTON_WIDTH);
@ -88,13 +71,15 @@ public class OverviewPage extends AbstractPage {
outlinedBtn.setPrefWidth(BUTTON_WIDTH);
var twoButtonGroup = new ToggleGroup();
var leftPill = toggleButton("Toggle 1", twoButtonGroup, true, LEFT_PILL);
leftPill.setPrefWidth(BUTTON_WIDTH + grid.getHgap() / 2);
var rightPill = toggleButton("Toggle 2", twoButtonGroup, false, RIGHT_PILL);
rightPill.setPrefWidth(BUTTON_WIDTH + grid.getHgap() / 2);
var leftPill = createToggleButton("Toggle 1", twoButtonGroup, true, LEFT_PILL);
leftPill.setPrefWidth(BUTTON_WIDTH + BLOCK_HGAP / 2.0);
var rightPill = createToggleButton("Toggle 2", twoButtonGroup, false, RIGHT_PILL);
rightPill.setPrefWidth(BUTTON_WIDTH + BLOCK_HGAP / 2.0);
var twoButtonBox = new HBox(leftPill, rightPill);
// ~
var grid = new GridPane();
grid.setVgap(BLOCK_VGAP);
grid.setHgap(BLOCK_HGAP);
grid.add(basicBtn, 0, 0);
grid.add(flatBtn, 1, 0);
grid.add(successBtn, 2, 0);
@ -108,10 +93,6 @@ public class OverviewPage extends AbstractPage {
}
private SampleBlock iconButtonSample() {
var grid = new GridPane();
grid.setVgap(V_GAP);
grid.setHgap(H_GAP);
var basicBtn = new Button("", new FontIcon(Feather.MORE_HORIZONTAL));
basicBtn.getStyleClass().addAll(BUTTON_ICON);
@ -129,7 +110,9 @@ public class OverviewPage extends AbstractPage {
flatBtn.getStyleClass().addAll(BUTTON_CIRCLE, FLAT);
flatBtn.setShape(new Circle(50));
// ~
var grid = new GridPane();
grid.setVgap(BLOCK_VGAP);
grid.setHgap(BLOCK_HGAP);
grid.add(basicBtn, 0, 0);
grid.add(successBtn, 1, 0);
grid.add(dangerBtn, 2, 0);
@ -140,46 +123,42 @@ public class OverviewPage extends AbstractPage {
}
private SampleBlock dropdownMenuSample() {
var grid = new GridPane();
grid.setVgap(V_GAP);
grid.setHgap(H_GAP);
var basicMenuBtn = new MenuButton("Menu Button");
basicMenuBtn.getItems().setAll(createMenuItems());
basicMenuBtn.setPrefWidth(COMBO_BOX_WIDTH);
var basicIconBtn = new MenuButton();
basicIconBtn.setGraphic(new FontIcon(Feather.MORE_HORIZONTAL));
basicIconBtn.getItems().setAll(menuItems(5));
basicIconBtn.getItems().setAll(createMenuItems());
basicIconBtn.getStyleClass().addAll(BUTTON_ICON);
var accentIconBtn = new MenuButton();
accentIconBtn.setGraphic(new FontIcon(Feather.MENU));
accentIconBtn.getItems().setAll(menuItems(5));
accentIconBtn.getItems().setAll(createMenuItems());
accentIconBtn.getStyleClass().addAll(BUTTON_ICON, ACCENT);
var basicMenuBtn = new MenuButton("Menu Button");
basicMenuBtn.getItems().setAll(menuItems(5));
basicMenuBtn.setPrefWidth(COMBO_BOX_WIDTH);
var basicSplitBtn = new SplitMenuButton(menuItems(5));
var basicSplitBtn = new SplitMenuButton(createMenuItems());
basicSplitBtn.setText("Split Menu Button");
var outlinedSplitBtn = new SplitMenuButton(menuItems(5));
var outlinedSplitBtn = new SplitMenuButton(createMenuItems());
outlinedSplitBtn.setGraphic(new FontIcon(Feather.TRASH));
outlinedSplitBtn.setText("Danger");
outlinedSplitBtn.getStyleClass().addAll(BUTTON_OUTLINED, DANGER);
outlinedSplitBtn.setPrefWidth(COMBO_BOX_WIDTH);
// ~
grid.add(basicIconBtn, 0, 0);
grid.add(accentIconBtn, 1, 0);
grid.add(basicMenuBtn, 2, 0);
grid.add(basicSplitBtn, 0, 1, 2, 1);
grid.add(outlinedSplitBtn, 2, 1);
var grid = new GridPane();
grid.setVgap(BLOCK_VGAP);
grid.setHgap(BLOCK_HGAP);
grid.add(basicMenuBtn, 0, 0);
grid.add(basicIconBtn, 1, 0);
grid.add(accentIconBtn, 2, 0);
grid.add(basicSplitBtn, 1, 1, 2, 1);
grid.add(outlinedSplitBtn, 0, 1);
return new SampleBlock("Dropdown Menus", grid);
}
private SampleBlock checkBoxSample() {
var box = new VBox(V_GAP);
var opt1 = new CheckBox("Option 1");
var opt2 = new CheckBox("Option 2");
@ -189,13 +168,11 @@ public class OverviewPage extends AbstractPage {
opt3.setAllowIndeterminate(true);
opt3.setIndeterminate(true);
box.getChildren().setAll(opt1, opt2, opt3);
return new SampleBlock("Check Boxes", box);
var container = new VBox(BLOCK_VGAP, opt1, opt2, opt3);
return new SampleBlock("Check Boxes", container);
}
private SampleBlock radioButtonSample() {
var box = new VBox(V_GAP);
var group = new ToggleGroup();
var opt1 = new RadioButton("Option 1");
@ -208,25 +185,21 @@ public class OverviewPage extends AbstractPage {
var opt3 = new RadioButton("Option 3");
opt3.setToggleGroup(group);
box.getChildren().setAll(opt1, opt2, opt3);
return new SampleBlock("Radio Buttons", box);
var container = new VBox(BLOCK_VGAP, opt1, opt2, opt3);
return new SampleBlock("Radio Buttons", container);
}
private SampleBlock toggleSwitchSample() {
var box = new VBox(V_GAP);
var switch1 = new ToggleSwitch();
var switch2 = new ToggleSwitch();
switch2.setSelected(true);
box.getChildren().setAll(switch1, switch2);
return new SampleBlock("Switches", box);
var container = new VBox(BLOCK_VGAP, switch1, switch2);
return new SampleBlock("Switches", container);
}
private SampleBlock comboBoxSample() {
var box = new HBox(H_GAP);
var comboBox = new ComboBox<String>();
comboBox.getItems().setAll("Option 1", "Option 2", "Option 3");
comboBox.getStyleClass().add(Tweaks.ALT_ICON);
@ -246,13 +219,11 @@ public class OverviewPage extends AbstractPage {
colorPicker.setPrefWidth(COMBO_BOX_WIDTH);
colorPicker.setValue(Color.ORANGE);
box.getChildren().setAll(comboBox, choiceBox, datePicker, colorPicker);
return new SampleBlock("Combo Boxes", box);
var container = new HBox(BLOCK_HGAP, comboBox, choiceBox, datePicker, colorPicker);
return new SampleBlock("Combo Boxes", container);
}
private SampleBlock sliderSample() {
var box = new HBox(H_GAP);
var slider = new Slider(1, 5, 3);
slider.setPrefWidth(BUTTON_WIDTH * 2);
@ -265,38 +236,34 @@ public class OverviewPage extends AbstractPage {
tickSlider.setSnapToTicks(true);
tickSlider.setPrefWidth(BUTTON_WIDTH * 2);
box.getChildren().setAll(slider, tickSlider);
return new SampleBlock("Sliders", box);
var container = new HBox(BLOCK_HGAP, slider, tickSlider);
return new SampleBlock("Sliders", container);
}
private SampleBlock textFieldSample() {
var box = new HBox(H_GAP);
var textField = new TextField("Text");
textField.setPrefWidth(BUTTON_WIDTH);
textField.setPrefWidth(COMBO_BOX_WIDTH);
var passwordField = new PasswordField();
passwordField.setText(FAKER.internet().password());
passwordField.setPrefWidth(BUTTON_WIDTH);
passwordField.setPrefWidth(COMBO_BOX_WIDTH);
box.getChildren().setAll(textField, passwordField);
return new SampleBlock("Text Fields", box);
var container = new HBox(BLOCK_HGAP, textField, passwordField);
return new SampleBlock("Text Fields", container);
}
private SampleBlock spinnerSample() {
var box = new HBox(H_GAP);
var spinner1 = new Spinner<Integer>(1, 10, 1);
IntegerStringConverter.createFor(spinner1);
spinner1.setPrefWidth(BUTTON_WIDTH);
spinner1.setPrefWidth(COMBO_BOX_WIDTH);
var spinner2 = new Spinner<Integer>(1, 10, 1);
IntegerStringConverter.createFor(spinner2);
spinner2.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
spinner2.setPrefWidth(BUTTON_WIDTH);
spinner2.setPrefWidth(COMBO_BOX_WIDTH);
box.getChildren().setAll(spinner1, spinner2);
return new SampleBlock("Spinners", box);
var container = new HBox(BLOCK_HGAP, spinner1, spinner2);
return new SampleBlock("Spinners", container);
}
private SampleBlock textAreaSample() {
@ -308,7 +275,7 @@ public class OverviewPage extends AbstractPage {
return new SampleBlock("Text Area", textArea);
}
private ToggleButton toggleButton(String text,
private ToggleButton createToggleButton(String text,
ToggleGroup group,
boolean selected,
String... styleClasses) {
@ -320,9 +287,8 @@ public class OverviewPage extends AbstractPage {
return toggleButton;
}
@SuppressWarnings("SameParameterValue")
private MenuItem[] menuItems(int count) {
return IntStream.range(0, count)
private MenuItem[] createMenuItems() {
return IntStream.range(0, 5)
.mapToObj(i -> new MenuItem(FAKER.babylon5().character()))
.toArray(MenuItem[]::new);
}

@ -1,10 +1,10 @@
/* SPDX-License-Identifier: MIT */
package atlantafx.sampler.page.components;
import atlantafx.base.theme.Styles;
import atlantafx.base.controls.ToggleSwitch;
import atlantafx.base.controls.Spacer;
import atlantafx.base.theme.Styles;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.SampleBlock;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.control.Pagination;
@ -12,9 +12,11 @@ import javafx.scene.control.Separator;
import javafx.scene.control.Spinner;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import static atlantafx.sampler.page.SampleBlock.BLOCK_HGAP;
import static atlantafx.sampler.page.SampleBlock.BLOCK_VGAP;
public class PaginationPage extends AbstractPage {
public static final String NAME = "Pagination";
@ -25,14 +27,12 @@ public class PaginationPage extends AbstractPage {
public PaginationPage() {
super();
createView();
setUserContent(new VBox(
new SampleBlock("Playground", createPlayground())
));
}
private void createView() {
var playground = new VBox(10);
playground.setMinHeight(100);
playground.setAlignment(Pos.CENTER);
private VBox createPlayground() {
var pagination = new Pagination();
pagination.setCurrentPageIndex(1);
pagination.setPageFactory(index -> {
@ -76,13 +76,14 @@ public class PaginationPage extends AbstractPage {
pagination.disableProperty().bind(disableToggle.selectedProperty());
var controls = new GridPane();
controls.setHgap(20);
controls.setVgap(10);
controls.setHgap(BLOCK_HGAP);
controls.setVgap(BLOCK_VGAP);
controls.setAlignment(Pos.CENTER);
controls.add(new Label("Page count:"), 0, 0);
controls.add(new Label("Page count"), 0, 0);
controls.add(pageCountSpinner, 1, 0);
controls.add(new Label("Visible count:"), 0, 1);
controls.add(new Label("Visible count"), 0, 1);
controls.add(visibleCountSpinner, 1, 1);
controls.add(new Label("Bullet style"), 3, 0);
@ -99,15 +100,9 @@ public class PaginationPage extends AbstractPage {
// ~
var separator = new Separator();
separator.getStyleClass().addAll(Styles.LARGE);
var playground = new VBox(BLOCK_VGAP, pagination, new Separator(), controls);
playground.setMinHeight(100);
playground.getChildren().setAll(
pagination,
separator,
new HBox(new Spacer(), controls, new Spacer())
);
userContent.getChildren().setAll(playground);
return playground;
}
}

@ -5,16 +5,22 @@ import atlantafx.base.controls.InlineDatePicker;
import atlantafx.base.controls.Popover;
import atlantafx.base.controls.Popover.ArrowLocation;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.Page;
import atlantafx.sampler.page.SampleBlock;
import atlantafx.sampler.theme.CSSFragment;
import javafx.geometry.Pos;
import javafx.scene.control.Hyperlink;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
import java.time.LocalDate;
import static atlantafx.sampler.page.SampleBlock.BLOCK_HGAP;
import static atlantafx.sampler.page.SampleBlock.BLOCK_VGAP;
public class PopoverPage extends AbstractPage {
public static final String NAME = "Popover";
@ -24,66 +30,73 @@ public class PopoverPage extends AbstractPage {
public PopoverPage() {
super();
createView();
setUserContent(new VBox(Page.PAGE_VGAP,
new HBox(PAGE_HGAP, textSample(), datePickerSample()),
positionSample()
));
}
private void createView() {
userContent.getChildren().setAll(basicSamples(), positionSamples().getRoot());
private SampleBlock textSample() {
var popover = new Popover(createTextFlow(30));
popover.setTitle("Lorem Ipsum");
popover.setHeaderAlwaysVisible(true);
popover.setDetachable(true);
var link = createHyperlink("Click me");
link.setOnAction(e -> popover.show(link));
return new SampleBlock("Text", link);
}
private HBox basicSamples() {
var textPopover = new Popover(textFlow(30));
textPopover.setTitle("Lorem Ipsum");
textPopover.setHeaderAlwaysVisible(true);
textPopover.setDetachable(true);
var textLink = hyperlink("Click me");
textLink.setOnAction(e -> textPopover.show(textLink));
var textBlock = new SampleBlock("Basic", textLink);
private SampleBlock datePickerSample() {
var datePicker = new InlineDatePicker();
datePicker.setValue(LocalDate.now());
var datePopover = new Popover(datePicker);
textPopover.setHeaderAlwaysVisible(false);
datePopover.setDetachable(true);
var dateLink = hyperlink("Click me");
dateLink.setOnAction(e -> datePopover.show(dateLink));
var dateBlock = new SampleBlock("Date picker", dateLink);
var popover = new Popover(datePicker);
popover.setHeaderAlwaysVisible(false);
popover.setDetachable(true);
var box = new HBox(20,
textBlock.getRoot(),
dateBlock.getRoot()
);
box.setAlignment(Pos.CENTER_LEFT);
var link = createHyperlink("Click me");
link.setOnAction(e -> popover.show(link));
new CSSFragment("""
.popover .date-picker-popup {
-color-date-border: transparent;
-color-date-bg: transparent;
-color-date-day-bg: transparent;
-color-date-month-year-bg: transparent;
-color-date-day-bg-hover: -color-bg-subtle;
}
"""
).addTo(link);
return box;
return new SampleBlock("Date Picker", link);
}
private SampleBlock positionSamples() {
private SampleBlock positionSample() {
var grid = new GridPane();
grid.setHgap(20);
grid.setVgap(20);
grid.setHgap(BLOCK_HGAP);
grid.setVgap(BLOCK_VGAP);
grid.add(arrowPositionBlock(ArrowLocation.TOP_LEFT), 0, 0);
grid.add(arrowPositionBlock(ArrowLocation.TOP_CENTER), 0, 1);
grid.add(arrowPositionBlock(ArrowLocation.TOP_RIGHT), 0, 2);
grid.add(createArrowPositionBlock(ArrowLocation.TOP_LEFT), 0, 0);
grid.add(createArrowPositionBlock(ArrowLocation.TOP_CENTER), 0, 1);
grid.add(createArrowPositionBlock(ArrowLocation.TOP_RIGHT), 0, 2);
grid.add(arrowPositionBlock(ArrowLocation.RIGHT_TOP), 1, 0);
grid.add(arrowPositionBlock(ArrowLocation.RIGHT_CENTER), 1, 1);
grid.add(arrowPositionBlock(ArrowLocation.RIGHT_BOTTOM), 1, 2);
grid.add(createArrowPositionBlock(ArrowLocation.RIGHT_TOP), 1, 0);
grid.add(createArrowPositionBlock(ArrowLocation.RIGHT_CENTER), 1, 1);
grid.add(createArrowPositionBlock(ArrowLocation.RIGHT_BOTTOM), 1, 2);
grid.add(arrowPositionBlock(ArrowLocation.BOTTOM_LEFT), 2, 0);
grid.add(arrowPositionBlock(ArrowLocation.BOTTOM_CENTER), 2, 1);
grid.add(arrowPositionBlock(ArrowLocation.BOTTOM_RIGHT), 2, 2);
grid.add(createArrowPositionBlock(ArrowLocation.BOTTOM_LEFT), 2, 0);
grid.add(createArrowPositionBlock(ArrowLocation.BOTTOM_CENTER), 2, 1);
grid.add(createArrowPositionBlock(ArrowLocation.BOTTOM_RIGHT), 2, 2);
grid.add(arrowPositionBlock(ArrowLocation.LEFT_TOP), 3, 0);
grid.add(arrowPositionBlock(ArrowLocation.LEFT_CENTER), 3, 1);
grid.add(arrowPositionBlock(ArrowLocation.LEFT_BOTTOM), 3, 2);
grid.add(createArrowPositionBlock(ArrowLocation.LEFT_TOP), 3, 0);
grid.add(createArrowPositionBlock(ArrowLocation.LEFT_CENTER), 3, 1);
grid.add(createArrowPositionBlock(ArrowLocation.LEFT_BOTTOM), 3, 2);
return new SampleBlock("Position", grid);
}
private Hyperlink hyperlink(String text) {
private Hyperlink createHyperlink(String text) {
Hyperlink hyperlink = new Hyperlink(text);
hyperlink.setMinWidth(50);
hyperlink.setMinHeight(50);
@ -91,18 +104,20 @@ public class PopoverPage extends AbstractPage {
return hyperlink;
}
private TextFlow textFlow(int wordCount) {
private TextFlow createTextFlow(int wordCount) {
var textFlow = new TextFlow(new Text(FAKER.lorem().sentence(wordCount)));
textFlow.setPrefWidth(300);
return textFlow;
}
private Hyperlink arrowPositionBlock(ArrowLocation arrowLocation) {
var link = hyperlink(String.valueOf(arrowLocation));
var popover = new Popover(textFlow(50));
private Hyperlink createArrowPositionBlock(ArrowLocation arrowLocation) {
var popover = new Popover(createTextFlow(50));
popover.setHeaderAlwaysVisible(false);
popover.setArrowLocation(arrowLocation);
var link = createHyperlink(String.valueOf(arrowLocation));
link.setOnAction(e -> popover.show(link));
return link;
}
}

@ -1,8 +1,8 @@
/* SPDX-License-Identifier: MIT */
package atlantafx.sampler.page.components;
import atlantafx.base.theme.Styles;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.Page;
import atlantafx.sampler.page.SampleBlock;
import atlantafx.sampler.theme.CSSFragment;
import javafx.concurrent.Task;
@ -18,9 +18,12 @@ import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
// Indeterminate (animated) progress bar and also progress indicator are very expensive.
// It consumes single CPU core and a lot of memory.
// #javafx-bug
import static atlantafx.base.theme.Styles.*;
import static atlantafx.sampler.page.SampleBlock.BLOCK_HGAP;
import static atlantafx.sampler.page.SampleBlock.BLOCK_VGAP;
// #javafx-bug Indeterminate (animated) progress bar and also progress indicator
// are VERY resource expensive. It consumes a single CPU core and a lot of memory.
public class ProgressPage extends AbstractPage {
public static final String NAME = "Progress";
@ -30,50 +33,44 @@ public class ProgressPage extends AbstractPage {
public ProgressPage() {
super();
createView();
setUserContent(new VBox(Page.PAGE_VGAP,
expandingHBox(basicBarSample(), basicIndicatorSample()),
expandingHBox(barSizeSample(), colorChangeSample())
));
}
private void createView() {
userContent.getChildren().addAll(
basicBarSamples().getRoot(),
basicIndicatorSamples().getRoot(),
barSizeSamples().getRoot(),
colorChangeSample().getRoot()
private SampleBlock basicBarSample() {
var flowPane = new FlowPane(
BLOCK_HGAP, BLOCK_VGAP,
createBar(0, false),
createBar(0.5, false),
createBar(1, false),
createBar(0.5, true)
);
}
private SampleBlock basicBarSamples() {
var flowPane = new FlowPane(20, 20);
flowPane.setAlignment(Pos.CENTER_LEFT);
flowPane.getChildren().addAll(
progressBar(0, false),
progressBar(0.5, false),
progressBar(1, false),
progressBar(0.5, true)
);
return new SampleBlock("Progress Bar", flowPane);
}
private SampleBlock basicIndicatorSamples() {
var flowPane = new FlowPane(20, 20);
flowPane.getChildren().addAll(
progressIndicator(0, false),
progressIndicator(0.5, false),
progressIndicator(1, false),
progressIndicator(0.5, true)
private SampleBlock basicIndicatorSample() {
var flowPane = new FlowPane(
BLOCK_HGAP, BLOCK_VGAP,
createIndicator(0, false),
createIndicator(0.5, false),
createIndicator(1, false),
createIndicator(0.5, true)
);
flowPane.setAlignment(Pos.TOP_LEFT);
return new SampleBlock("Progress Indicator", flowPane);
}
private SampleBlock barSizeSamples() {
private SampleBlock barSizeSample() {
var container = new VBox(
10,
new HBox(20, progressBar(0.5, false, Styles.SMALL), new Text("small")),
new HBox(20, progressBar(0.5, false, Styles.MEDIUM), new Text("medium")),
new HBox(20, progressBar(0.5, false, Styles.LARGE), new Text("large"))
BLOCK_VGAP,
new HBox(20, createBar(0.5, false, SMALL), new Text("small")),
new HBox(20, createBar(0.5, false, MEDIUM), new Text("medium")),
new HBox(20, createBar(0.5, false, LARGE), new Text("large"))
);
container.getChildren().forEach(c -> ((HBox) c).setAlignment(Pos.CENTER_LEFT));
@ -83,10 +80,10 @@ public class ProgressPage extends AbstractPage {
private SampleBlock colorChangeSample() {
var stateSuccess = PseudoClass.getPseudoClass("state-success");
var stateDanger = PseudoClass.getPseudoClass("state-danger");
var width = 400;
var width = 300;
var bar = new ProgressBar(0);
bar.getStyleClass().add(Styles.LARGE);
bar.getStyleClass().add(LARGE);
bar.setPrefWidth(width);
bar.setMaxWidth(width);
@ -102,7 +99,7 @@ public class ProgressPage extends AbstractPage {
// ~
var content = new VBox(10);
var content = new VBox(BLOCK_VGAP);
content.getChildren().setAll(barStack, runBtn);
content.setAlignment(Pos.CENTER_LEFT);
@ -127,7 +124,8 @@ public class ProgressPage extends AbstractPage {
.example:state-danger .label {
-fx-text-fill: -color-fg-emphasis;
}
""").addTo(content);
"""
).addTo(content);
runBtn.setOnAction(e1 -> {
var task = new Task<Void>() {
@ -162,17 +160,17 @@ public class ProgressPage extends AbstractPage {
new Thread(task).start();
});
return new SampleBlock("Live color change", content);
return new SampleBlock("Dynamic Color Change", content);
}
private ProgressIndicator progressBar(double progress, boolean disabled, String... styleClasses) {
private ProgressIndicator createBar(double progress, boolean disabled, String... styleClasses) {
var bar = new ProgressBar(progress);
bar.getStyleClass().addAll(styleClasses);
bar.setDisable(disabled);
return bar;
}
private ProgressIndicator progressIndicator(double progress, boolean disabled) {
private ProgressIndicator createIndicator(double progress, boolean disabled) {
var indicator = new ProgressIndicator(progress);
indicator.setMinSize(50, 50);
indicator.setMaxSize(50, 50);

@ -2,12 +2,15 @@
package atlantafx.sampler.page.components;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.Page;
import atlantafx.sampler.page.SampleBlock;
import javafx.scene.control.RadioButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.HBox;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.VBox;
import static atlantafx.sampler.page.SampleBlock.BLOCK_VGAP;
public class RadioButtonPage extends AbstractPage {
public static final String NAME = "RadioButton";
@ -17,36 +20,30 @@ public class RadioButtonPage extends AbstractPage {
public RadioButtonPage() {
super();
createView();
setUserContent(new FlowPane(
Page.PAGE_HGAP, Page.PAGE_VGAP,
basicSample(),
groupSample(),
disabledSample()
));
}
private void createView() {
userContent.getChildren().addAll(
basicSamples(),
groupSamples().getRoot()
);
private SampleBlock basicSample() {
var radio1 = new RadioButton("_Check Me");
radio1.setMnemonicParsing(true);
var radio2 = new RadioButton("Check Me");
return new SampleBlock("Basic", new VBox(BLOCK_VGAP, radio1, radio2));
}
private HBox basicSamples() {
var basicRadio = new RadioButton("_Check Me");
basicRadio.setMnemonicParsing(true);
basicRadio.setOnAction(PRINT_SOURCE);
var basicBlock = new SampleBlock("Basic", basicRadio);
var disabledRadio = new RadioButton("Check Me");
disabledRadio.setDisable(true);
var disabledBlock = new SampleBlock("Disabled", disabledRadio);
var root = new HBox(20);
root.getChildren().addAll(
basicBlock.getRoot(),
disabledBlock.getRoot()
);
return root;
private SampleBlock disabledSample() {
var radio = new RadioButton("Check Me");
radio.setDisable(true);
return new SampleBlock("Disabled", radio);
}
private SampleBlock groupSamples() {
private SampleBlock groupSample() {
var group = new ToggleGroup();
var musicRadio = new RadioButton("Music");

@ -2,84 +2,86 @@
package atlantafx.sampler.page.components;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.Page;
import atlantafx.sampler.page.SampleBlock;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.layout.*;
public class ScrollPanePage extends AbstractPage {
public static final String NAME = "ScrollPane";
private static final int SPACING = 1;
@Override
public String getName() { return NAME; }
public ScrollPanePage() {
super();
createView();
}
private void createView() {
userContent.getChildren().setAll(new FlowPane(20, 20,
hScrollBlock().getRoot(),
vScrollBlock().getRoot(),
gridScrollBlock().getRoot(),
disabledBlock().getRoot()
setUserContent(new FlowPane(
Page.PAGE_VGAP, Page.PAGE_HGAP,
horizontalScrollSample(),
verticalScrollSample(),
gridScrollSample(),
disabledSample()
));
}
private SampleBlock hScrollBlock() {
private SampleBlock horizontalScrollSample() {
var scrollPane = new ScrollPane();
scrollPane.setMaxHeight(100);
scrollPane.setMaxWidth(300);
scrollPane.setContent(new HBox(2,
new Rectangle(200, 100, Color.GREEN),
new Rectangle(200, 100, Color.RED)
scrollPane.setContent(new HBox(SPACING,
createRegion(200, 100, "-color-success-emphasis"),
createRegion(200, 100, "-color-danger-emphasis")
));
scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
return new SampleBlock("Horizontal scrolling", scrollPane);
return new SampleBlock("Horizontal Scrolling", scrollPane);
}
private SampleBlock vScrollBlock() {
private SampleBlock verticalScrollSample() {
var scrollPane = new ScrollPane();
scrollPane.setMaxHeight(100);
scrollPane.setMaxWidth(300);
scrollPane.setContent(new VBox(2,
new Rectangle(300, 75, Color.GREEN),
new Rectangle(300, 75, Color.RED)
scrollPane.setContent(new VBox(SPACING,
createRegion(300, 75, "-color-success-emphasis"),
createRegion(300, 75, "-color-danger-emphasis")
));
scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
return new SampleBlock("Vertical scrolling", scrollPane);
return new SampleBlock("Vertical Scrolling", scrollPane);
}
private SampleBlock gridScrollBlock() {
private SampleBlock gridScrollSample() {
var grid = new GridPane();
grid.add(new Rectangle(200, 75, Color.GREEN), 0, 0);
grid.add(new Rectangle(200, 75, Color.RED), 1, 0);
grid.add(new Rectangle(200, 75, Color.RED), 0, 1);
grid.add(new Rectangle(200, 75, Color.GREEN), 1, 1);
grid.setHgap(2);
grid.setVgap(2);
grid.add(createRegion(200, 75, "-color-success-emphasis"), 0, 0);
grid.add(createRegion(200, 75, "-color-danger-emphasis"), 1, 0);
grid.add(createRegion(200, 75, "-color-danger-emphasis"), 0, 1);
grid.add(createRegion(200, 75, "-color-success-emphasis"), 1, 1);
grid.setHgap(SPACING);
grid.setVgap(SPACING);
var gridScroll = new ScrollPane();
gridScroll.setMaxHeight(100);
gridScroll.setMaxWidth(300);
gridScroll.setContent(grid);
return new SampleBlock("Horizontal & vertical scrolling", gridScroll);
return new SampleBlock("Scrolling", gridScroll);
}
private SampleBlock disabledBlock() {
var block = gridScrollBlock();
block.setText("Disabled");
private SampleBlock disabledSample() {
var block = gridScrollSample();
block.setTitle("Disabled");
block.getContent().setDisable(true);
return block;
}
private Region createRegion(int width, int height, String bg) {
var r = new Region();
r.setMinSize(width, height);
r.setPrefSize(width, height);
r.setMaxSize(width, height);
r.setStyle("-fx-background-color:" + bg + ";");
return r;
}
}

@ -3,6 +3,7 @@ package atlantafx.sampler.page.components;
import atlantafx.base.theme.Styles;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.Page;
import atlantafx.sampler.page.SampleBlock;
import javafx.geometry.Orientation;
import javafx.scene.control.Label;
@ -16,89 +17,89 @@ import static javafx.geometry.Pos.CENTER;
public final class SeparatorPage extends AbstractPage {
public static final String NAME = "Separator";
private static final int BRICK_SIZE = 100;
private static final int SPACING = 50;
private static final int PANE_SIZE = 100;
@Override
public String getName() { return NAME; }
public SeparatorPage() {
super();
createView();
setUserContent(new FlowPane(
Page.PAGE_HGAP, Page.PAGE_VGAP,
orientationSample(),
sizeSample()
));
}
private void createView() {
userContent.getChildren().setAll(
orientationSamples(),
sizeSamples()
private SampleBlock orientationSample() {
var hBox = new HBox(
createPane("Left", VERTICAL),
new Separator(VERTICAL),
createPane("Right", VERTICAL)
);
}
private FlowPane orientationSamples() {
var hBox = new HBox(brick("Left", VERTICAL), new Separator(VERTICAL), brick("Right", VERTICAL));
hBox.setAlignment(CENTER);
var hBlock = new SampleBlock("Vertical", hBox);
var vBox = new VBox(brick("Top", HORIZONTAL), new Separator(HORIZONTAL), brick("Bottom", HORIZONTAL));
vBox.setAlignment(CENTER);
var vBlock = new SampleBlock("Horizontal", vBox);
var root = new FlowPane(20, 20);
root.getChildren().setAll(
hBlock.getRoot(),
vBlock.getRoot()
var vBox = new VBox(
createPane("Top", HORIZONTAL),
new Separator(HORIZONTAL),
createPane("Bottom", HORIZONTAL)
);
vBox.setAlignment(CENTER);
return root;
return new SampleBlock("Orientation", new HBox(SPACING, hBox, vBox));
}
private FlowPane sizeSamples() {
private SampleBlock sizeSample() {
var smallSep = new Separator(VERTICAL);
smallSep.getStyleClass().add(Styles.SMALL);
var smallBox = new HBox(brick("Left", VERTICAL), smallSep, brick("Right", VERTICAL));
var smallBox = new HBox(
createPane("Left", VERTICAL),
smallSep,
createPane("Right", VERTICAL)
);
smallBox.setAlignment(CENTER);
var smallBlock = new SampleBlock("Small", smallBox);
var mediumSep = new Separator(VERTICAL);
mediumSep.getStyleClass().add(Styles.MEDIUM);
var mediumBox = new HBox(brick("Left", VERTICAL), mediumSep, brick("Right", VERTICAL));
var mediumBox = new HBox(
createPane("Left", VERTICAL),
mediumSep,
createPane("Right", VERTICAL)
);
mediumBox.setAlignment(CENTER);
var mediumBlock = new SampleBlock("Medium", mediumBox);
var largeSep = new Separator(VERTICAL);
largeSep.getStyleClass().add(Styles.LARGE);
var largeBox = new HBox(brick("Left", VERTICAL), largeSep, brick("Right", VERTICAL));
largeBox.setAlignment(CENTER);
var largeBlock = new SampleBlock("Large", largeBox);
var root = new FlowPane(20, 20);
root.getChildren().setAll(
smallBlock.getRoot(),
mediumBlock.getRoot(),
largeBlock.getRoot()
var largeBox = new HBox(
createPane("Left", VERTICAL),
largeSep,
createPane("Right", VERTICAL)
);
largeBox.setAlignment(CENTER);
return root;
return new SampleBlock("Size", new HBox(SPACING, smallBox, mediumBox, largeBox));
}
private Pane brick(String text, Orientation orientation) {
var root = new StackPane();
root.getChildren().setAll(new Label(text));
root.getStyleClass().add("bordered");
private Pane createPane(String text, Orientation orientation) {
var pane = new StackPane();
pane.getChildren().setAll(new Label(text));
pane.getStyleClass().add("bordered");
if (orientation == HORIZONTAL) {
root.setMinHeight(BRICK_SIZE);
root.setPrefHeight(BRICK_SIZE);
root.setMaxHeight(BRICK_SIZE);
root.setMinWidth(BRICK_SIZE);
pane.setMinHeight(PANE_SIZE);
pane.setPrefHeight(PANE_SIZE);
pane.setMaxHeight(PANE_SIZE);
pane.setMinWidth(PANE_SIZE);
}
if (orientation == VERTICAL) {
root.setMinWidth(BRICK_SIZE);
root.setPrefWidth(BRICK_SIZE);
root.setMaxWidth(BRICK_SIZE);
root.setMinHeight(BRICK_SIZE);
pane.setMinWidth(PANE_SIZE);
pane.setPrefWidth(PANE_SIZE);
pane.setMaxWidth(PANE_SIZE);
pane.setMinHeight(PANE_SIZE);
}
return root;
return pane;
}
}

@ -2,10 +2,13 @@
package atlantafx.sampler.page.components;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.Page;
import atlantafx.sampler.page.SampleBlock;
import javafx.scene.control.Slider;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import static javafx.geometry.Orientation.HORIZONTAL;
import static javafx.geometry.Orientation.VERTICAL;
@ -13,52 +16,52 @@ import static javafx.geometry.Orientation.VERTICAL;
public class SliderPage extends AbstractPage {
public static final String NAME = "Slider";
private static final int SLIDER_SIZE = 200;
private static final int SPACING = 40;
@Override
public String getName() { return NAME; }
public SliderPage() {
super();
createView();
setUserContent(new FlowPane(
Page.PAGE_HGAP, Page.PAGE_VGAP,
horizontalSample(),
verticalSample(),
disabledSample()
));
}
private void createView() {
userContent.getChildren().addAll(row1(), row2());
}
private Pane row1() {
private SampleBlock horizontalSample() {
var slider = new Slider(1, 5, 3);
slider.setOrientation(HORIZONTAL);
var tickSlider = tickSlider();
tickSlider.setMinWidth(200);
tickSlider.setMaxWidth(200);
var tickSlider = createTickSlider();
tickSlider.setMinWidth(SLIDER_SIZE);
tickSlider.setMaxWidth(SLIDER_SIZE);
var hBlock = new SampleBlock("Horizontal", new HBox(20, slider, tickSlider));
return new HBox(20, hBlock.getRoot());
return new SampleBlock("Horizontal", new VBox(SPACING, slider, tickSlider));
}
private Pane row2() {
private Pane verticalSample() {
var slider = new Slider(1, 5, 3);
slider.setOrientation(VERTICAL);
var tickSlider = tickSlider();
var tickSlider = createTickSlider();
tickSlider.setOrientation(VERTICAL);
tickSlider.setMinHeight(200);
tickSlider.setMaxHeight(200);
tickSlider.setMinHeight(SLIDER_SIZE);
tickSlider.setMaxHeight(SLIDER_SIZE);
var vBlock = new SampleBlock("Vertical", new HBox(20, slider, tickSlider));
var disabledSlider = tickSlider();
disabledSlider.setDisable(true);
var disabledBlock = new SampleBlock("Disabled", new HBox(20, disabledSlider));
return new HBox(40, vBlock.getRoot(), disabledBlock.getRoot());
return new SampleBlock("Vertical", new HBox(SPACING, slider, tickSlider));
}
private Slider tickSlider() {
private Pane disabledSample() {
var disabledSlider = createTickSlider();
disabledSlider.setDisable(true);
return new SampleBlock("Disabled", new HBox(disabledSlider));
}
private Slider createTickSlider() {
var slider = new Slider(0, 5, 3);
slider.setShowTickLabels(true);
slider.setShowTickMarks(true);
@ -66,7 +69,6 @@ public class SliderPage extends AbstractPage {
slider.setBlockIncrement(1);
slider.setMinorTickCount(5);
slider.setSnapToTicks(true);
return slider;
}
}

@ -3,6 +3,7 @@ package atlantafx.sampler.page.components;
import atlantafx.base.util.IntegerStringConverter;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.Page;
import atlantafx.sampler.page.SampleBlock;
import javafx.scene.control.Spinner;
import javafx.scene.layout.FlowPane;
@ -17,82 +18,75 @@ public final class SpinnerPage extends AbstractPage {
public SpinnerPage() {
super();
createView();
setUserContent(new FlowPane(
Page.PAGE_HGAP, Page.PAGE_VGAP,
basicSample(),
arrowsLeftVerticalSample(),
arrowsLeftHorizontalSample(),
arrowsRightHorizontalSample(),
arrowsSplitHorizontalSample(),
arrowsSplitVerticalSample(),
disabledSample()
));
}
private void createView() {
userContent.getChildren().addAll(
basicSamples(),
arrowPositionSamples()
);
private SampleBlock basicSample() {
var spinner = new Spinner<Integer>(1, 10, 1);
IntegerStringConverter.createFor(spinner);
spinner.setPrefWidth(PREF_WIDTH);
spinner.setEditable(true);
return new SampleBlock("Basic", spinner);
}
private FlowPane basicSamples() {
var editableSpin = new Spinner<Integer>(1, 10, 1);
IntegerStringConverter.createFor(editableSpin);
editableSpin.setPrefWidth(PREF_WIDTH);
editableSpin.setEditable(true);
var editableBlock = new SampleBlock("Editable", editableSpin);
var disabledSpin = new Spinner<Integer>(1, 10, 1);
disabledSpin.setPrefWidth(PREF_WIDTH);
disabledSpin.setDisable(true);
var disabledBlock = new SampleBlock("Disabled", disabledSpin);
var root = new FlowPane(20, 20);
root.getChildren().addAll(
editableBlock.getRoot(),
disabledBlock.getRoot()
);
return root;
private SampleBlock disabledSample() {
var spinner = new Spinner<Integer>(1, 10, 1);
spinner.setPrefWidth(PREF_WIDTH);
spinner.setDisable(true);
return new SampleBlock("Disabled", spinner);
}
private FlowPane arrowPositionSamples() {
var leftVSpin = new Spinner<Integer>(1, 10, 1);
IntegerStringConverter.createFor(leftVSpin);
leftVSpin.getStyleClass().add(Spinner.STYLE_CLASS_ARROWS_ON_LEFT_VERTICAL);
leftVSpin.setPrefWidth(PREF_WIDTH);
leftVSpin.setEditable(true);
var leftVBlock = new SampleBlock("Arrows on left & vertical", leftVSpin);
private SampleBlock arrowsLeftVerticalSample() {
var spinner = new Spinner<Integer>(1, 10, 1);
IntegerStringConverter.createFor(spinner);
spinner.getStyleClass().add(Spinner.STYLE_CLASS_ARROWS_ON_LEFT_VERTICAL);
spinner.setPrefWidth(PREF_WIDTH);
spinner.setEditable(true);
return new SampleBlock("Left & Vertical", spinner);
}
var leftHSpin = new Spinner<Integer>(1, 10, 1);
IntegerStringConverter.createFor(leftHSpin);
leftHSpin.getStyleClass().add(Spinner.STYLE_CLASS_ARROWS_ON_LEFT_HORIZONTAL);
leftHSpin.setPrefWidth(PREF_WIDTH);
leftHSpin.setEditable(true);
var leftHBlock = new SampleBlock("Arrows on left & horizontal", leftHSpin);
private SampleBlock arrowsLeftHorizontalSample() {
var spinner = new Spinner<Integer>(1, 10, 1);
IntegerStringConverter.createFor(spinner);
spinner.getStyleClass().add(Spinner.STYLE_CLASS_ARROWS_ON_LEFT_HORIZONTAL);
spinner.setPrefWidth(PREF_WIDTH);
spinner.setEditable(true);
return new SampleBlock("Left & Horizontal", spinner);
}
var rightHSpin = new Spinner<Integer>(1, 10, 1);
IntegerStringConverter.createFor(rightHSpin);
rightHSpin.getStyleClass().add(Spinner.STYLE_CLASS_ARROWS_ON_RIGHT_HORIZONTAL);
rightHSpin.setPrefWidth(PREF_WIDTH);
rightHSpin.setEditable(true);
var rightHBlock = new SampleBlock("Arrows on right & horizontal", rightHSpin);
private SampleBlock arrowsRightHorizontalSample() {
var spinner = new Spinner<Integer>(1, 10, 1);
IntegerStringConverter.createFor(spinner);
spinner.getStyleClass().add(Spinner.STYLE_CLASS_ARROWS_ON_RIGHT_HORIZONTAL);
spinner.setPrefWidth(PREF_WIDTH);
spinner.setEditable(true);
return new SampleBlock("Right & Horizontal", spinner);
}
var splitHSpin = new Spinner<Integer>(1, 10, 1);
IntegerStringConverter.createFor(splitHSpin);
splitHSpin.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
splitHSpin.setPrefWidth(PREF_WIDTH);
splitHSpin.setEditable(true);
var splitHBlock = new SampleBlock("Split arrows & horizontal", splitHSpin);
private SampleBlock arrowsSplitHorizontalSample() {
var spinner = new Spinner<Integer>(1, 10, 1);
IntegerStringConverter.createFor(spinner);
spinner.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
spinner.setPrefWidth(PREF_WIDTH);
spinner.setEditable(true);
return new SampleBlock("Split & Horizontal", spinner);
}
var splitVSpin = new Spinner<Integer>(1, 10, 1);
IntegerStringConverter.createFor(splitVSpin);
splitVSpin.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_VERTICAL);
splitVSpin.setEditable(true);
splitVSpin.setPrefWidth(40);
var splitVBlock = new SampleBlock("Split arrows & vertical", splitVSpin);
var root = new FlowPane(20, 20);
root.getChildren().addAll(
leftVBlock.getRoot(),
leftHBlock.getRoot(),
rightHBlock.getRoot(),
splitHBlock.getRoot(),
splitVBlock.getRoot()
);
return root;
private SampleBlock arrowsSplitVerticalSample() {
var spinner = new Spinner<Integer>(1, 10, 1);
IntegerStringConverter.createFor(spinner);
spinner.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_VERTICAL);
spinner.setEditable(true);
spinner.setPrefWidth(40);
return new SampleBlock("Split & Vertical", spinner);
}
}

@ -2,6 +2,7 @@
package atlantafx.sampler.page.components;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.Page;
import atlantafx.sampler.page.SampleBlock;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
@ -21,51 +22,46 @@ public class SplitPanePage extends AbstractPage {
public SplitPanePage() {
super();
createView();
}
private void createView() {
userContent.getChildren().setAll(new FlowPane(20, 20,
hSplitBlock().getRoot(),
vSplitBlock().getRoot(),
disabledSplitBlock().getRoot(),
gridSplitBlock().getRoot()
setUserContent(new FlowPane(
Page.PAGE_VGAP, Page.PAGE_HGAP,
hSplitSample(),
vSplitSample(),
disabledSample(),
gridSample()
));
}
private SampleBlock hSplitBlock() {
private SampleBlock hSplitSample() {
var splitPane = new SplitPane();
splitPane.setOrientation(Orientation.HORIZONTAL);
splitPane.setDividerPositions(0.5);
splitPane.getItems().setAll(hBrick("Left"), hBrick("Right"));
splitPane.getItems().setAll(createBox("Left"), createBox("Right"));
splitPane.setMinSize(200, 100);
splitPane.setMaxSize(200, 100);
return new SampleBlock("Horizontal", splitPane);
}
private SampleBlock vSplitBlock() {
private SampleBlock vSplitSample() {
var splitPane = new SplitPane();
splitPane.setOrientation(Orientation.VERTICAL);
splitPane.setDividerPositions(0.5);
splitPane.getItems().setAll(vBrick("Top"), hBrick("Bottom"));
splitPane.getItems().setAll(createBox("Top"), createBox("Bottom"));
splitPane.setMinSize(100, 200);
splitPane.setMaxSize(100, 200);
return new SampleBlock("Vertical", splitPane);
}
private SampleBlock gridSplitBlock() {
private SampleBlock gridSample() {
var topSplitPane = new SplitPane();
topSplitPane.setOrientation(Orientation.HORIZONTAL);
topSplitPane.setDividerPositions(0.5);
topSplitPane.getItems().setAll(vBrick("Quarter 4"), hBrick("Quarter 1"));
topSplitPane.getItems().setAll(createBox("Quarter 4"), createBox("Quarter 1"));
VBox.setVgrow(topSplitPane, Priority.ALWAYS);
var bottomSplitPane = new SplitPane();
bottomSplitPane.setOrientation(Orientation.HORIZONTAL);
bottomSplitPane.setDividerPositions(0.5);
bottomSplitPane.getItems().setAll(vBrick("Quarter 3"), hBrick("Quarter 2"));
bottomSplitPane.getItems().setAll(createBox("Quarter 3"), createBox("Quarter 2"));
VBox.setVgrow(bottomSplitPane, Priority.ALWAYS);
var doubleSplitPane = new SplitPane();
@ -81,23 +77,17 @@ public class SplitPanePage extends AbstractPage {
return new SampleBlock("Nested", doubleSplitPane);
}
private SampleBlock disabledSplitBlock() {
var block = hSplitBlock();
block.setText("Disabled");
private SampleBlock disabledSample() {
var block = hSplitSample();
block.setTitle("Disabled");
block.getContent().setDisable(true);
return block;
}
private HBox hBrick(String text) {
private HBox createBox(String text) {
var brick = new HBox(new Text(text));
brick.setAlignment(Pos.CENTER);
return brick;
}
private VBox vBrick(String text) {
var brick = new VBox(new Text(text));
brick.setAlignment(Pos.CENTER);
return brick;
}
}

@ -1,10 +1,11 @@
/* SPDX-License-Identifier: MIT */
package atlantafx.sampler.page.components;
import atlantafx.base.theme.Styles;
import atlantafx.base.controls.ToggleSwitch;
import atlantafx.base.controls.Spacer;
import atlantafx.base.controls.ToggleSwitch;
import atlantafx.base.theme.Styles;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.SampleBlock;
import javafx.application.Platform;
import javafx.collections.ListChangeListener;
import javafx.geometry.Pos;
@ -14,8 +15,8 @@ import javafx.scene.layout.*;
import org.kordamp.ikonli.feather.Feather;
import org.kordamp.ikonli.javafx.FontIcon;
import static atlantafx.base.theme.Styles.BUTTON_ICON;
import static atlantafx.base.theme.Styles.ACCENT;
import static atlantafx.base.theme.Styles.BUTTON_ICON;
import static javafx.scene.control.TabPane.TabClosingPolicy.ALL_TABS;
import static javafx.scene.control.TabPane.TabClosingPolicy.UNAVAILABLE;
@ -36,7 +37,7 @@ public class TabPanePage extends AbstractPage {
}
private void createView() {
var tabs = tabPane();
var tabs = createTabPane();
var tabsLayer = new BorderPane();
tabsLayer.setTop(tabs);
tabs.getTabs().addListener((ListChangeListener<Tab>) c -> updateTabsWidth(tabsLayer, tabs, fullWidth));
@ -52,7 +53,7 @@ public class TabPanePage extends AbstractPage {
root.getChildren().addAll(tabsLayer, controllerLayer);
VBox.setVgrow(root, Priority.ALWAYS);
userContent.getChildren().setAll(root);
setUserContent(new SampleBlock("Playground", root));
}
private TitledPane createController(BorderPane borderPane, TabPane tabs) {
@ -76,7 +77,7 @@ public class TabPanePage extends AbstractPage {
var appendBtn = new Button("", new FontIcon(Feather.PLUS));
appendBtn.getStyleClass().addAll(BUTTON_ICON, ACCENT);
appendBtn.setOnAction(e -> tabs.getTabs().add(randomTab()));
appendBtn.setOnAction(e -> tabs.getTabs().add(createRandomTab()));
var buttonsPane = new BorderPane();
buttonsPane.setMinSize(120, 120);
@ -112,6 +113,16 @@ public class TabPanePage extends AbstractPage {
if (val != null) { Styles.toggleStyleClass(tabs, TabPane.STYLE_CLASS_FLOATING); }
});
var animatedToggle = new ToggleSwitch();
animatedToggle.setSelected(true);
animatedToggle.selectedProperty().addListener((obs, old, val) -> {
if (val != null && val) {
tabs.setStyle("");
} else {
tabs.setStyle("-fx-open-tab-animation:none;-fx-close-tab-animation:none;");
}
});
var fullWidthToggle = new ToggleSwitch();
fullWidthToggle.selectedProperty().addListener((obs, old, val) -> {
if (val != null) {
@ -129,17 +140,20 @@ public class TabPanePage extends AbstractPage {
togglesGrid.setHgap(10);
togglesGrid.setVgap(10);
togglesGrid.add(gridLabel("Closeable"), 0, 0);
togglesGrid.add(createGridLabel("Closeable"), 0, 0);
togglesGrid.add(closeableToggle, 1, 0);
togglesGrid.add(gridLabel("Floating"), 0, 1);
togglesGrid.add(createGridLabel("Floating"), 0, 1);
togglesGrid.add(floatingToggle, 1, 1);
togglesGrid.add(gridLabel("Full width"), 0, 2);
togglesGrid.add(fullWidthToggle, 1, 2);
togglesGrid.add(createGridLabel("Animated"), 0, 2);
togglesGrid.add(animatedToggle, 1, 2);
togglesGrid.add(gridLabel("Disable"), 0, 3);
togglesGrid.add(disableToggle, 1, 3);
togglesGrid.add(createGridLabel("Full width"), 0, 3);
togglesGrid.add(fullWidthToggle, 1, 3);
togglesGrid.add(createGridLabel("Disable"), 0, 4);
togglesGrid.add(disableToggle, 1, 4);
// == LAYOUT ==
@ -151,11 +165,7 @@ public class TabPanePage extends AbstractPage {
);
controls.setAlignment(Pos.CENTER);
var content = new VBox(20);
content.getChildren().setAll(controls);
content.setAlignment(Pos.CENTER);
var root = new TitledPane("Controller", content);
var root = new TitledPane("Controller", controls);
root.setCollapsible(false);
return root;
@ -194,7 +204,7 @@ public class TabPanePage extends AbstractPage {
}
}
private TabPane tabPane() {
private TabPane createTabPane() {
var tabs = new TabPane();
tabs.setTabClosingPolicy(UNAVAILABLE);
tabs.setMinHeight(TAB_MIN_HEIGHT);
@ -203,9 +213,9 @@ public class TabPanePage extends AbstractPage {
// like disabled. To prevent it from closing one can use "black hole"
// event handler. #javafx-bug
tabs.getTabs().addAll(
randomTab(),
randomTab(),
randomTab()
createRandomTab(),
createRandomTab(),
createRandomTab()
);
return tabs;
@ -229,13 +239,13 @@ public class TabPanePage extends AbstractPage {
});
}
private Tab randomTab() {
private Tab createRandomTab() {
var tab = new Tab(FAKER.cat().name());
tab.setGraphic(new FontIcon(randomIcon()));
return tab;
}
private Label gridLabel(String text) {
private Label createGridLabel(String text) {
var label = new Label(text);
label.setAlignment(Pos.CENTER_RIGHT);
label.setMaxWidth(Double.MAX_VALUE);

@ -4,8 +4,10 @@ package atlantafx.sampler.page.components;
import atlantafx.base.controls.CaptionMenuItem;
import atlantafx.base.controls.Spacer;
import atlantafx.base.controls.ToggleSwitch;
import atlantafx.base.theme.Tweaks;
import atlantafx.sampler.fake.domain.Product;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.SampleBlock;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.StringBinding;
import javafx.beans.property.SimpleObjectProperty;
@ -15,9 +17,11 @@ import javafx.geometry.Pos;
import javafx.scene.control.*;
import javafx.scene.control.cell.*;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.util.Callback;
import org.kordamp.ikonli.feather.Feather;
import org.kordamp.ikonli.javafx.FontIcon;
import org.kordamp.ikonli.javafx.FontIconTableCell;
import java.util.List;
@ -26,8 +30,9 @@ import java.util.stream.IntStream;
import static atlantafx.base.theme.Styles.*;
import static atlantafx.base.theme.Tweaks.*;
import static atlantafx.sampler.page.SampleBlock.BLOCK_HGAP;
import static atlantafx.sampler.page.SampleBlock.BLOCK_VGAP;
import static javafx.collections.FXCollections.observableArrayList;
import static javafx.geometry.Orientation.HORIZONTAL;
public class TablePage extends AbstractPage {
@ -43,16 +48,15 @@ public class TablePage extends AbstractPage {
public TablePage() {
super();
createView();
var sample = new SampleBlock("Playground", createPlayground());
sample.setFillHeight(true);
setUserContent(sample);
}
private void createView() {
userContent.getChildren().setAll(
playground()
);
}
private VBox createPlayground() {
// == FOOTER ==
private VBox playground() {
var bordersToggle = new ToggleSwitch("Bordered");
bordersToggle.selectedProperty().addListener((obs, old, val) -> toggleStyleClass(table, BORDERED));
@ -62,29 +66,31 @@ public class TablePage extends AbstractPage {
var stripesToggle = new ToggleSwitch("Striped");
stripesToggle.selectedProperty().addListener((obs, old, val) -> toggleStyleClass(table, STRIPED));
var disableToggle = new ToggleSwitch("Disable");
disableToggle.selectedProperty().addListener((obs, old, val) -> {
if (val != null) { table.setDisable(val); }
});
var edge2edgeToggle = new ToggleSwitch("Edge to edge");
edge2edgeToggle.selectedProperty().addListener(
(obs, old, value) -> toggleStyleClass(table, Tweaks.EDGE_TO_EDGE)
);
var maxValue = 100;
var rowCountChoice = new ComboBox<>(observableArrayList(0, 5, 10, 25, maxValue));
rowCountChoice.setValue(maxValue);
var maxRowCount = 100;
var rowCountChoice = new ComboBox<>(observableArrayList(0, 5, 10, 25, maxRowCount));
rowCountChoice.setValue(maxRowCount);
var rowCountBox = new HBox(10, new Label("rows"), rowCountChoice);
var rowCountBox = new HBox(BLOCK_HGAP, new Label("rows"), rowCountChoice);
rowCountBox.setAlignment(Pos.CENTER_LEFT);
var togglesBox = new HBox(20,
var footer = new HBox(
BLOCK_HGAP,
new Spacer(),
bordersToggle,
denseToggle,
stripesToggle,
disableToggle,
new Spacer(HORIZONTAL),
edge2edgeToggle,
new Spacer(),
rowCountBox
);
togglesBox.setAlignment(Pos.CENTER_LEFT);
footer.setAlignment(Pos.CENTER_LEFT);
// ~
// == TABLE ==
var filteredData = new FilteredList<>(observableArrayList(dataList));
filteredData.predicateProperty().bind(Bindings.createObjectBinding(
@ -94,32 +100,69 @@ public class TablePage extends AbstractPage {
var sortedData = new SortedList<>(filteredData);
table = table();
table = createTable();
table.setItems(sortedData);
sortedData.comparatorProperty().bind(table.comparatorProperty());
VBox.setVgrow(table, Priority.ALWAYS);
// == HEADER ==
var alignGroup = new ToggleGroup();
var alignLeftBtn = new ToggleButton("", new FontIcon(Feather.ALIGN_LEFT));
alignLeftBtn.getStyleClass().add(".left-pill");
alignLeftBtn.setToggleGroup(alignGroup);
alignLeftBtn.setSelected(true);
alignLeftBtn.setOnAction(e -> {
for (TableColumn<?, ?> c : table.getColumns()) {
c.getStyleClass().removeAll(ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT);
}
});
var alignCenterBtn = new ToggleButton("", new FontIcon(Feather.ALIGN_CENTER));
alignCenterBtn.getStyleClass().add(".center-pill");
alignCenterBtn.setToggleGroup(alignGroup);
alignCenterBtn.selectedProperty().addListener((obs, old, val) -> {
for (TableColumn<?, ?> c : table.getColumns()) {
addStyleClass(c, ALIGN_CENTER, ALIGN_LEFT, ALIGN_RIGHT);
}
});
var alignRightBtn = new ToggleButton("", new FontIcon(Feather.ALIGN_RIGHT));
alignRightBtn.getStyleClass().add(".right-pill");
alignRightBtn.setToggleGroup(alignGroup);
alignRightBtn.selectedProperty().addListener((obs, old, val) -> {
for (TableColumn<?, ?> c : table.getColumns()) {
addStyleClass(c, ALIGN_RIGHT, ALIGN_LEFT, ALIGN_CENTER);
}
});
var alignBox = new HBox(alignLeftBtn, alignCenterBtn, alignRightBtn);
var disableToggle = new ToggleSwitch("Disable");
disableToggle.selectedProperty().addListener((obs, old, val) -> {
if (val != null) { table.setDisable(val); }
});
var header = new HBox(
createTablePropertiesMenu(table),
new Spacer(),
alignBox,
new Spacer(),
disableToggle
);
header.setAlignment(Pos.CENTER_LEFT);
// ~
var topBox = new HBox(
new Label("Example:"),
new Spacer(),
settingsMenu(table)
);
topBox.setAlignment(Pos.CENTER_LEFT);
var playground = new VBox(10);
var playground = new VBox(BLOCK_VGAP, header, table, footer);
playground.setMinHeight(100);
playground.getChildren().setAll(
topBox,
table,
togglesBox
);
return playground;
}
@SuppressWarnings("unchecked")
private TableView<Product> table() {
private TableView<Product> createTable() {
var stateCol = new TableColumn<Product, Boolean>("Selected");
stateCol.setCellValueFactory(new PropertyValueFactory<>("state"));
stateCol.setCellFactory(CheckBoxTableCell.forTableColumn(stateCol));
@ -142,21 +185,21 @@ public class TablePage extends AbstractPage {
iconCol.setCellFactory(FontIconTableCell.forTableColumn());
iconCol.setEditable(false);
var brandCol = new TableColumn<Product, String>("Brand ");
var brandCol = new TableColumn<Product, String>("Brand 🖉");
brandCol.setCellValueFactory(new PropertyValueFactory<>("brand"));
brandCol.setCellFactory(ChoiceBoxTableCell.forTableColumn(
generate(() -> FAKER.commerce().brand(), 10).toArray(String[]::new)
));
brandCol.setEditable(true);
var nameCol = new TableColumn<Product, String>("Name ");
var nameCol = new TableColumn<Product, String>("Name 🖉");
nameCol.setCellValueFactory(new PropertyValueFactory<>("name"));
nameCol.setCellFactory(ComboBoxTableCell.forTableColumn(
generate(() -> FAKER.commerce().productName(), 10).toArray(String[]::new)
));
nameCol.setEditable(true);
var priceCol = new TableColumn<Product, String>("Price ");
var priceCol = new TableColumn<Product, String>("Price 🖉");
priceCol.setCellValueFactory(new PropertyValueFactory<>("price"));
priceCol.setCellFactory(TextFieldTableCell.forTableColumn());
priceCol.setEditable(true);
@ -179,7 +222,7 @@ public class TablePage extends AbstractPage {
return table;
}
private MenuButton settingsMenu(TableView<Product> table) {
private MenuButton createTablePropertiesMenu(TableView<Product> table) {
var resizePolicyCaption = new CaptionMenuItem("Resize Policy");
var resizePolicyGroup = new ToggleGroup();
resizePolicyGroup.selectedToggleProperty().addListener((obs, old, val) -> {
@ -227,66 +270,13 @@ public class TablePage extends AbstractPage {
table.getSelectionModel().cellSelectionEnabledProperty().bind(cellSelectionItem.selectedProperty());
cellSelectionItem.setSelected(false);
var edge2edgeItem = new CheckMenuItem("Edge to edge");
edge2edgeItem.selectedProperty().addListener((obs, old, val) -> {
if (!val) {
table.getStyleClass().remove(EDGE_TO_EDGE);
} else {
table.getStyleClass().add(EDGE_TO_EDGE);
}
});
// ~
var alignToggleGroup = new ToggleGroup();
var alignLeftItem = new RadioMenuItem("Left");
alignLeftItem.setToggleGroup(alignToggleGroup);
alignLeftItem.selectedProperty().addListener((obs, old, val) -> {
for (TableColumn<?, ?> c : table.getColumns()) {
addStyleClass(c, ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT);
}
});
var alignCenterItem = new RadioMenuItem("Center");
alignCenterItem.setToggleGroup(alignToggleGroup);
alignCenterItem.selectedProperty().addListener((obs, old, val) -> {
for (TableColumn<?, ?> c : table.getColumns()) {
addStyleClass(c, ALIGN_CENTER, ALIGN_LEFT, ALIGN_RIGHT);
}
});
var alignRightItem = new RadioMenuItem("Right");
alignRightItem.setToggleGroup(alignToggleGroup);
alignRightItem.selectedProperty().addListener((obs, old, val) -> {
for (TableColumn<?, ?> c : table.getColumns()) {
addStyleClass(c, ALIGN_RIGHT, ALIGN_LEFT, ALIGN_CENTER);
}
});
var alignDefaultItem = new MenuItem("Default");
alignDefaultItem.setOnAction(e -> {
for (TableColumn<?, ?> c : table.getColumns()) {
c.getStyleClass().removeAll(ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT);
}
});
var alignMenu = new Menu("Align columns");
alignMenu.getItems().setAll(
alignLeftItem,
alignCenterItem,
alignRightItem,
new SeparatorMenuItem(),
alignDefaultItem
);
// ~
var menuButtonItem = new CheckMenuItem("Show menu button");
table.tableMenuButtonVisibleProperty().bind(menuButtonItem.selectedProperty());
menuButtonItem.setSelected(true);
return new MenuButton("Settings") {{
return new MenuButton("Properties") {{
getItems().setAll(
resizePolicyCaption,
unconstrainedResizeItem,
@ -297,8 +287,6 @@ public class TablePage extends AbstractPage {
new SeparatorMenuItem(),
editCellsItem,
cellSelectionItem,
alignMenu,
edge2edgeItem,
menuButtonItem
);
}};

@ -23,59 +23,63 @@ public class TextAreaPage extends AbstractPage {
public TextAreaPage() {
super();
createView();
setUserContent(new FlowPane(
PAGE_HGAP, PAGE_VGAP,
basicSample(),
promptSample(),
scrollSample(),
readonlySample(),
successSample(),
dangerSample(),
disabledSample()
));
}
private void createView() {
userContent.getChildren().setAll(samples());
private SampleBlock basicSample() {
var textArea = createTextArea("Text");
textArea.setWrapText(true);
return new SampleBlock("Basic", textArea);
}
private FlowPane samples() {
var basicArea = textArea("Text");
basicArea.setWrapText(true);
var basicBlock = new SampleBlock("Basic", basicArea);
private SampleBlock promptSample() {
var textArea = createTextArea(null);
textArea.setPromptText("Prompt text");
return new SampleBlock("Prompt", textArea);
}
var promptArea = textArea(null);
promptArea.setPromptText("Prompt text");
var promptBlock = new SampleBlock("Prompt", promptArea);
var scrollArea = textArea(
private SampleBlock scrollSample() {
var textArea = createTextArea(
Stream.generate(() -> FAKER.lorem().paragraph()).limit(10).collect(Collectors.joining("\n"))
);
scrollArea.setWrapText(false);
var scrollBlock = new SampleBlock("Scrolling", scrollArea);
var readonlyArea = textArea("Text");
readonlyArea.setEditable(false);
var readonlyBlock = new SampleBlock("Readonly", readonlyArea);
var disabledArea = textArea("Text");
disabledArea.setDisable(true);
var disabledBlock = new SampleBlock("Disabled", disabledArea);
var successArea = textArea("Text");
successArea.pseudoClassStateChanged(STATE_SUCCESS, true);
var successBlock = new SampleBlock("Success", successArea);
var dangerArea = textArea("Text");
dangerArea.pseudoClassStateChanged(STATE_DANGER, true);
var dangerBlock = new SampleBlock("Danger", dangerArea);
var flowPane = new FlowPane(20, 20);
flowPane.getChildren().setAll(
basicBlock.getRoot(),
promptBlock.getRoot(),
scrollBlock.getRoot(),
readonlyBlock.getRoot(),
disabledBlock.getRoot(),
successBlock.getRoot(),
dangerBlock.getRoot()
);
return flowPane;
textArea.setWrapText(false);
return new SampleBlock("Scrolling", textArea);
}
private TextArea textArea(String text) {
private SampleBlock readonlySample() {
var textArea = createTextArea("Text");
textArea.setEditable(false);
return new SampleBlock("Readonly", textArea);
}
private SampleBlock successSample() {
var textArea = createTextArea("Text");
textArea.pseudoClassStateChanged(STATE_SUCCESS, true);
return new SampleBlock("Success", textArea);
}
private SampleBlock dangerSample() {
var textArea = createTextArea("Text");
textArea.pseudoClassStateChanged(STATE_DANGER, true);
return new SampleBlock("Danger", textArea);
}
private SampleBlock disabledSample() {
var textArea = createTextArea("Text");
textArea.setDisable(true);
return new SampleBlock("Disabled", textArea);
}
private TextArea createTextArea(String text) {
var textArea = new TextArea(text);
textArea.setMinWidth(CONTROL_WIDTH);
textArea.setMinHeight(CONTROL_HEIGHT);

@ -20,57 +20,63 @@ public class TextFieldPage extends AbstractPage {
public TextFieldPage() {
super();
createView();
setUserContent(new FlowPane(
PAGE_HGAP, PAGE_VGAP,
basicSample(),
promptSample(),
passwordSample(),
readonlySample(),
successSample(),
dangerSample(),
roundedSample(),
disabledSample()
));
}
private void createView() {
userContent.getChildren().setAll(samples());
private SampleBlock basicSample() {
var field = new TextField("Text");
return new SampleBlock("Basic", field);
}
private FlowPane samples() {
var basicField = new TextField("Text");
var basicBlock = new SampleBlock("Basic", basicField);
private SampleBlock passwordSample() {
var field = new PasswordField();
field.setText("qwerty");
return new SampleBlock("Password", field);
}
var passwordField = new PasswordField();
passwordField.setText("qwerty");
var passwordBlock = new SampleBlock("Password", passwordField);
private SampleBlock promptSample() {
var field = new TextField();
field.setPromptText("Prompt text");
return new SampleBlock("Prompt", field);
}
var promptField = new TextField();
promptField.setPromptText("Prompt text");
var promptBlock = new SampleBlock("Prompt", promptField);
private SampleBlock readonlySample() {
var field = new TextField("Text");
field.setEditable(false);
return new SampleBlock("Readonly", field);
}
var readonlyField = new TextField("Text");
readonlyField.setEditable(false);
var readonlyBlock = new SampleBlock("Readonly", readonlyField);
private SampleBlock successSample() {
var field = new TextField("Text");
field.pseudoClassStateChanged(STATE_SUCCESS, true);
return new SampleBlock("Success", field);
}
var disabledField = new TextField("Text");
disabledField.setDisable(true);
var disabledBlock = new SampleBlock("Disabled", disabledField);
private SampleBlock dangerSample() {
var field = new TextField("Text");
field.pseudoClassStateChanged(STATE_DANGER, true);
return new SampleBlock("Danger", field);
}
var successField = new TextField("Text");
successField.pseudoClassStateChanged(STATE_SUCCESS, true);
var successBlock = new SampleBlock("Success", successField);
private SampleBlock roundedSample() {
var field = new TextField("Text");
field.getStyleClass().add(Styles.ROUNDED);
return new SampleBlock("Rounded", field);
}
var dangerField = new TextField("Text");
dangerField.pseudoClassStateChanged(STATE_DANGER, true);
var dangerBlock = new SampleBlock("Danger", dangerField);
var roundedField = new TextField("Text");
roundedField.getStyleClass().add(Styles.ROUNDED);
var roundedBlock = new SampleBlock("Rounded", roundedField);
var flowPane = new FlowPane(20, 20);
flowPane.getChildren().setAll(
basicBlock.getRoot(),
passwordBlock.getRoot(),
promptBlock.getRoot(),
readonlyBlock.getRoot(),
disabledBlock.getRoot(),
successBlock.getRoot(),
dangerBlock.getRoot(),
roundedBlock.getRoot()
);
return flowPane;
private SampleBlock disabledSample() {
var field = new TextField("Text");
field.setDisable(true);
return new SampleBlock("Disabled", field);
}
}

@ -1,9 +1,10 @@
/* SPDX-License-Identifier: MIT */
package atlantafx.sampler.page.components;
import atlantafx.base.controls.ToggleSwitch;
import atlantafx.base.controls.Spacer;
import atlantafx.base.controls.ToggleSwitch;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.Page;
import javafx.geometry.Pos;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
@ -18,6 +19,8 @@ import javafx.scene.text.TextFlow;
import static atlantafx.base.theme.Styles.ELEVATED_2;
import static atlantafx.base.theme.Styles.INTERACTIVE;
import static atlantafx.sampler.page.SampleBlock.BLOCK_HGAP;
import static atlantafx.sampler.page.SampleBlock.BLOCK_VGAP;
public class TitledPanePage extends AbstractPage {
@ -33,13 +36,22 @@ public class TitledPanePage extends AbstractPage {
}
private void createView() {
var samples = new HBox(20, interactivePane(), disabledCard(), untitledCard());
var samples = new HBox(
PAGE_HGAP,
interactivePane(),
disabledPane(),
untitledPane()
);
samples.getChildren().forEach(c -> ((TitledPane) c).setPrefSize(500, 120));
userContent.getChildren().setAll(new VBox(20, playground(), samples));
setUserContent(new VBox(
Page.PAGE_VGAP,
createPlayground(),
samples
));
}
private TitledPane playground() {
private TitledPane createPlayground() {
var playground = new TitledPane();
playground.setText("_Playground");
playground.setMnemonicParsing(true);
@ -79,7 +91,7 @@ public class TitledPanePage extends AbstractPage {
animateToggle.setSelected(true);
playground.animatedProperty().bind(animateToggle.selectedProperty());
var controls = new HBox(20);
var controls = new HBox(BLOCK_HGAP);
controls.setMinHeight(80);
controls.setFillHeight(false);
controls.setAlignment(Pos.CENTER_LEFT);
@ -91,7 +103,7 @@ public class TitledPanePage extends AbstractPage {
animateToggle
);
var content = new VBox(20, textFlow, controls);
var content = new VBox(BLOCK_VGAP, textFlow, controls);
VBox.setVgrow(textFlow, Priority.ALWAYS);
playground.setContent(content);
@ -105,14 +117,14 @@ public class TitledPanePage extends AbstractPage {
return titledPane;
}
private TitledPane disabledCard() {
private TitledPane disabledPane() {
var titledPane = new TitledPane("Disabled", new CheckBox("This checkbox is disabled."));
titledPane.setCollapsible(false);
titledPane.setDisable(true);
return titledPane;
}
private TitledPane untitledCard() {
private TitledPane untitledPane() {
var titledPane = new TitledPane("This pane has no title.", new Text());
titledPane.setCollapsible(false);
return titledPane;

@ -2,6 +2,7 @@
package atlantafx.sampler.page.components;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.Page;
import atlantafx.sampler.page.SampleBlock;
import javafx.scene.control.Button;
import javafx.scene.control.ContentDisplay;
@ -12,6 +13,7 @@ import org.kordamp.ikonli.feather.Feather;
import org.kordamp.ikonli.javafx.FontIcon;
import static atlantafx.base.theme.Styles.*;
import static atlantafx.sampler.page.SampleBlock.BLOCK_HGAP;
import static atlantafx.sampler.util.Controls.toggleButton;
import static javafx.scene.layout.GridPane.REMAINING;
@ -29,15 +31,15 @@ public class ToggleButtonPage extends AbstractPage {
private void createView() {
var grid = new GridPane();
grid.setHgap(40);
grid.setVgap(40);
grid.setHgap(Page.PAGE_HGAP);
grid.setVgap(Page.PAGE_VGAP);
grid.add(basicSample().getRoot(), 0, 0, REMAINING, 1);
grid.add(wizardSample().getRoot(), 0, 1);
grid.add(iconOnlySample().getRoot(), 1, 1);
grid.add(disabledSample().getRoot(), 0, 2);
grid.add(basicSample(), 0, 0, REMAINING, 1);
grid.add(wizardSample(), 0, 1);
grid.add(iconOnlySample(), 1, 1);
grid.add(disabledSample(), 0, 2);
userContent.getChildren().addAll(grid);
setUserContent(grid);
}
private SampleBlock basicSample() {
@ -45,15 +47,12 @@ public class ToggleButtonPage extends AbstractPage {
var leftPill = toggleButton("._left-pill", null, threeButtonGroup, true, LEFT_PILL);
leftPill.setMnemonicParsing(true);
leftPill.setOnAction(PRINT_SOURCE);
var centerPill = toggleButton("._center-pill", null, threeButtonGroup, false, CENTER_PILL);
centerPill.setMnemonicParsing(true);
centerPill.setOnAction(PRINT_SOURCE);
var rightPill = toggleButton("._right-pill", null, threeButtonGroup, false, RIGHT_PILL);
rightPill.setMnemonicParsing(true);
rightPill.setOnAction(PRINT_SOURCE);
var threeButtonBox = new HBox(leftPill, centerPill, rightPill);
@ -63,18 +62,14 @@ public class ToggleButtonPage extends AbstractPage {
toggleButton(".right-pill", null, twoButtonGroup, false, RIGHT_PILL)
);
var content = new HBox(10);
content.getChildren().setAll(threeButtonBox, twoButtonBox);
return new SampleBlock("Basic", content);
return new SampleBlock("Basic", new HBox(BLOCK_HGAP, threeButtonBox, twoButtonBox));
}
private SampleBlock wizardSample() {
var group = new ToggleGroup();
var prevBtn = new Button("\f");
var prevBtn = new Button("\f", new FontIcon(Feather.CHEVRON_LEFT));
prevBtn.getStyleClass().addAll(BUTTON_ICON, LEFT_PILL);
prevBtn.setGraphic(new FontIcon(Feather.CHEVRON_LEFT));
prevBtn.setOnAction(e -> {
int selected = group.getToggles().indexOf(group.getSelectedToggle());
if (selected > 0) {
@ -82,9 +77,8 @@ public class ToggleButtonPage extends AbstractPage {
}
});
var nextBtn = new Button("\f");
var nextBtn = new Button("\f", new FontIcon(Feather.CHEVRON_RIGHT));
nextBtn.getStyleClass().addAll(BUTTON_ICON, RIGHT_PILL);
nextBtn.setGraphic(new FontIcon(Feather.CHEVRON_RIGHT));
nextBtn.setContentDisplay(ContentDisplay.RIGHT);
nextBtn.setOnAction(e -> {
int selected = group.getToggles().indexOf(group.getSelectedToggle());

@ -3,9 +3,9 @@ package atlantafx.sampler.page.components;
import atlantafx.base.controls.ToggleSwitch;
import atlantafx.sampler.page.AbstractPage;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import atlantafx.sampler.page.Page;
import atlantafx.sampler.page.SampleBlock;
import javafx.scene.layout.FlowPane;
public class ToggleSwitchPage extends AbstractPage {
@ -16,17 +16,16 @@ public class ToggleSwitchPage extends AbstractPage {
public ToggleSwitchPage() {
super();
createView();
setUserContent(new FlowPane(
Page.PAGE_HGAP, Page.PAGE_VGAP,
basicSample()
));
}
private void createView() {
private SampleBlock basicSample() {
var toggle = new ToggleSwitch();
toggle.selectedProperty().addListener((obs, old, val) -> toggle.setText(val ? "Disable" : "Enable"));
toggle.setSelected(true);
var box = new VBox(20, new Label("Nothing fancy here."), toggle);
box.setAlignment(Pos.CENTER);
userContent.getChildren().setAll(box);
return new SampleBlock("Basic", toggle);
}
}

@ -6,6 +6,7 @@ import atlantafx.base.controls.ToggleSwitch;
import atlantafx.base.theme.Styles;
import atlantafx.sampler.fake.SampleMenuBar;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.SampleBlock;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.geometry.Orientation;
@ -22,6 +23,7 @@ import java.util.ArrayList;
import java.util.stream.IntStream;
import static atlantafx.base.theme.Styles.*;
import static atlantafx.sampler.page.SampleBlock.BLOCK_VGAP;
import static atlantafx.sampler.util.Controls.*;
import static javafx.geometry.Orientation.HORIZONTAL;
import static javafx.geometry.Orientation.VERTICAL;
@ -41,7 +43,7 @@ public class ToolBarPage extends AbstractPage {
}
private void createView() {
var toolbar = new ToolBar(toolBarButtons(HORIZONTAL));
var toolbar = new ToolBar(createButtons(HORIZONTAL));
var toolbarLayer = new BorderPane();
toolbarLayer.setTop(new TopBar(toolbar));
@ -56,7 +58,7 @@ public class ToolBarPage extends AbstractPage {
root.getChildren().addAll(toolbarLayer, controllerLayer);
VBox.setVgrow(root, Priority.ALWAYS);
userContent.getChildren().setAll(root);
setUserContent(new SampleBlock("Playground", root));
}
private TitledPane createController(BorderPane borderPane, ToolBar toolbar) {
@ -130,10 +132,10 @@ public class ToolBarPage extends AbstractPage {
togglesGrid.setHgap(10);
togglesGrid.setVgap(10);
togglesGrid.add(gridLabel("Show menu bar"), 0, 0);
togglesGrid.add(createLabel("Show menu bar"), 0, 0);
togglesGrid.add(menuBarToggle, 1, 0);
togglesGrid.add(gridLabel("Disable"), 0, 1);
togglesGrid.add(createLabel("Disable"), 0, 1);
togglesGrid.add(disableToggle, 1, 1);
// == LAYOUT ==
@ -141,7 +143,7 @@ public class ToolBarPage extends AbstractPage {
var controls = new HBox(40, new Spacer(), buttonsPane, togglesGrid, new Spacer());
controls.setAlignment(Pos.CENTER);
var content = new VBox(10);
var content = new VBox(BLOCK_VGAP);
content.getChildren().setAll(controls);
content.setAlignment(Pos.CENTER);
@ -171,32 +173,32 @@ public class ToolBarPage extends AbstractPage {
case TOP -> {
toolbar.setOrientation(HORIZONTAL);
Styles.addStyleClass(toolbar, TOP, RIGHT, BOTTOM, LEFT);
toolbar.getItems().setAll(toolBarButtons(HORIZONTAL));
toolbar.getItems().setAll(createButtons(HORIZONTAL));
topBar.setToolBar(toolbar);
}
case RIGHT -> {
toolbar.setOrientation(VERTICAL);
Styles.addStyleClass(toolbar, RIGHT, TOP, BOTTOM, LEFT);
toolbar.getItems().setAll(toolBarButtons(VERTICAL));
toolbar.getItems().setAll(createButtons(VERTICAL));
borderPane.setRight(toolbar);
}
case BOTTOM -> {
toolbar.setOrientation(HORIZONTAL);
Styles.addStyleClass(toolbar, BOTTOM, TOP, RIGHT, LEFT);
toolbar.getItems().setAll(toolBarButtons(HORIZONTAL));
toolbar.getItems().setAll(createButtons(HORIZONTAL));
borderPane.setBottom(toolbar);
}
case LEFT -> {
toolbar.setOrientation(VERTICAL);
Styles.addStyleClass(toolbar, LEFT, RIGHT, TOP, BOTTOM);
toolbar.getItems().setAll(toolBarButtons(VERTICAL));
toolbar.getItems().setAll(createButtons(VERTICAL));
borderPane.setLeft(toolbar);
}
}
});
}
public Node[] toolBarButtons(Orientation orientation) {
public Node[] createButtons(Orientation orientation) {
var result = new ArrayList<Node>();
result.add(iconButton(Feather.FILE, false));
result.add(iconButton(Feather.FOLDER, false));
@ -209,18 +211,18 @@ public class ToolBarPage extends AbstractPage {
result.add(new Separator());
var group = new ToggleGroup();
result.add(toggleButton("", Feather.BOLD, null, true, BUTTON_ICON, LEFT_PILL));
result.add(toggleButton("", Feather.ITALIC, null, false, BUTTON_ICON, CENTER_PILL));
result.add(toggleButton("", Feather.UNDERLINE, null, false, BUTTON_ICON, RIGHT_PILL));
result.add(new Spacer(5));
var fontCombo = new ComboBox<>(FXCollections.observableArrayList(Font.getFamilies()));
fontCombo.setPrefWidth(150);
fontCombo.getSelectionModel().selectFirst();
result.add(fontCombo);
var settingsMenu = new MenuButton("Settings", new FontIcon(Feather.SETTINGS), menuItems(5));
var settingsMenu = new MenuButton("Settings", new FontIcon(Feather.SETTINGS), createItems(5));
settingsMenu.getStyleClass().add(FLAT);
result.add(new Spacer());
result.add(settingsMenu);
@ -236,14 +238,14 @@ public class ToolBarPage extends AbstractPage {
return result.toArray(Node[]::new);
}
private Label gridLabel(String text) {
private Label createLabel(String text) {
var label = new Label(text);
label.setAlignment(Pos.CENTER_RIGHT);
label.setMaxWidth(Double.MAX_VALUE);
return label;
}
public static MenuItem[] menuItems(int count) {
public static MenuItem[] createItems(int count) {
return IntStream.range(0, count).mapToObj(i -> new MenuItem(FAKER.babylon5().character())).toArray(MenuItem[]::new);
}

@ -2,15 +2,20 @@
package atlantafx.sampler.page.components;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.Page;
import atlantafx.sampler.page.SampleBlock;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.control.Separator;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.VBox;
import javafx.stage.PopupWindow.AnchorLocation;
import javafx.util.Duration;
import static atlantafx.sampler.page.SampleBlock.BLOCK_HGAP;
import static atlantafx.sampler.page.SampleBlock.BLOCK_VGAP;
import static javafx.geometry.Orientation.VERTICAL;
public class TooltipPage extends AbstractPage {
@ -22,59 +27,63 @@ public class TooltipPage extends AbstractPage {
public TooltipPage() {
super();
createView();
setUserContent(new VBox(Page.PAGE_VGAP,
expandingHBox(
basicSample(),
textWrapSample(),
indefiniteSample()
),
positionSample()
));
}
private void createView() {
userContent.getChildren().setAll(
basicSamples(),
positionSamples().getRoot()
);
private SampleBlock basicSample() {
var tooltip = new Tooltip(FAKER.harryPotter().spell());
tooltip.setHideDelay(Duration.seconds(3));
var label = createLabel("Hover me");
label.setTooltip(tooltip);
return new SampleBlock("Basic", label);
}
private FlowPane basicSamples() {
var basicTooltip = new Tooltip(FAKER.harryPotter().spell());
basicTooltip.setHideDelay(Duration.seconds(3));
var basicLabel = label("Hover me");
basicLabel.setTooltip(basicTooltip);
var basicBlock = new SampleBlock("Basic", basicLabel);
private SampleBlock textWrapSample() {
var tooltip = new Tooltip(FAKER.lorem().paragraph(5));
tooltip.setHideDelay(Duration.seconds(3));
tooltip.setPrefWidth(200);
tooltip.setWrapText(true);
var textWrapTooltip = new Tooltip(FAKER.lorem().paragraph(5));
textWrapTooltip.setHideDelay(Duration.seconds(3));
textWrapTooltip.setPrefWidth(200);
textWrapTooltip.setWrapText(true);
var textWrapLabel = label("Hover me");
textWrapLabel.setTooltip(textWrapTooltip);
var textWrapBlock = new SampleBlock("Text wrapping", textWrapLabel);
var label = createLabel("Hover me");
label.setTooltip(tooltip);
var indefiniteTooltip = new Tooltip(FAKER.harryPotter().spell());
indefiniteTooltip.setHideDelay(Duration.INDEFINITE);
var indefiniteLabel = label("Hover me");
indefiniteLabel.setTooltip(basicTooltip);
var indefiniteBlock = new SampleBlock("Indefinite", indefiniteLabel);
return new FlowPane(20, 10,
basicBlock.getRoot(),
textWrapBlock.getRoot(),
indefiniteBlock.getRoot()
);
return new SampleBlock("Text Wrap", label);
}
private SampleBlock positionSamples() {
var topLeftLabel = label("Top Left");
topLeftLabel.setTooltip(tooltip("Top Left", AnchorLocation.WINDOW_BOTTOM_RIGHT));
private SampleBlock indefiniteSample() {
var tooltip = new Tooltip(FAKER.harryPotter().spell());
tooltip.setHideDelay(Duration.INDEFINITE);
var topRightLabel = label("Top Right");
topRightLabel.setTooltip(tooltip("Top Right", AnchorLocation.WINDOW_BOTTOM_LEFT));
var label = createLabel("Hover me");
label.setTooltip(tooltip);
var bottomLeftLabel = label("Bottom Left");
bottomLeftLabel.setTooltip(tooltip("Bottom Left", AnchorLocation.WINDOW_TOP_RIGHT));
return new SampleBlock("Indefinite", label);
}
var bottomRightLabel = label("Bottom Right");
bottomRightLabel.setTooltip(tooltip("Bottom Right", AnchorLocation.WINDOW_TOP_LEFT));
private SampleBlock positionSample() {
var topLeftLabel = createLabel("Top Left");
topLeftLabel.setTooltip(createTooltip("Top Left", AnchorLocation.WINDOW_BOTTOM_RIGHT));
var flowPane = new FlowPane(20, 10);
flowPane.getChildren().setAll(
var topRightLabel = createLabel("Top Right");
topRightLabel.setTooltip(createTooltip("Top Right", AnchorLocation.WINDOW_BOTTOM_LEFT));
var bottomLeftLabel = createLabel("Bottom Left");
bottomLeftLabel.setTooltip(createTooltip("Bottom Left", AnchorLocation.WINDOW_TOP_RIGHT));
var bottomRightLabel = createLabel("Bottom Right");
bottomRightLabel.setTooltip(createTooltip("Bottom Right", AnchorLocation.WINDOW_TOP_LEFT));
var flowPane = new FlowPane(
BLOCK_HGAP, BLOCK_VGAP,
topLeftLabel,
new Separator(VERTICAL),
topRightLabel,
@ -87,17 +96,19 @@ public class TooltipPage extends AbstractPage {
return new SampleBlock("Position", flowPane);
}
private Label label(String text) {
private Label createLabel(String text) {
Label label = new Label(text);
label.setMinWidth(50);
label.setMinHeight(50);
label.setPadding(new Insets(10));
label.setStyle("-fx-background-color:-color-accent-subtle;");
label.setAlignment(Pos.CENTER_LEFT);
return label;
}
private Tooltip tooltip(String text, AnchorLocation anchorLocation) {
private Tooltip createTooltip(String text, AnchorLocation arrowPos) {
var tooltip = new Tooltip(text);
tooltip.setAnchorLocation(anchorLocation);
tooltip.setAnchorLocation(arrowPos);
return tooltip;
}
}

@ -5,13 +5,16 @@ import atlantafx.base.controls.Spacer;
import atlantafx.base.controls.ToggleSwitch;
import atlantafx.base.theme.Tweaks;
import atlantafx.sampler.page.AbstractPage;
import javafx.geometry.Orientation;
import atlantafx.sampler.page.SampleBlock;
import javafx.geometry.Pos;
import javafx.scene.control.*;
import javafx.scene.control.cell.CheckBoxTreeCell;
import javafx.scene.control.cell.ChoiceBoxTreeCell;
import javafx.scene.control.cell.ComboBoxTreeCell;
import javafx.scene.control.cell.TextFieldTreeCell;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.util.StringConverter;
import org.kordamp.ikonli.feather.Feather;
@ -25,6 +28,8 @@ import java.util.function.Supplier;
import static atlantafx.base.theme.Styles.DENSE;
import static atlantafx.base.theme.Styles.toggleStyleClass;
import static atlantafx.sampler.page.SampleBlock.BLOCK_HGAP;
import static atlantafx.sampler.page.SampleBlock.BLOCK_VGAP;
public class TreePage extends AbstractPage {
@ -33,34 +38,20 @@ public class TreePage extends AbstractPage {
private static final int[] TREE_DICE = { -1, 0, 1 };
@Override
public String getName() {
return NAME;
}
public String getName() { return NAME; }
private VBox playground;
private ComboBox<Example> exampleSelect;
private final BorderPane treeWrapper = new BorderPane();
private final ComboBox<Example> exampleSelect = createExampleSelect();
public TreePage() {
super();
createView();
var sample = new SampleBlock("Playground", createPlayground());
sample.setFillHeight(true);
setUserContent(sample);
}
private void createView() {
exampleSelect = exampleSelect();
playground = playground(exampleSelect);
userContent.getChildren().setAll(playground);
}
@Override
protected void onRendered() {
super.onRendered();
exampleSelect.getSelectionModel().selectFirst();
}
private VBox playground(ComboBox<Example> exampleSelect) {
var playground = new VBox(10);
playground.setMinHeight(100);
private VBox createPlayground() {
var denseToggle = new ToggleSwitch("Dense");
denseToggle.selectedProperty().addListener(
(obs, old, value) -> findDisplayedTree().ifPresent(tv -> toggleStyleClass(tv, DENSE))
@ -82,34 +73,29 @@ public class TreePage extends AbstractPage {
if (val != null) { tv.setDisable(val); }
}));
var controls = new HBox(20,
new Spacer(),
denseToggle,
showRootToggle,
edge2edgeToggle,
disableToggle,
new Spacer()
);
var controls = new HBox(BLOCK_HGAP, denseToggle, showRootToggle, edge2edgeToggle);
controls.setAlignment(Pos.CENTER);
playground.getChildren().setAll(
new Label("Select an example:"),
VBox.setVgrow(treeWrapper, Priority.ALWAYS);
var playground = new VBox(
BLOCK_VGAP,
new HBox(new Label("Select an example:"), new Spacer(), disableToggle),
exampleSelect,
new Spacer(Orientation.VERTICAL), // placeholder for TreeView<?>
treeWrapper,
controls
);
playground.setMinHeight(100);
return playground;
}
private ComboBox<Example> exampleSelect() {
private ComboBox<Example> createExampleSelect() {
var select = new ComboBox<Example>();
select.setMaxWidth(Double.MAX_VALUE);
select.getItems().setAll(Example.values());
select.getSelectionModel().selectedItemProperty().addListener((obs, old, val) -> {
if (val == null) { return; }
if (playground.getChildren().size() != 4) {
throw new RuntimeException("Unexpected container size.");
}
TreeView<String> newTree = createTree(val);
@ -123,10 +109,9 @@ public class TreePage extends AbstractPage {
newTree.setDisable(tv.isDisable());
});
playground.getChildren().set(2, newTree);
treeWrapper.setCenter(newTree);
});
select.setConverter(new StringConverter<>() {
@Override
public String toString(Example example) {
return example == null ? "" : example.getName();
@ -141,12 +126,16 @@ public class TreePage extends AbstractPage {
return select;
}
@Override
protected void onRendered() {
super.onRendered();
exampleSelect.getSelectionModel().selectFirst();
}
private Optional<TreeView<?>> findDisplayedTree() {
if (playground == null) { return Optional.empty(); }
return playground.getChildren().stream()
.filter(c -> c instanceof TreeView<?>)
.findFirst()
.map(c -> (TreeView<?>) c);
return treeWrapper.getChildren().size() > 0 ?
Optional.of((TreeView<?>) treeWrapper.getChildren().get(0)) :
Optional.empty();
}
private TreeView<String> createTree(Example example) {

@ -7,13 +7,17 @@ import atlantafx.base.controls.ToggleSwitch;
import atlantafx.base.theme.Tweaks;
import atlantafx.sampler.fake.domain.Product;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.SampleBlock;
import javafx.beans.property.SimpleStringProperty;
import javafx.geometry.Pos;
import javafx.scene.control.*;
import javafx.scene.control.cell.*;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.util.Callback;
import org.kordamp.ikonli.feather.Feather;
import org.kordamp.ikonli.javafx.FontIcon;
import java.util.List;
import java.util.Objects;
@ -21,6 +25,8 @@ import java.util.stream.IntStream;
import static atlantafx.base.theme.Styles.*;
import static atlantafx.base.theme.Tweaks.*;
import static atlantafx.sampler.page.SampleBlock.BLOCK_HGAP;
import static atlantafx.sampler.page.SampleBlock.BLOCK_VGAP;
public class TreeTablePage extends AbstractPage {
@ -33,16 +39,15 @@ public class TreeTablePage extends AbstractPage {
public TreeTablePage() {
super();
createView();
var sample = new SampleBlock("Playground", createPlayground());
sample.setFillHeight(true);
setUserContent(sample);
}
private void createView() {
userContent.getChildren().setAll(
playground()
);
}
private VBox createPlayground() {
// == FOOTER ==
private VBox playground() {
var bordersToggle = new ToggleSwitch("Bordered");
bordersToggle.selectedProperty().addListener((obs, old, val) -> toggleStyleClass(treeTable, BORDERED));
@ -52,20 +57,15 @@ public class TreeTablePage extends AbstractPage {
var stripesToggle = new ToggleSwitch("Striped");
stripesToggle.selectedProperty().addListener((obs, old, val) -> toggleStyleClass(treeTable, STRIPED));
var disableToggle = new ToggleSwitch("Disable");
disableToggle.selectedProperty().addListener((obs, old, val) -> {
if (val != null) { treeTable.setDisable(val); }
});
var togglesBox = new HBox(20,
bordersToggle,
denseToggle,
stripesToggle,
disableToggle
var edge2edgeToggle = new ToggleSwitch("Edge to edge");
edge2edgeToggle.selectedProperty().addListener(
(obs, old, value) -> toggleStyleClass(treeTable, Tweaks.EDGE_TO_EDGE)
);
togglesBox.setAlignment(Pos.CENTER_LEFT);
// ~
var footer = new HBox(BLOCK_HGAP, bordersToggle, denseToggle, stripesToggle, edge2edgeToggle);
footer.setAlignment(Pos.CENTER);
// == TREE TABLE ==
var rootVal = Product.empty(0);
rootVal.setBrand("Root");
@ -78,35 +78,72 @@ public class TreeTablePage extends AbstractPage {
var group = new TreeItem<>(groupVal);
group.getChildren().setAll(
treeItems(idx * 100, FAKER.random().nextInt(5, 10), brand)
createTreeItems(idx * 100, FAKER.random().nextInt(5, 10), brand)
);
root.getChildren().add(group);
}
treeTable = treeTable();
treeTable = createTreeTable();
treeTable.setRoot(root);
VBox.setVgrow(treeTable, Priority.ALWAYS);
// == HEADER ==
var alignGroup = new ToggleGroup();
var alignLeftBtn = new ToggleButton("", new FontIcon(Feather.ALIGN_LEFT));
alignLeftBtn.getStyleClass().add(".left-pill");
alignLeftBtn.setToggleGroup(alignGroup);
alignLeftBtn.setSelected(true);
alignLeftBtn.setOnAction(e -> {
for (TreeTableColumn<?, ?> c : treeTable.getColumns()) {
c.getStyleClass().removeAll(ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT);
}
});
var alignCenterBtn = new ToggleButton("", new FontIcon(Feather.ALIGN_CENTER));
alignCenterBtn.getStyleClass().add(".center-pill");
alignCenterBtn.setToggleGroup(alignGroup);
alignCenterBtn.selectedProperty().addListener((obs, old, val) -> {
for (TreeTableColumn<?, ?> c : treeTable.getColumns()) {
addStyleClass(c, ALIGN_CENTER, ALIGN_LEFT, ALIGN_RIGHT);
}
});
var alignRightBtn = new ToggleButton("", new FontIcon(Feather.ALIGN_RIGHT));
alignRightBtn.getStyleClass().add(".right-pill");
alignRightBtn.setToggleGroup(alignGroup);
alignRightBtn.selectedProperty().addListener((obs, old, val) -> {
for (TreeTableColumn<?, ?> c : treeTable.getColumns()) {
addStyleClass(c, ALIGN_RIGHT, ALIGN_LEFT, ALIGN_CENTER);
}
});
var alignBox = new HBox(alignLeftBtn, alignCenterBtn, alignRightBtn);
var disableToggle = new ToggleSwitch("Disable");
disableToggle.selectedProperty().addListener((obs, old, val) -> {
if (val != null) { treeTable.setDisable(val); }
});
var header = new HBox(
createPropertiesMenu(treeTable),
new Spacer(),
alignBox,
new Spacer(),
disableToggle
);
header.setAlignment(Pos.CENTER_LEFT);
// ~
var topBox = new HBox(
new Label("Example:"),
new Spacer(),
settingsMenu(treeTable)
);
topBox.setAlignment(Pos.CENTER_LEFT);
var playground = new VBox(10);
var playground = new VBox(BLOCK_VGAP, header, treeTable, footer);
playground.setMinHeight(100);
playground.getChildren().setAll(
topBox,
treeTable,
togglesBox
);
return playground;
}
private List<TreeItem<Product>> treeItems(int startId, int count, String brand) {
private List<TreeItem<Product>> createTreeItems(int startId, int count, String brand) {
return IntStream.range(startId, startId + count + 1).boxed()
.map(id -> Product.random(id, brand, FAKER))
.map(TreeItem::new)
@ -114,7 +151,7 @@ public class TreeTablePage extends AbstractPage {
}
@SuppressWarnings("unchecked")
private TreeTableView<Product> treeTable() {
private TreeTableView<Product> createTreeTable() {
var arrowCol = new TreeTableColumn<Product, String>("#");
// This is placeholder column for disclosure nodes. We need to fill it
// with empty strings or all .tree-table-cell will be marked as :empty,
@ -138,14 +175,14 @@ public class TreeTablePage extends AbstractPage {
idCol.setEditable(false);
idCol.setMinWidth(80);
var brandCol = new TreeTableColumn<Product, String>("Brand ");
var brandCol = new TreeTableColumn<Product, String>("Brand 🖉");
brandCol.setCellValueFactory(new TreeItemPropertyValueFactory<>("brand"));
brandCol.setCellFactory(ChoiceBoxTreeTableCell.forTreeTableColumn(
generate(() -> FAKER.commerce().brand(), 10).toArray(String[]::new)
));
brandCol.setEditable(true);
var nameCol = new TreeTableColumn<Product, String>("Name ");
var nameCol = new TreeTableColumn<Product, String>("Name 🖉");
nameCol.setCellValueFactory(new TreeItemPropertyValueFactory<>("name"));
nameCol.setCellFactory(ComboBoxTreeTableCell.forTreeTableColumn(
generate(() -> FAKER.commerce().productName(), 10).toArray(String[]::new)
@ -153,7 +190,7 @@ public class TreeTablePage extends AbstractPage {
nameCol.setEditable(true);
nameCol.setMinWidth(200);
var priceCol = new TreeTableColumn<Product, String>("Price ");
var priceCol = new TreeTableColumn<Product, String>("Price 🖉");
priceCol.setCellValueFactory(new TreeItemPropertyValueFactory<>("price"));
priceCol.setCellFactory(TextFieldTreeTableCell.forTreeTableColumn());
priceCol.setEditable(true);
@ -164,7 +201,7 @@ public class TreeTablePage extends AbstractPage {
return table;
}
private MenuButton settingsMenu(TreeTableView<Product> treeTable) {
private MenuButton createPropertiesMenu(TreeTableView<Product> treeTable) {
var resizePolicyCaption = new CaptionMenuItem("Resize Policy");
var resizePolicyGroup = new ToggleGroup();
resizePolicyGroup.selectedToggleProperty().addListener((obs, old, val) -> {
@ -216,66 +253,13 @@ public class TreeTablePage extends AbstractPage {
treeTable.getSelectionModel().cellSelectionEnabledProperty().bind(cellSelectionItem.selectedProperty());
cellSelectionItem.setSelected(false);
var edge2edgeItem = new CheckMenuItem("Edge to edge");
edge2edgeItem.selectedProperty().addListener((obs, old, val) -> {
if (!val) {
treeTable.getStyleClass().remove(Tweaks.EDGE_TO_EDGE);
} else {
treeTable.getStyleClass().add(Tweaks.EDGE_TO_EDGE);
}
});
// ~
var alignToggleGroup = new ToggleGroup();
var alignLeftItem = new RadioMenuItem("Left");
alignLeftItem.setToggleGroup(alignToggleGroup);
alignLeftItem.selectedProperty().addListener((obs, old, val) -> {
for (TreeTableColumn<?, ?> c : treeTable.getColumns()) {
addStyleClass(c, ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT);
}
});
var alignCenterItem = new RadioMenuItem("Center");
alignCenterItem.setToggleGroup(alignToggleGroup);
alignCenterItem.selectedProperty().addListener((obs, old, val) -> {
for (TreeTableColumn<?, ?> c : treeTable.getColumns()) {
addStyleClass(c, ALIGN_CENTER, ALIGN_LEFT, ALIGN_RIGHT);
}
});
var alignRightItem = new RadioMenuItem("Right");
alignRightItem.setToggleGroup(alignToggleGroup);
alignRightItem.selectedProperty().addListener((obs, old, val) -> {
for (TreeTableColumn<?, ?> c : treeTable.getColumns()) {
addStyleClass(c, ALIGN_RIGHT, ALIGN_LEFT, ALIGN_CENTER);
}
});
var alignDefaultItem = new MenuItem("Default");
alignDefaultItem.setOnAction(e -> {
for (TreeTableColumn<?, ?> c : treeTable.getColumns()) {
c.getStyleClass().removeAll(ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT);
}
});
var alignMenu = new Menu("Align columns");
alignMenu.getItems().setAll(
alignLeftItem,
alignCenterItem,
alignRightItem,
new SeparatorMenuItem(),
alignDefaultItem
);
// ~
var menuButtonItem = new CheckMenuItem("Show menu button");
treeTable.tableMenuButtonVisibleProperty().bind(menuButtonItem.selectedProperty());
menuButtonItem.setSelected(true);
return new MenuButton("Settings") {{
return new MenuButton("Properties") {{
getItems().setAll(
resizePolicyCaption,
unconstrainedResizeItem,
@ -287,8 +271,6 @@ public class TreeTablePage extends AbstractPage {
showRootItem,
editCellsItem,
cellSelectionItem,
alignMenu,
edge2edgeItem,
menuButtonItem
);
}};

@ -5,6 +5,7 @@ import atlantafx.base.theme.Styles;
import atlantafx.sampler.event.DefaultEventBus;
import atlantafx.sampler.event.ThemeEvent;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.Page;
import atlantafx.sampler.theme.SamplerTheme;
import atlantafx.sampler.theme.ThemeManager;
import javafx.geometry.HPos;
@ -13,6 +14,7 @@ import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Label;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
import javafx.util.Duration;
@ -25,6 +27,8 @@ import java.util.Objects;
import java.util.function.Consumer;
import static atlantafx.sampler.event.ThemeEvent.EventType.*;
import static atlantafx.sampler.page.SampleBlock.BLOCK_HGAP;
import static atlantafx.sampler.page.SampleBlock.BLOCK_VGAP;
import static atlantafx.sampler.util.Controls.hyperlink;
public class ThemePage extends AbstractPage {
@ -46,29 +50,25 @@ public class ThemePage extends AbstractPage {
private final ColorPalette colorPalette = new ColorPalette(colorBlockActionHandler);
private final ColorScale colorScale = new ColorScale();
private final ChoiceBox<SamplerTheme> themeSelector = themeSelector();
private final ChoiceBox<SamplerTheme> themeSelector = createThemeSelector();
private ThemeRepoManagerDialog themeRepoManagerDialog;
private ContrastCheckerDialog contrastCheckerDialog;
@Override
public String getName() {
return NAME;
}
public String getName() { return NAME; }
@Override
public boolean canDisplaySourceCode() {
return false;
}
public boolean canDisplaySourceCode() { return false; }
@Override
public boolean canChangeThemeSettings() {
return false;
}
public boolean canChangeThemeSettings() { return false; }
public ThemePage() {
super();
createView();
DefaultEventBus.getInstance().subscribe(ThemeEvent.class, e -> {
if (e.getEventType() == THEME_ADD || e.getEventType() == THEME_REMOVE) {
themeSelector.getItems().setAll(TM.getRepository().getAll());
@ -91,32 +91,29 @@ public class ThemePage extends AbstractPage {
private void createView() {
var noteText = new TextFlow(
new Text("AtlantaFX follows "),
hyperlink("Github Primer interface guidelines",
URI.create("https://primer.style/design/foundations/color")
),
hyperlink("Github Primer interface guidelines", URI.create("https://primer.style/design/foundations/color")),
new Text(" and color system.")
);
userContent.getChildren().addAll(
optionsGrid(),
setUserContent(new VBox(
Page.PAGE_VGAP,
createOptionsGrid(),
noteText,
colorPalette,
colorScale
);
));
selectCurrentTheme();
}
private GridPane optionsGrid() {
private GridPane createOptionsGrid() {
var themeRepoBtn = new Button("", new FontIcon(Material2OutlinedMZ.SETTINGS));
themeRepoBtn.getStyleClass().addAll(Styles.BUTTON_ICON, Styles.FLAT);
themeRepoBtn.setTooltip(new Tooltip("Settings"));
themeRepoBtn.setOnAction(e -> {
ThemeRepoManagerDialog dialog = getOrCreateThemeRepoManagerDialog();
overlay.setContent(dialog, HPos.CENTER);
dialog.getContent().update();
overlay.toFront();
});
@ -125,8 +122,8 @@ public class ThemePage extends AbstractPage {
// ~
var grid = new GridPane();
grid.setVgap(20);
grid.setHgap(20);
grid.setHgap(BLOCK_HGAP);
grid.setVgap(BLOCK_VGAP);
grid.add(new Label("Color theme"), 0, 0);
grid.add(themeSelector, 1, 0);
@ -137,7 +134,7 @@ public class ThemePage extends AbstractPage {
return grid;
}
private ChoiceBox<SamplerTheme> themeSelector() {
private ChoiceBox<SamplerTheme> createThemeSelector() {
var selector = new ChoiceBox<SamplerTheme>();
selector.getItems().setAll(TM.getRepository().getAll());
selector.getSelectionModel().selectedItemProperty().addListener((obs, old, val) -> {

@ -6,56 +6,54 @@ import atlantafx.sampler.event.ThemeEvent;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.page.SampleBlock;
import atlantafx.sampler.theme.ThemeManager;
import atlantafx.sampler.util.NodeUtils;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.collections.FXCollections;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.Label;
import javafx.scene.control.Spinner;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.layout.*;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
import javafx.util.Duration;
import java.util.Map;
import java.util.stream.Collectors;
import static atlantafx.base.theme.Styles.*;
import static atlantafx.sampler.event.ThemeEvent.EventType.FONT_CHANGE;
import static atlantafx.sampler.event.ThemeEvent.EventType.THEME_CHANGE;
import static atlantafx.sampler.page.SampleBlock.BLOCK_HGAP;
import static atlantafx.sampler.page.SampleBlock.BLOCK_VGAP;
import static atlantafx.sampler.theme.ThemeManager.DEFAULT_FONT_FAMILY_NAME;
import static atlantafx.sampler.theme.ThemeManager.SUPPORTED_FONT_SIZE;
public class TypographyPage extends AbstractPage {
private static final double CONTROL_WIDTH = 200;
private static final String DEFAULT_FONT_ID = "Default";
public static final String NAME = "Typography";
@Override
public String getName() {
return NAME;
}
@Override
public boolean canDisplaySourceCode() {
return false;
}
@Override
public boolean canChangeThemeSettings() {
return false;
}
private static final int CONTROL_WIDTH = 200;
private static final String DEFAULT_FONT_ID = "Default";
private static final ThemeManager TM = ThemeManager.getInstance();
private Pane fontSizeSampleContent;
@Override
public String getName() { return NAME; }
@Override
public boolean canDisplaySourceCode() { return false; }
@Override
public boolean canChangeThemeSettings() { return false; }
public TypographyPage() {
super();
createView();
DefaultEventBus.getInstance().subscribe(ThemeEvent.class, e -> {
if (e.getEventType() == THEME_CHANGE || e.getEventType() == FONT_CHANGE) {
@ -66,53 +64,53 @@ public class TypographyPage extends AbstractPage {
private void createView() {
var controlsGrid = new GridPane();
controlsGrid.setVgap(10);
controlsGrid.setHgap(20);
controlsGrid.setHgap(BLOCK_HGAP);
controlsGrid.setVgap(BLOCK_VGAP);
controlsGrid.add(new Label("Font family"), 0, 0);
controlsGrid.add(fontFamilyChooser(), 1, 0);
controlsGrid.add(createFontFamilyChooser(), 1, 0);
controlsGrid.add(new Label("Font size"), 0, 1);
controlsGrid.add(fontSizeSpinner(), 1, 1);
controlsGrid.add(crateFontSizeSpinner(), 1, 1);
var fontSizeSample = fontSizeSample();
fontSizeSampleContent = (Pane) fontSizeSample.getContent();
userContent.getChildren().setAll(
setUserContent(new VBox(
PAGE_VGAP,
controlsGrid,
fontSizeSample.getRoot(),
fontWeightSample().getRoot(),
fontStyleSample().getRoot(),
hyperlinkSample().getRoot(),
textColorSample().getRoot(),
textFlowSample().getRoot()
);
fontSizeSample,
fontWeightSample(),
expandingHBox(fontStyleSample(), textColorSample(), hyperlinkSample()),
textFlowSample()
));
}
private ComboBox<String> fontFamilyChooser() {
final var tm = ThemeManager.getInstance();
@Override
protected void onRendered() {
super.onRendered();
// font metrics can only be obtained by requesting from a rendered node
updateFontInfo(Duration.ZERO);
}
private ComboBox<String> createFontFamilyChooser() {
ComboBox<String> comboBox = new ComboBox<>();
comboBox.getItems().add(tm.isDefaultFontFamily() ? DEFAULT_FONT_ID : tm.getFontFamily());
comboBox.getItems().add(TM.isDefaultFontFamily() ? DEFAULT_FONT_ID : TM.getFontFamily());
comboBox.getItems().addAll(FXCollections.observableArrayList(Font.getFamilies()));
comboBox.setPrefWidth(CONTROL_WIDTH);
comboBox.getSelectionModel().select(tm.getFontFamily());
comboBox.getSelectionModel().select(TM.getFontFamily());
comboBox.valueProperty().addListener((obs, old, val) -> {
if (val != null) {
tm.setFontFamily(DEFAULT_FONT_ID.equals(val) ? ThemeManager.DEFAULT_FONT_FAMILY_NAME : val);
TM.setFontFamily(DEFAULT_FONT_ID.equals(val) ? DEFAULT_FONT_FAMILY_NAME : val);
}
});
return comboBox;
}
private Spinner<Integer> fontSizeSpinner() {
final var tm = ThemeManager.getInstance();
private Spinner<Integer> crateFontSizeSpinner() {
var spinner = new Spinner<Integer>(
SUPPORTED_FONT_SIZE.get(0),
SUPPORTED_FONT_SIZE.get(SUPPORTED_FONT_SIZE.size() - 1),
tm.getFontSize()
TM.getFontSize()
);
spinner.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
spinner.setPrefWidth(CONTROL_WIDTH);
@ -122,11 +120,11 @@ public class TypographyPage extends AbstractPage {
// we just keep current font size inside ThemeManager singleton.
// It works fine if ThemeManager default font size value matches
// default theme font size value.
spinner.getValueFactory().setValue(tm.getFontSize());
spinner.getValueFactory().setValue(TM.getFontSize());
spinner.valueProperty().addListener((obs, old, val) -> {
if (val != null) {
tm.setFontSize(val);
TM.setFontSize(val);
updateFontInfo(Duration.seconds(1));
}
});
@ -134,159 +132,153 @@ public class TypographyPage extends AbstractPage {
return spinner;
}
// font metrics can only be obtained by requesting from a rendered node
protected void onRendered() {
super.onRendered();
updateFontInfo(Duration.ZERO);
}
private void updateFontInfo(Duration delay) {
var t = new Timeline(new KeyFrame(delay));
t.setOnFinished(e -> {
for (Node node : fontSizeSampleContent.getChildren()) {
if (node instanceof Text textNode) {
var font = textNode.getFont();
textNode.setText(
String.format("%s = %.1fpx", textNode.getUserData(), Math.ceil(font.getSize()))
);
}
}
Map<String, Node> map = fontSizeSampleContent.getChildren().stream()
.collect(Collectors.toMap(
n -> GridPane.getColumnIndex(n).toString() + GridPane.getRowIndex(n).toString(),
n -> n
));
((Label) map.get("10")).setText(String.format("%.0fpx", getFontSize(map.get("00"))));
((Label) map.get("11")).setText(String.format("%.0fpx", getFontSize(map.get("01"))));
((Label) map.get("12")).setText(String.format("%.0fpx", getFontSize(map.get("02"))));
((Label) map.get("13")).setText(String.format("%.0fpx", getFontSize(map.get("03"))));
((Label) map.get("30")).setText(String.format("%.0fpx", getFontSize(map.get("20"))));
((Label) map.get("31")).setText(String.format("%.0fpx", getFontSize(map.get("21"))));
((Label) map.get("32")).setText(String.format("%.0fpx", getFontSize(map.get("22"))));
});
t.play();
}
private double getFontSize(Node node) {
return (node instanceof Text text) ? Math.ceil(text.getFont().getSize()) : 0;
}
private SampleBlock fontSizeSample() {
var grid = new GridPane();
grid.setHgap(40);
grid.setVgap(10);
grid.setHgap(BLOCK_HGAP);
grid.setVgap(BLOCK_VGAP);
grid.add(text("Title 1", TITLE_1), 0, 0);
grid.add(text("Title 2", TITLE_2), 0, 1);
grid.add(text("Title 3", TITLE_3), 0, 2);
grid.add(text("Title 4", TITLE_4), 0, 3);
grid.add(createText("Title 1", TITLE_1), 0, 0);
grid.add(createFontSizeLabel(), 1, 0);
grid.add(createText("Title 2", TITLE_2), 0, 1);
grid.add(createFontSizeLabel(), 1, 1);
grid.add(createText("Title 3", TITLE_3), 0, 2);
grid.add(createFontSizeLabel(), 1, 2);
grid.add(createText("Title 4", TITLE_4), 0, 3);
grid.add(createFontSizeLabel(), 1, 3);
grid.add(text("Caption", TEXT_CAPTION), 1, 0);
grid.add(text("Default"), 1, 1);
grid.add(text("Small", TEXT_SMALL), 1, 2);
grid.add(createText("Caption", TEXT_CAPTION), 2, 0);
grid.add(createFontSizeLabel(), 3, 0);
grid.add(createText("Default"), 2, 1);
grid.add(createFontSizeLabel(), 3, 1);
grid.add(createText("Small", TEXT_SMALL), 2, 2);
grid.add(createFontSizeLabel(), 3, 2);
grid.setAlignment(Pos.BASELINE_LEFT);
return new SampleBlock("Font size", grid);
return new SampleBlock("Font Size", grid);
}
private SampleBlock fontWeightSample() {
var sample1 = new HBox(10,
text("Bold", TEXT_BOLD),
text("Bolder", TEXT_BOLDER),
text("Normal", TEXT_NORMAL),
text("Lighter", TEXT_LIGHTER)
var sample1 = new HBox(
BLOCK_HGAP,
createText("Bold", TEXT_BOLD),
createText("Bolder", TEXT_BOLDER),
createText("Normal", TEXT_NORMAL),
createText("Lighter", TEXT_LIGHTER)
);
sample1.setAlignment(Pos.BASELINE_LEFT);
var sample2 = new HBox(10,
textInlineStyle("900", "-fx-font-weight:900;"),
textInlineStyle("800", "-fx-font-weight:800;"),
textInlineStyle("700", "-fx-font-weight:700;"),
textInlineStyle("600", "-fx-font-weight:600;"),
textInlineStyle("500", "-fx-font-weight:500;"),
textInlineStyle("400", "-fx-font-weight:400;"),
textInlineStyle("300", "-fx-font-weight:300;"),
textInlineStyle("200", "-fx-font-weight:200;"),
textInlineStyle("100", "-fx-font-weight:100;")
var sample2 = new HBox(
BLOCK_HGAP,
createStyledText("900", "-fx-font-weight:900;"),
createStyledText("800", "-fx-font-weight:800;"),
createStyledText("700", "-fx-font-weight:700;"),
createStyledText("600", "-fx-font-weight:600;"),
createStyledText("500", "-fx-font-weight:500;"),
createStyledText("400", "-fx-font-weight:400;"),
createStyledText("300", "-fx-font-weight:300;"),
createStyledText("200", "-fx-font-weight:200;"),
createStyledText("100", "-fx-font-weight:100;")
);
sample2.setAlignment(Pos.BASELINE_LEFT);
var sample3 = new HBox(10,
textInlineStyle("900", "-fx-font-family:'Inter Black';"),
textInlineStyle("800", "-fx-font-family:'Inter Extra Bold';"),
textInlineStyle("700", "-fx-font-family:'Inter Bold';"),
textInlineStyle("600", "-fx-font-family:'Inter Semi Bold';"),
textInlineStyle("500", "-fx-font-family:'Inter Medium';"),
textInlineStyle("400", "-fx-font-family:'Inter Regular';"),
textInlineStyle("300", "-fx-font-family:'Inter Light';"),
textInlineStyle("200", "-fx-font-family:'Inter Extra Light';"),
textInlineStyle("100", "-fx-font-family:'Inter Thin';")
var sample3 = new HBox(
BLOCK_HGAP,
createStyledText("900", "-fx-font-family:'Inter Black';"),
createStyledText("800", "-fx-font-family:'Inter Extra Bold';"),
createStyledText("700", "-fx-font-family:'Inter Bold';"),
createStyledText("600", "-fx-font-family:'Inter Semi Bold';"),
createStyledText("500", "-fx-font-family:'Inter Medium';"),
createStyledText("400", "-fx-font-family:'Inter Regular';"),
createStyledText("300", "-fx-font-family:'Inter Light';"),
createStyledText("200", "-fx-font-family:'Inter Extra Light';"),
createStyledText("100", "-fx-font-family:'Inter Thin';")
);
sample3.setAlignment(Pos.BASELINE_LEFT);
// JDK-8090423: https://bugs.openjdk.org/browse/JDK-8090423
// Workaround: https://edencoding.com/resources/css_properties/fx-font-weight/
return new SampleBlock("Font weight", new VBox(10,
return new SampleBlock("Font Weight", new VBox(
BLOCK_VGAP,
sample1,
sample2,
sample3,
text("JavaFX only supports Bold or Regular font weight. See the source code for workaround.",
TEXT, TEXT_SMALL, DANGER
)
createText("JavaFX only supports Bold or Regular font weight. See the source code for workaround.", TEXT, WARNING)
));
}
private SampleBlock fontStyleSample() {
var box = new HBox(10,
text("Italic", TEXT_ITALIC),
text("Oblique", TEXT_OBLIQUE),
text("Underlined", TEXT_UNDERLINED),
text("Strikethrough", TEXT_STRIKETHROUGH)
var box = new FlowPane(
BLOCK_HGAP, BLOCK_VGAP,
createText("Italic", TEXT_ITALIC),
createText("Oblique", TEXT_OBLIQUE),
createText("Underlined", TEXT_UNDERLINED),
createText("Strikethrough", TEXT_STRIKETHROUGH)
);
box.setAlignment(Pos.BASELINE_LEFT);
return new SampleBlock("Font style", box);
return new SampleBlock("Font Style", box);
}
private SampleBlock textColorSample() {
var box = new HBox(10,
text("Accent", TEXT, ACCENT),
text("Success", TEXT, SUCCESS),
text("Warning", TEXT, WARNING),
text("Danger", TEXT, DANGER)
var box = new FlowPane(
BLOCK_HGAP, BLOCK_VGAP,
createText("Accent", TEXT, ACCENT),
createText("Success", TEXT, SUCCESS),
createText("Warning", TEXT, WARNING),
createText("Danger", TEXT, DANGER)
);
box.setAlignment(Pos.BASELINE_LEFT);
return new SampleBlock("Text color", box);
return new SampleBlock("Text Color", box);
}
private SampleBlock hyperlinkSample() {
var linkNormal = hyperlink("_Normal", false, false);
var linkNormal = createHyperlink("_Normal", false, false);
linkNormal.setMnemonicParsing(true);
var linkVisited = hyperlink("_Visited", true, false);
var linkVisited = createHyperlink("_Visited", true, false);
linkVisited.setMnemonicParsing(true);
var linkBroken = hyperlink("_Broken", true, false);
var linkBroken = createHyperlink("_Broken", true, false);
linkBroken.setStyle("-color-link-fg-visited:-color-danger-fg;");
linkBroken.setMnemonicParsing(true);
var box = new HBox(10,
var box = new FlowPane(
BLOCK_HGAP, BLOCK_VGAP,
linkNormal,
linkVisited,
linkBroken,
hyperlink("Disabled", false, true)
createHyperlink("Disabled", false, true)
);
box.setAlignment(Pos.BASELINE_LEFT);
return new SampleBlock("Hyperlink", box);
}
private Text text(String text, String... styleClasses) {
var t = new Text(text);
t.getStyleClass().addAll(styleClasses);
t.setUserData(text);
return t;
}
private Text textInlineStyle(String text, String style) {
var t = new Text(text);
t.setStyle(style);
return t;
}
private Hyperlink hyperlink(String text, boolean visited, boolean disabled) {
var h = new Hyperlink(text);
h.setVisited(visited);
h.setDisable(disabled);
return h;
}
private SampleBlock textFlowSample() {
var textFlow = new TextFlow(
new Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. "),
@ -303,6 +295,32 @@ public class TypographyPage extends AbstractPage {
new Text(".")
);
return new SampleBlock("Text flow", textFlow);
return new SampleBlock("Text Flow", textFlow);
}
private Text createText(String text, String... styleClasses) {
var t = new Text(text);
t.getStyleClass().addAll(styleClasses);
t.setUserData(text);
return t;
}
private Text createStyledText(String text, String style) {
var t = new Text(text);
t.setStyle(style);
return t;
}
private Label createFontSizeLabel() {
var label = new Label();
label.setPadding(new Insets(5, 40, 5, 10));
return label;
}
private Hyperlink createHyperlink(String text, boolean visited, boolean disabled) {
var h = new Hyperlink(text);
h.setVisited(visited);
h.setDisable(disabled);
return h;
}
}

@ -1,7 +1,7 @@
package atlantafx.sampler.page.showcase;
import atlantafx.base.controls.Spacer;
import atlantafx.sampler.page.AbstractPage;
import atlantafx.sampler.util.NodeUtils;
import javafx.css.PseudoClass;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
@ -41,30 +41,25 @@ public abstract class ShowcasePage extends AbstractPage {
expandBtn.setOnAction(e -> {
expandBtn.getScene().getRoot().pseudoClassStateChanged(SHOWCASE_MODE, true);
VBox.setVgrow(showcase, Priority.ALWAYS);
expandBox.setVisible(false);
expandBox.setManaged(false);
collapseBox.setVisible(true);
collapseBox.setManaged(true);
NodeUtils.toggleVisibility(expandBox, false);
NodeUtils.toggleVisibility(collapseBox, true);
});
expandBox.getChildren().setAll(new Spacer(), expandBtn, new Spacer());
expandBox.setAlignment(Pos.CENTER_LEFT);
expandBox.getChildren().setAll(expandBtn);
expandBox.setAlignment(Pos.CENTER);
var collapseBtn = new Hyperlink("Exit showcase mode");
collapseBtn.setOnAction(e -> {
expandBtn.getScene().getRoot().pseudoClassStateChanged(SHOWCASE_MODE, false);
VBox.setVgrow(showcase, Priority.NEVER);
expandBox.setVisible(true);
expandBox.setManaged(true);
collapseBox.setVisible(false);
collapseBox.setManaged(false);
NodeUtils.toggleVisibility(expandBox, true);
NodeUtils.toggleVisibility(collapseBox, false);
});
collapseBox.getChildren().setAll(new FontIcon(Feather.MINIMIZE_2), collapseBtn);
collapseBox.setAlignment(Pos.CENTER_LEFT);
collapseBox.setPadding(new Insets(5));
collapseBox.setVisible(false);
collapseBox.setManaged(false);
NodeUtils.toggleVisibility(collapseBox, false);
userContent.getChildren().setAll(showcase, expandBox, collapseBox);
setUserContent(new VBox(showcase, expandBox, collapseBox));
}
@SuppressWarnings("SameParameterValue")

@ -85,7 +85,7 @@ final class PlayerPane extends VBox {
trackAlbum.setAlignment(CENTER);
trackAlbum.setMaxWidth(MAX_VALUE);
// == Media controls ==
// == MEDIA CONTROLS ==
var prevBtn = new Button("", new FontIcon(FAST_REWIND));
prevBtn.getStyleClass().addAll(BUTTON_CIRCLE);
@ -112,7 +112,7 @@ final class PlayerPane extends VBox {
mediaControls.getChildren().setAll(prevBtn, playBtn, nextBtn);
mediaControls.setAlignment(CENTER);
// == Time controls ==
// == TIME CONTROLS ==
timeSlider = new Slider(0, 1, 0);
timeSlider.getStyleClass().add("time-slider");
@ -129,7 +129,7 @@ final class PlayerPane extends VBox {
timeMarkersBox.getChildren().setAll(currentTimeLabel, new Spacer(), endTimeLabel);
timeMarkersBox.setMaxWidth(PANEL_MAX_WIDTH);
// == Extra controls ==
// == EXTRA CONTROLS ==
var clearPlaylistBtn = new Button("", new FontIcon(CLEAR_ALL));
clearPlaylistBtn.getStyleClass().addAll(BUTTON_CIRCLE);

@ -23,10 +23,12 @@
.page {
>.scroll-pane>.viewport>*>.wrapper>.user-content {
-fx-max-width: 4096px;
>.scroll-pane .user-content {
-fx-padding: 0;
-fx-spacing: 0;
>* {
-fx-max-width: 4096px;
}
}
.about {

@ -1,17 +0,0 @@
// SPDX-License-Identifier: MIT
.sample-block {
-fx-spacing: 1em;
>.title {
-fx-font-weight: bold;
}
}
.popover .date-picker-popup {
-color-date-border: transparent;
-color-date-bg: transparent;
-color-date-day-bg: transparent;
-color-date-month-year-bg: transparent;
-color-date-day-bg-hover: -color-bg-subtle;
}

@ -3,4 +3,3 @@
@use "main";
@use "overlay";
@use "page";
@use "components";

@ -1,19 +1,34 @@
// SPDX-License-Identifier: MIT
.page {
>.scroll-pane {
-fx-background-color: -color-bg-default;
>.viewport>*>.wrapper {
-fx-min-width: 880px;
-fx-alignment: TOP_CENTER;
// stack pane to center user content
.user-content {
-fx-padding: 40px 0 40px 0; // vertical paddings
-fx-min-width: 860px; // horizontal paddings
>.user-content {
-fx-padding: 40px 0 40px 0;
-fx-spacing: 40px;
>* {
// limit user content width
-fx-min-width: 800px;
-fx-max-width: 800px;
}
}
}
}
.sample-block {
-fx-background-color: -color-bg-default;
-fx-effect: dropshadow(gaussian, -color-shadow-default, 10, 0.4, 0, 0);
-fx-border-color: -color-border-muted;
-fx-border-width: 1px;
-fx-padding: 1em 1.5em 1.5em 1.5em;
-fx-spacing: 1em;
-fx-min-width: 220px;
>.title {
-fx-font-weight: bold;
-fx-padding: 0 0 10px 0;
}
}