Use new ModalPane control for Sampler dialogs
This commit is contained in:
parent
e86c95af29
commit
6ef6b5502c
@ -9,9 +9,7 @@ import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@ -95,10 +93,18 @@ public class DialogPane extends AnchorPane {
|
||||
getChildren().add(getChildren().indexOf(closeButton), node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually closes the DialogPane in case one needs to use their
|
||||
* own close button.
|
||||
*/
|
||||
public void close() {
|
||||
handleClose();
|
||||
}
|
||||
|
||||
protected void createLayout() {
|
||||
closeButton.getStyleClass().add("close-button");
|
||||
closeButton.getChildren().setAll(closeButtonIcon);
|
||||
closeButton.setOnMouseClicked(this::handleClose);
|
||||
closeButton.setOnMouseClicked(e -> handleClose());
|
||||
|
||||
closeButtonIcon.getStyleClass().add("icon");
|
||||
|
||||
@ -112,7 +118,7 @@ public class DialogPane extends AnchorPane {
|
||||
setRightAnchor(closeButton, 10d);
|
||||
}
|
||||
|
||||
protected void handleClose(MouseEvent event) {
|
||||
protected void handleClose() {
|
||||
if (modalPane != null) {
|
||||
modalPane.hide(clearOnClose.get());
|
||||
} else if (selector != null && getScene() != null) {
|
||||
@ -125,7 +131,7 @@ public class DialogPane extends AnchorPane {
|
||||
|
||||
// call user specified close handler
|
||||
if (onClose.get() != null) {
|
||||
onClose.get().handle(event);
|
||||
onClose.get().run();
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,18 +145,18 @@ public class DialogPane extends AnchorPane {
|
||||
* handler will be executed after the default close handler. Therefore, you
|
||||
* can use it to perform arbitrary actions on dialog close.
|
||||
*/
|
||||
protected final ObjectProperty<EventHandler<? super MouseEvent>> onClose =
|
||||
protected final ObjectProperty<Runnable> onClose =
|
||||
new SimpleObjectProperty<>(this, "onClose");
|
||||
|
||||
public EventHandler<? super MouseEvent> getOnClose() {
|
||||
public Runnable getOnClose() {
|
||||
return onClose.get();
|
||||
}
|
||||
|
||||
public ObjectProperty<EventHandler<? super MouseEvent>> onCloseProperty() {
|
||||
public ObjectProperty<Runnable> onCloseProperty() {
|
||||
return onClose;
|
||||
}
|
||||
|
||||
public void setOnClose(EventHandler<? super MouseEvent> onClose) {
|
||||
public void setOnClose(Runnable onClose) {
|
||||
this.onClose.set(onClose);
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
package atlantafx.sampler.layout;
|
||||
|
||||
import atlantafx.base.controls.ModalPane;
|
||||
import atlantafx.sampler.util.NodeUtils;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
@ -11,16 +12,19 @@ public final class ApplicationWindow extends AnchorPane {
|
||||
|
||||
public static final int MIN_WIDTH = 1200;
|
||||
public static final int SIDEBAR_WIDTH = 250;
|
||||
public static final String MAIN_MODAL_ID = "modal-pane";
|
||||
|
||||
|
||||
public ApplicationWindow() {
|
||||
// this is the place to apply user custom CSS,
|
||||
// one level below the ':root'
|
||||
var body = new StackPane();
|
||||
body.getStyleClass().add("body");
|
||||
body.getChildren().setAll(
|
||||
new Overlay(),
|
||||
new MainLayer()
|
||||
);
|
||||
|
||||
var modalPane = new ModalPane();
|
||||
modalPane.setId(MAIN_MODAL_ID);
|
||||
|
||||
body.getChildren().setAll(modalPane, new MainLayer());
|
||||
NodeUtils.setAnchors(body, Insets.EMPTY);
|
||||
|
||||
getChildren().setAll(body);
|
||||
|
@ -0,0 +1,64 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
package atlantafx.sampler.layout;
|
||||
|
||||
import atlantafx.base.controls.Card;
|
||||
import atlantafx.base.controls.ModalPane;
|
||||
import atlantafx.base.controls.Spacer;
|
||||
import atlantafx.base.controls.Tile;
|
||||
import atlantafx.base.layout.DialogPane;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
public abstract class ModalDialog extends DialogPane {
|
||||
|
||||
protected Card content = new Card();
|
||||
protected Tile header = new Tile();
|
||||
|
||||
public ModalDialog() {
|
||||
super("#" + ApplicationWindow.MAIN_MODAL_ID);
|
||||
createView();
|
||||
}
|
||||
|
||||
public void show(Scene scene) {
|
||||
var modalPane = (ModalPane) scene.lookup("#" + ApplicationWindow.MAIN_MODAL_ID);
|
||||
modalPane.show(this);
|
||||
}
|
||||
|
||||
protected void createView() {
|
||||
content.setHeader(header);
|
||||
|
||||
// IMPORTANT: this guarantees client will use correct width and height
|
||||
setMinWidth(USE_PREF_SIZE);
|
||||
setMaxWidth(USE_PREF_SIZE);
|
||||
setMinHeight(USE_PREF_SIZE);
|
||||
setMaxHeight(USE_PREF_SIZE);
|
||||
|
||||
AnchorPane.setTopAnchor(content, 0d);
|
||||
AnchorPane.setRightAnchor(content, 0d);
|
||||
AnchorPane.setBottomAnchor(content, 0d);
|
||||
AnchorPane.setLeftAnchor(content, 0d);
|
||||
|
||||
addContent(content);
|
||||
getStyleClass().add("modal-dialog");
|
||||
}
|
||||
|
||||
protected HBox createDefaultFooter() {
|
||||
var closeBtn = new Button("Close");
|
||||
closeBtn.getStyleClass().add("form-action");
|
||||
closeBtn.setCancelButton(true);
|
||||
closeBtn.setOnAction(e -> close());
|
||||
|
||||
var footer = new HBox(10, new Spacer(), closeBtn);
|
||||
footer.getStyleClass().add("footer");
|
||||
footer.setAlignment(Pos.CENTER_RIGHT);
|
||||
VBox.setVgrow(footer, Priority.NEVER);
|
||||
|
||||
return footer;
|
||||
}
|
||||
}
|
@ -1,162 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
package atlantafx.sampler.layout;
|
||||
|
||||
import atlantafx.base.util.Animations;
|
||||
import atlantafx.sampler.util.NodeUtils;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import javafx.animation.Timeline;
|
||||
import javafx.beans.property.ReadOnlyBooleanProperty;
|
||||
import javafx.beans.property.ReadOnlyBooleanWrapper;
|
||||
import javafx.event.Event;
|
||||
import javafx.geometry.HPos;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.input.MouseButton;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.util.Duration;
|
||||
|
||||
public final class Overlay extends StackPane {
|
||||
|
||||
public static final String STYLE_CLASS = "overlay";
|
||||
|
||||
private ScrollPane scrollPane;
|
||||
private AnchorPane edgeContentWrapper;
|
||||
private StackPane centerContentWrapper;
|
||||
|
||||
private final ReadOnlyBooleanWrapper onFrontProperty = new ReadOnlyBooleanWrapper(false);
|
||||
private final Timeline fadeInTransition = Animations.fadeIn(this, Duration.millis(100));
|
||||
private final Timeline fadeOutTransition = Animations.fadeOut(this, Duration.millis(200));
|
||||
|
||||
private HPos currentContentPos;
|
||||
|
||||
public Overlay() {
|
||||
createView();
|
||||
}
|
||||
|
||||
private void createView() {
|
||||
edgeContentWrapper = new AnchorPane();
|
||||
edgeContentWrapper.getStyleClass().add("scrollable-content");
|
||||
|
||||
centerContentWrapper = new StackPane();
|
||||
centerContentWrapper.getStyleClass().add("scrollable-content");
|
||||
centerContentWrapper.setAlignment(Pos.CENTER);
|
||||
|
||||
scrollPane = new ScrollPane();
|
||||
NodeUtils.setScrollConstraints(scrollPane,
|
||||
ScrollPane.ScrollBarPolicy.AS_NEEDED, true,
|
||||
ScrollPane.ScrollBarPolicy.NEVER, true
|
||||
);
|
||||
scrollPane.setMaxHeight(10_000); // scroll pane won't work without height specified
|
||||
|
||||
// ~
|
||||
|
||||
Consumer<Event> hideAndConsume = e -> {
|
||||
removeContent();
|
||||
toBack();
|
||||
e.consume();
|
||||
};
|
||||
|
||||
// hide overlay by pressing ESC (only works when overlay or one of its children has focus,
|
||||
// that's why we requesting it in the toFront())
|
||||
addEventHandler(KeyEvent.KEY_PRESSED, e -> {
|
||||
if (e.getCode() == KeyCode.ESCAPE) {
|
||||
hideAndConsume.accept(e);
|
||||
}
|
||||
});
|
||||
|
||||
// hide overlay by clicking outside content area
|
||||
setOnMouseClicked(e -> {
|
||||
Pane content = getContent();
|
||||
Node eventSource = e.getPickResult().getIntersectedNode();
|
||||
if (e.getButton() == MouseButton.PRIMARY && content != null
|
||||
&& !NodeUtils.isDescendant(content, eventSource)) {
|
||||
hideAndConsume.accept(e);
|
||||
}
|
||||
});
|
||||
|
||||
getChildren().add(scrollPane);
|
||||
getStyleClass().add(STYLE_CLASS);
|
||||
}
|
||||
|
||||
public Pane getContent() {
|
||||
return NodeUtils.getChildByIndex(getContentWrapper(), 0, Pane.class);
|
||||
}
|
||||
|
||||
private Pane getContentWrapper() {
|
||||
return currentContentPos == HPos.CENTER ? centerContentWrapper : edgeContentWrapper;
|
||||
}
|
||||
|
||||
public void setContent(Pane content, HPos pos) {
|
||||
Objects.requireNonNull(content);
|
||||
Objects.requireNonNull(pos);
|
||||
|
||||
// clear old content
|
||||
if (pos != currentContentPos) {
|
||||
removeContent();
|
||||
currentContentPos = pos;
|
||||
}
|
||||
|
||||
switch (pos) {
|
||||
case LEFT -> {
|
||||
edgeContentWrapper.getChildren().setAll(content);
|
||||
NodeUtils.setAnchors(content, new Insets(0, -1, 0, 0));
|
||||
}
|
||||
case RIGHT -> {
|
||||
edgeContentWrapper.getChildren().setAll(content);
|
||||
NodeUtils.setAnchors(content, new Insets(0, 0, 0, -1));
|
||||
}
|
||||
case CENTER -> {
|
||||
centerContentWrapper.getChildren().setAll(content);
|
||||
StackPane.setAlignment(content, Pos.CENTER);
|
||||
}
|
||||
}
|
||||
|
||||
scrollPane.setContent(getContentWrapper());
|
||||
}
|
||||
|
||||
public void removeContent() {
|
||||
getContentWrapper().getChildren().clear();
|
||||
}
|
||||
|
||||
public boolean contains(Pane content) {
|
||||
return content != null
|
||||
&& getContentWrapper().getChildren().size() > 0
|
||||
&& getContentWrapper().getChildren().get(0).equals(content);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toFront() {
|
||||
if (onFrontProperty.get()) {
|
||||
return;
|
||||
}
|
||||
super.toFront();
|
||||
fadeInTransition.playFromStart();
|
||||
onFrontProperty.set(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBack() {
|
||||
if (!onFrontProperty.get()) {
|
||||
return;
|
||||
}
|
||||
super.toBack();
|
||||
fadeOutTransition.playFromStart();
|
||||
onFrontProperty.set(false);
|
||||
}
|
||||
|
||||
public ReadOnlyBooleanProperty onFrontProperty() {
|
||||
return onFrontProperty.getReadOnlyProperty();
|
||||
}
|
||||
|
||||
public boolean isOnFront() {
|
||||
return onFrontProperty().get();
|
||||
}
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
package atlantafx.sampler.layout;
|
||||
|
||||
import static atlantafx.base.theme.Styles.BUTTON_CIRCLE;
|
||||
import static atlantafx.base.theme.Styles.BUTTON_ICON;
|
||||
import static atlantafx.base.theme.Styles.FLAT;
|
||||
import static atlantafx.base.theme.Styles.TITLE_4;
|
||||
|
||||
import atlantafx.base.controls.Spacer;
|
||||
import java.util.Objects;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
import org.kordamp.ikonli.javafx.FontIcon;
|
||||
import org.kordamp.ikonli.material2.Material2AL;
|
||||
|
||||
public abstract class OverlayDialog<T extends Region> extends VBox {
|
||||
|
||||
protected static final int CONTENT_CHILD_INDEX = 1;
|
||||
|
||||
protected Label titleLabel;
|
||||
protected Button topCloseBtn;
|
||||
protected HBox headerBox;
|
||||
|
||||
protected Button bottomCloseBtn;
|
||||
protected HBox footerBox;
|
||||
|
||||
protected Runnable onCloseCallback;
|
||||
|
||||
public OverlayDialog() {
|
||||
createView();
|
||||
}
|
||||
|
||||
protected void createView() {
|
||||
titleLabel = new Label();
|
||||
titleLabel.getStyleClass().addAll(TITLE_4, "title");
|
||||
|
||||
topCloseBtn = new Button("", new FontIcon(Material2AL.CLOSE));
|
||||
topCloseBtn.getStyleClass().addAll(BUTTON_ICON, BUTTON_CIRCLE, FLAT, "close-button");
|
||||
topCloseBtn.setOnAction(e -> close());
|
||||
|
||||
headerBox = new HBox(10);
|
||||
headerBox.getStyleClass().add("header");
|
||||
headerBox.setAlignment(Pos.CENTER_LEFT);
|
||||
headerBox.getChildren().setAll(
|
||||
titleLabel,
|
||||
new Spacer(),
|
||||
topCloseBtn
|
||||
);
|
||||
VBox.setVgrow(headerBox, Priority.NEVER);
|
||||
|
||||
bottomCloseBtn = new Button("Close");
|
||||
bottomCloseBtn.getStyleClass().add("form-action");
|
||||
bottomCloseBtn.setOnAction(e -> close());
|
||||
bottomCloseBtn.setCancelButton(true);
|
||||
|
||||
footerBox = new HBox(10);
|
||||
footerBox.getStyleClass().add("footer");
|
||||
footerBox.setAlignment(Pos.CENTER_RIGHT);
|
||||
footerBox.getChildren().setAll(
|
||||
new Spacer(),
|
||||
bottomCloseBtn
|
||||
);
|
||||
VBox.setVgrow(footerBox, Priority.NEVER);
|
||||
|
||||
// IMPORTANT: this guarantees client will use correct width and height
|
||||
setMinWidth(USE_PREF_SIZE);
|
||||
setMaxWidth(USE_PREF_SIZE);
|
||||
setMinHeight(USE_PREF_SIZE);
|
||||
setMaxHeight(USE_PREF_SIZE);
|
||||
|
||||
// if you're updating this line, update setContent() method as well
|
||||
getChildren().setAll(headerBox, footerBox);
|
||||
|
||||
getStyleClass().add("overlay-dialog");
|
||||
}
|
||||
|
||||
protected void setContent(T content) {
|
||||
Objects.requireNonNull(content);
|
||||
VBox.setVgrow(content, Priority.ALWAYS);
|
||||
|
||||
// content have to be placed exactly between header and footer
|
||||
if (getChildren().size() == 2) {
|
||||
// add new content
|
||||
getChildren().add(CONTENT_CHILD_INDEX, content);
|
||||
} else if (getChildren().size() == 3) {
|
||||
// overwrite existing content
|
||||
getChildren().set(CONTENT_CHILD_INDEX, content);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Content cannot be placed because of unexpected children size. "
|
||||
+ "You should override 'OverlayDialog#setContent()' and place it manually.");
|
||||
}
|
||||
}
|
||||
|
||||
protected void setTitle(String title) {
|
||||
titleLabel.setText(title);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (onCloseCallback != null) {
|
||||
onCloseCallback.run();
|
||||
}
|
||||
}
|
||||
|
||||
public Runnable getOnCloseRequest() {
|
||||
return onCloseCallback;
|
||||
}
|
||||
|
||||
public void setOnCloseRequest(Runnable handler) {
|
||||
this.onCloseCallback = handler;
|
||||
}
|
||||
}
|
@ -7,7 +7,6 @@ import atlantafx.base.controls.Spacer;
|
||||
import atlantafx.base.theme.Styles;
|
||||
import atlantafx.base.theme.Tweaks;
|
||||
import java.util.function.Consumer;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ListCell;
|
||||
@ -22,7 +21,7 @@ import org.kordamp.ikonli.javafx.FontIcon;
|
||||
import org.kordamp.ikonli.material2.Material2AL;
|
||||
import org.kordamp.ikonli.material2.Material2MZ;
|
||||
|
||||
final class SearchDialog extends OverlayDialog<VBox> {
|
||||
final class SearchDialog extends ModalDialog {
|
||||
|
||||
private final MainModel model;
|
||||
|
||||
@ -35,8 +34,11 @@ final class SearchDialog extends OverlayDialog<VBox> {
|
||||
this.model = model;
|
||||
|
||||
setId("search-dialog");
|
||||
setTitle("Search");
|
||||
setContent(createContent());
|
||||
header.setTitle("Search");
|
||||
content.setBody(createContent());
|
||||
content.setFooter(createDefaultFooter());
|
||||
content.setPrefSize(600, 440);
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
@ -61,11 +63,7 @@ final class SearchDialog extends OverlayDialog<VBox> {
|
||||
resultList.setCellFactory(c -> new ResultListCell(clickHandler));
|
||||
VBox.setVgrow(resultList, Priority.ALWAYS);
|
||||
|
||||
var content = new VBox(10, searchField, resultList);
|
||||
content.setPadding(new Insets(10, 20, 10, 20));
|
||||
content.setPrefSize(600, 440);
|
||||
|
||||
return content;
|
||||
return new VBox(10, searchField, resultList);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
|
@ -19,7 +19,6 @@ import atlantafx.sampler.util.Lazy;
|
||||
import java.net.URI;
|
||||
import java.util.Objects;
|
||||
import javafx.application.Platform;
|
||||
import javafx.geometry.HPos;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Cursor;
|
||||
@ -43,7 +42,6 @@ import org.kordamp.ikonli.material2.Material2OutlinedAL;
|
||||
final class Sidebar extends VBox {
|
||||
|
||||
private final NavTree navTree;
|
||||
private Overlay overlay;
|
||||
private final Lazy<SearchDialog> searchDialog;
|
||||
private final Lazy<ThemeDialog> themeDialog;
|
||||
|
||||
@ -56,21 +54,13 @@ final class Sidebar extends VBox {
|
||||
|
||||
searchDialog = new Lazy<>(() -> {
|
||||
var dialog = new SearchDialog(model);
|
||||
dialog.setOnCloseRequest(() -> {
|
||||
var overlay = lookupOverlay();
|
||||
overlay.removeContent();
|
||||
overlay.toBack();
|
||||
});
|
||||
dialog.setClearOnClose(true);
|
||||
return dialog;
|
||||
});
|
||||
|
||||
themeDialog = new Lazy<>(() -> {
|
||||
var dialog = new ThemeDialog();
|
||||
dialog.setOnCloseRequest(() -> {
|
||||
var overlay = lookupOverlay();
|
||||
overlay.removeContent();
|
||||
overlay.toBack();
|
||||
});
|
||||
dialog.setClearOnClose(true);
|
||||
return dialog;
|
||||
});
|
||||
|
||||
@ -129,27 +119,16 @@ final class Sidebar extends VBox {
|
||||
|
||||
private void openSearchDialog() {
|
||||
var dialog = searchDialog.get();
|
||||
var overlay = lookupOverlay();
|
||||
overlay.setContent(dialog, HPos.CENTER);
|
||||
overlay.toFront();
|
||||
dialog.show(getScene());
|
||||
Platform.runLater(dialog::begForFocus);
|
||||
}
|
||||
|
||||
private void openThemeDialog() {
|
||||
var dialog = themeDialog.get();
|
||||
var overlay = lookupOverlay();
|
||||
overlay.setContent(dialog, HPos.CENTER);
|
||||
overlay.toFront();
|
||||
dialog.show(getScene());
|
||||
Platform.runLater(dialog::requestFocus);
|
||||
}
|
||||
|
||||
private Overlay lookupOverlay() {
|
||||
return Objects.requireNonNullElse(overlay,
|
||||
overlay = getScene() != null
|
||||
&& getScene().lookup("." + Overlay.STYLE_CLASS) instanceof Overlay o ? o : null
|
||||
);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private class Header extends VBox {
|
||||
|
@ -2,7 +2,6 @@ package atlantafx.sampler.layout;
|
||||
|
||||
import atlantafx.sampler.theme.SamplerTheme;
|
||||
import atlantafx.sampler.theme.ThemeManager;
|
||||
import atlantafx.sampler.util.NodeUtils;
|
||||
import java.util.Objects;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
@ -10,7 +9,7 @@ import javafx.scene.control.ToggleGroup;
|
||||
import javafx.scene.layout.TilePane;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
final class ThemeDialog extends OverlayDialog<VBox> {
|
||||
final class ThemeDialog extends ModalDialog {
|
||||
|
||||
private final TilePane thumbnailsPane = new TilePane(20, 20);
|
||||
private final ToggleGroup thumbnailsGroup = new ToggleGroup();
|
||||
@ -19,17 +18,14 @@ final class ThemeDialog extends OverlayDialog<VBox> {
|
||||
super();
|
||||
|
||||
setId("theme-dialog");
|
||||
setTitle("Select a theme");
|
||||
setContent(createContent());
|
||||
NodeUtils.toggleVisibility(footerBox, false);
|
||||
header.setTitle("Select a theme");
|
||||
content.setBody(createContent());
|
||||
content.setFooter(null);
|
||||
|
||||
updateThumbnails();
|
||||
|
||||
thumbnailsGroup.selectedToggleProperty().addListener((obs, old, val) -> {
|
||||
System.out.println(0);
|
||||
System.out.println(val.getUserData().getClass().getName());
|
||||
if (val != null && val.getUserData() instanceof SamplerTheme theme) {
|
||||
System.out.println(1);
|
||||
ThemeManager.getInstance().setTheme(theme);
|
||||
}
|
||||
});
|
||||
|
@ -6,7 +6,6 @@ import static javafx.scene.control.ScrollPane.ScrollBarPolicy.AS_NEEDED;
|
||||
import static javafx.scene.control.ScrollPane.ScrollBarPolicy.NEVER;
|
||||
|
||||
import atlantafx.base.util.BBCodeParser;
|
||||
import atlantafx.sampler.layout.Overlay;
|
||||
import atlantafx.sampler.util.NodeUtils;
|
||||
import java.net.URI;
|
||||
import javafx.geometry.Pos;
|
||||
@ -21,7 +20,6 @@ public abstract class AbstractPage extends StackPane implements Page {
|
||||
|
||||
protected final VBox userContent = new VBox();
|
||||
protected final StackPane userContentArea = new StackPane(userContent);
|
||||
protected Overlay overlay;
|
||||
protected boolean isRendered = false;
|
||||
|
||||
protected AbstractPage() {
|
||||
@ -88,7 +86,6 @@ public abstract class AbstractPage extends StackPane implements Page {
|
||||
// Some properties can only be obtained after node placed
|
||||
// to the scene graph and here is the place do this.
|
||||
protected void onRendered() {
|
||||
this.overlay = lookupOverlay();
|
||||
}
|
||||
|
||||
protected void addPageHeader() {
|
||||
@ -103,9 +100,4 @@ public abstract class AbstractPage extends StackPane implements Page {
|
||||
protected void addFormattedText(String text) {
|
||||
userContent.getChildren().add(BBCodeParser.createFormattedText(text));
|
||||
}
|
||||
|
||||
protected Overlay lookupOverlay() {
|
||||
return getScene() != null
|
||||
&& getScene().lookup("." + Overlay.STYLE_CLASS) instanceof Overlay ov ? ov : null;
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import static javafx.scene.control.ScrollPane.ScrollBarPolicy.AS_NEEDED;
|
||||
import static javafx.scene.control.ScrollPane.ScrollBarPolicy.NEVER;
|
||||
|
||||
import atlantafx.base.theme.Styles;
|
||||
import atlantafx.sampler.layout.Overlay;
|
||||
import atlantafx.sampler.util.NodeUtils;
|
||||
import java.net.URI;
|
||||
import java.util.LinkedHashSet;
|
||||
@ -39,8 +38,6 @@ public abstract class OutlinePage extends StackPane implements Page {
|
||||
protected final VBox userContent = new VBox();
|
||||
protected final StackPane userContentArea = new StackPane(userContent);
|
||||
protected final Outline outline = new Outline(createOutlineHandler());
|
||||
|
||||
protected Overlay overlay;
|
||||
protected boolean isRendered = false;
|
||||
|
||||
protected OutlinePage() {
|
||||
@ -200,12 +197,6 @@ public abstract class OutlinePage extends StackPane implements Page {
|
||||
// Some properties can only be obtained after node placed
|
||||
// to the scene graph and here is the place do this.
|
||||
protected void onRendered() {
|
||||
this.overlay = lookupOverlay();
|
||||
}
|
||||
|
||||
protected Overlay lookupOverlay() {
|
||||
var scene = getScene();
|
||||
return scene != null && scene.lookup("." + Overlay.STYLE_CLASS) instanceof Overlay o ? o : null;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
@ -9,7 +9,6 @@ import java.util.function.Consumer;
|
||||
import javafx.animation.KeyFrame;
|
||||
import javafx.animation.Timeline;
|
||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.util.Duration;
|
||||
@ -17,13 +16,15 @@ import javafx.util.Duration;
|
||||
final class ColorPalette extends GridPane {
|
||||
|
||||
private final List<ColorPaletteBlock> blocks = new ArrayList<>();
|
||||
private final ReadOnlyObjectWrapper<Color> bgBaseColor = new ReadOnlyObjectWrapper<>(Color.WHITE);
|
||||
private final Consumer<ColorPaletteBlock> colorBlockActionHandler;
|
||||
private final ReadOnlyObjectProperty<Color> bgBaseColor;
|
||||
|
||||
public ColorPalette(Consumer<ColorPaletteBlock> actionHandler) {
|
||||
public ColorPalette(Consumer<ColorPaletteBlock> actionHandler,
|
||||
ReadOnlyObjectProperty<Color> bgBaseColor) {
|
||||
super();
|
||||
|
||||
this.colorBlockActionHandler = Objects.requireNonNull(actionHandler, "actionHandler");
|
||||
this.bgBaseColor = bgBaseColor;
|
||||
|
||||
add(colorBlock("-color-fg-default", "-color-bg-default", "-color-border-default"), 0, 0);
|
||||
add(colorBlock("-color-fg-default", "-color-bg-overlay", "-color-border-default"), 1, 0);
|
||||
@ -59,7 +60,7 @@ final class ColorPalette extends GridPane {
|
||||
}
|
||||
|
||||
private ColorPaletteBlock colorBlock(String fgColor, String bgColor, String borderColor) {
|
||||
var block = new ColorPaletteBlock(fgColor, bgColor, borderColor, bgBaseColor.getReadOnlyProperty());
|
||||
var block = new ColorPaletteBlock(fgColor, bgColor, borderColor, bgBaseColor);
|
||||
block.setOnAction(colorBlockActionHandler);
|
||||
blocks.add(block);
|
||||
return block;
|
||||
@ -73,8 +74,4 @@ final class ColorPalette extends GridPane {
|
||||
t.setOnFinished(e -> blocks.forEach(ColorPaletteBlock::update));
|
||||
t.play();
|
||||
}
|
||||
|
||||
public ReadOnlyObjectProperty<Color> bgBaseColorProperty() {
|
||||
return bgBaseColor.getReadOnlyProperty();
|
||||
}
|
||||
}
|
||||
|
@ -6,31 +6,26 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import javafx.animation.KeyFrame;
|
||||
import javafx.animation.Timeline;
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||
import javafx.scene.layout.FlowPane;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.util.Duration;
|
||||
|
||||
final class ColorScale extends FlowPane {
|
||||
|
||||
private final ReadOnlyObjectWrapper<Color> bgBaseColor = new ReadOnlyObjectWrapper<>(Color.WHITE);
|
||||
private final List<ColorScaleBlock> blocks = Arrays.asList(
|
||||
ColorScaleBlock.forColorPrefix(bgBaseColor, "-color-base-", 10),
|
||||
ColorScaleBlock.forColorPrefix(bgBaseColor, "-color-accent-", 10),
|
||||
ColorScaleBlock.forColorPrefix(bgBaseColor, "-color-success-", 10),
|
||||
ColorScaleBlock.forColorPrefix(bgBaseColor, "-color-warning-", 10),
|
||||
ColorScaleBlock.forColorPrefix(bgBaseColor, "-color-danger-", 10),
|
||||
ColorScaleBlock.forColorName(bgBaseColor, "-color-dark", "-color-light")
|
||||
);
|
||||
private final List<ColorScaleBlock> blocks;
|
||||
|
||||
public ColorScale() {
|
||||
public ColorScale(ReadOnlyObjectProperty<Color> bgBaseColor) {
|
||||
super();
|
||||
|
||||
backgroundProperty().addListener((obs, old, val) -> bgBaseColor.set(
|
||||
val != null && !val.getFills().isEmpty()
|
||||
? (Color) val.getFills().get(0).getFill()
|
||||
: Color.WHITE
|
||||
));
|
||||
blocks = Arrays.asList(
|
||||
ColorScaleBlock.forColorPrefix(bgBaseColor, "-color-base-", 10),
|
||||
ColorScaleBlock.forColorPrefix(bgBaseColor, "-color-accent-", 10),
|
||||
ColorScaleBlock.forColorPrefix(bgBaseColor, "-color-success-", 10),
|
||||
ColorScaleBlock.forColorPrefix(bgBaseColor, "-color-warning-", 10),
|
||||
ColorScaleBlock.forColorPrefix(bgBaseColor, "-color-danger-", 10),
|
||||
ColorScaleBlock.forColorName(bgBaseColor, "-color-dark", "-color-light")
|
||||
);
|
||||
|
||||
setId("color-scale");
|
||||
getChildren().setAll(blocks);
|
||||
|
@ -77,7 +77,11 @@ final class ContrastChecker extends GridPane {
|
||||
|
||||
this.bgBaseColor = bgBaseColor;
|
||||
this.contrastRatio = Bindings.createDoubleBinding(
|
||||
() -> getContrastRatioOpacityAware(bgColor.getColor(), fgColor.getColor(), bgBaseColor.get()),
|
||||
() -> getContrastRatioOpacityAware(
|
||||
bgColor.getColor(),
|
||||
fgColor.getColor(),
|
||||
bgBaseColor.get()
|
||||
),
|
||||
bgColor.colorProperty(),
|
||||
fgColor.colorProperty(),
|
||||
bgBaseColor
|
||||
@ -97,6 +101,10 @@ final class ContrastChecker extends GridPane {
|
||||
setForeground(fgColor);
|
||||
}
|
||||
|
||||
public Color getBgBaseColor() {
|
||||
return bgBaseColor.get();
|
||||
}
|
||||
|
||||
public String getBgColorName() {
|
||||
return bgColorName;
|
||||
}
|
||||
@ -109,8 +117,9 @@ final class ContrastChecker extends GridPane {
|
||||
return bgColor.colorProperty().get();
|
||||
}
|
||||
|
||||
public Color getFgColor() {
|
||||
return fgColor.colorProperty().get();
|
||||
public Color getFlatBgColor() {
|
||||
double[] flatBg = JColorUtils.flattenColor(getBgBaseColor(), getBgColor());
|
||||
return Color.color(flatBg[0], flatBg[1], flatBg[2]);
|
||||
}
|
||||
|
||||
public ReadOnlyObjectProperty<Color> bgColorProperty() {
|
||||
@ -478,7 +487,7 @@ final class ContrastChecker extends GridPane {
|
||||
}
|
||||
|
||||
public float[] getRgbaArithmeticColor() {
|
||||
float[] hsl = new float[] {getHue(), getSaturation(), getLightness()};
|
||||
float[] hsl = new float[] { getHue(), getSaturation(), getLightness() };
|
||||
var color = JColor.color(hsl, getAlpha());
|
||||
return new float[] {
|
||||
color.getRedArithmetic(),
|
||||
@ -489,7 +498,7 @@ final class ContrastChecker extends GridPane {
|
||||
}
|
||||
|
||||
public String getColorHexWithAlpha() {
|
||||
float[] hsl = new float[] {getHue(), getSaturation(), getLightness()};
|
||||
float[] hsl = new float[] { getHue(), getSaturation(), getLightness() };
|
||||
return JColor.color(hsl, getAlpha()).getColorHexWithAlpha();
|
||||
}
|
||||
}
|
||||
@ -510,7 +519,7 @@ final class ContrastChecker extends GridPane {
|
||||
var hexItem = new MenuItem("Copy as HEX");
|
||||
hexItem.setOnAction(e -> {
|
||||
var c = JColor.color(
|
||||
new float[] {color.getHue(), color.getSaturation(), color.getLightness(), color.getAlpha()});
|
||||
new float[] { color.getHue(), color.getSaturation(), color.getLightness(), color.getAlpha() });
|
||||
PlatformUtils.copyToClipboard(color.getAlpha() < 1
|
||||
? toHexWithAlpha(color.getColor()) : c.getColorHex()
|
||||
);
|
||||
@ -519,7 +528,7 @@ final class ContrastChecker extends GridPane {
|
||||
var rgbItem = new MenuItem("Copy as RGB");
|
||||
rgbItem.setOnAction(e -> {
|
||||
var c = JColor.color(
|
||||
new float[] {color.getHue(), color.getSaturation(), color.getLightness(), color.getAlpha()});
|
||||
new float[] { color.getHue(), color.getSaturation(), color.getLightness(), color.getAlpha() });
|
||||
PlatformUtils.copyToClipboard(color.getAlpha() < 1
|
||||
? String.format(
|
||||
"rgba(%d,%d,%d, %.1f)", c.getGreen(), c.getGreen(), c.getBlue(), c.getAlphaArithmetic()
|
||||
|
@ -2,31 +2,32 @@
|
||||
|
||||
package atlantafx.sampler.page.general;
|
||||
|
||||
import atlantafx.sampler.layout.OverlayDialog;
|
||||
import atlantafx.sampler.layout.ModalDialog;
|
||||
import atlantafx.sampler.util.JColorUtils;
|
||||
import atlantafx.sampler.util.NodeUtils;
|
||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||
import javafx.scene.paint.Color;
|
||||
|
||||
class ContrastCheckerDialog extends OverlayDialog<ContrastChecker> {
|
||||
class ContrastCheckerDialog extends ModalDialog {
|
||||
|
||||
private final ContrastChecker contrastChecker;
|
||||
|
||||
public ContrastCheckerDialog(ReadOnlyObjectProperty<Color> bgBaseColor) {
|
||||
super();
|
||||
|
||||
this.contrastChecker = new ContrastChecker(bgBaseColor);
|
||||
|
||||
contrastChecker.bgColorProperty().addListener((obs, old, val) -> updateStyle());
|
||||
contrastChecker.fgColorProperty().addListener((obs, old, val) -> updateStyle());
|
||||
|
||||
getStyleClass().add("contrast-checker-dialog");
|
||||
setTitle("Contrast Checker");
|
||||
setContent(contrastChecker);
|
||||
NodeUtils.toggleVisibility(footerBox, false);
|
||||
header.setTitle("Contrast Checker");
|
||||
content.setBody(contrastChecker);
|
||||
content.setFooter(null);
|
||||
}
|
||||
|
||||
private void updateStyle() {
|
||||
setStyle(String.format("-color-dialog-bg:%s;-color-dialog-fg:%s;",
|
||||
JColorUtils.toHexWithAlpha(contrastChecker.getBgColor()),
|
||||
setStyle(String.format("-color-contrast-checker-bg:%s;-color-contrast-checker-fg:%s;",
|
||||
JColorUtils.toHexWithAlpha(contrastChecker.getFlatBgColor()),
|
||||
JColorUtils.toHexWithAlpha(contrastChecker.getSafeFgColor())
|
||||
));
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import atlantafx.base.theme.Styles;
|
||||
import atlantafx.sampler.Resources;
|
||||
import atlantafx.sampler.event.BrowseEvent;
|
||||
import atlantafx.sampler.event.DefaultEventBus;
|
||||
import atlantafx.sampler.layout.OverlayDialog;
|
||||
import atlantafx.sampler.layout.ModalDialog;
|
||||
import atlantafx.sampler.page.general.SceneBuilderDialogModel.Screen;
|
||||
import atlantafx.sampler.util.NodeUtils;
|
||||
import java.io.File;
|
||||
@ -46,7 +46,7 @@ import org.kordamp.ikonli.javafx.FontIcon;
|
||||
import org.kordamp.ikonli.material2.Material2AL;
|
||||
import org.kordamp.ikonli.material2.Material2OutlinedAL;
|
||||
|
||||
class SceneBuilderDialog extends OverlayDialog<DeckPane> {
|
||||
class SceneBuilderDialog extends ModalDialog {
|
||||
|
||||
private final DeckPane deck;
|
||||
private final Button backBtn;
|
||||
@ -62,6 +62,8 @@ class SceneBuilderDialog extends OverlayDialog<DeckPane> {
|
||||
private final SceneBuilderDialogModel model = new SceneBuilderDialogModel();
|
||||
|
||||
public SceneBuilderDialog() {
|
||||
super();
|
||||
|
||||
deck = createContent();
|
||||
|
||||
backBtn = new Button("Previous", new FontIcon(Material2AL.ARROW_BACK));
|
||||
@ -72,10 +74,17 @@ class SceneBuilderDialog extends OverlayDialog<DeckPane> {
|
||||
closeBtn = new Button("Close");
|
||||
NodeUtils.toggleVisibility(closeBtn, false);
|
||||
|
||||
footerBox.getChildren().setAll(backBtn, new Spacer(), forwardBtn, closeBtn);
|
||||
var footer = new HBox(10);
|
||||
footer.getChildren().setAll(backBtn, new Spacer(), forwardBtn, closeBtn);
|
||||
footer.getStyleClass().add("footer");
|
||||
footer.setAlignment(Pos.CENTER_RIGHT);
|
||||
VBox.setVgrow(footer, Priority.NEVER);
|
||||
|
||||
header.setTitle("SceneBuilder Integration");
|
||||
content.setBody(deck);
|
||||
content.setFooter(footer);
|
||||
content.setPrefSize(600, 440);
|
||||
|
||||
setTitle("SceneBuilder Integration");
|
||||
setContent(deck);
|
||||
init();
|
||||
}
|
||||
|
||||
@ -91,8 +100,6 @@ class SceneBuilderDialog extends OverlayDialog<DeckPane> {
|
||||
deck.setAnimationDuration(Duration.millis(250));
|
||||
deck.setId("scene-builder-wizard");
|
||||
|
||||
deck.setPrefSize(600, 440);
|
||||
|
||||
return deck;
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
package atlantafx.sampler.page.general;
|
||||
|
||||
import static atlantafx.sampler.event.ThemeEvent.EventType;
|
||||
import static atlantafx.sampler.theme.ThemeManager.DEFAULT_FONT_SIZE;
|
||||
|
||||
import atlantafx.base.theme.Styles;
|
||||
import atlantafx.base.util.BBCodeParser;
|
||||
@ -15,10 +16,8 @@ import atlantafx.sampler.theme.ThemeManager;
|
||||
import atlantafx.sampler.util.Lazy;
|
||||
import java.net.URI;
|
||||
import java.util.Objects;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.geometry.HPos;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ChoiceBox;
|
||||
@ -72,11 +71,12 @@ public final class ThemePage extends OutlinePage {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private final ReadOnlyObjectWrapper<Color> bgBaseColor = new ReadOnlyObjectWrapper<>(Color.WHITE);
|
||||
private final Lazy<ThemeRepoManagerDialog> themeRepoManagerDialog;
|
||||
private final Lazy<ContrastCheckerDialog> contrastCheckerDialog;
|
||||
private final Lazy<SceneBuilderDialog> sceneBuilderDialog;
|
||||
private final ColorPalette colorPalette;
|
||||
private final ColorScale colorScale = new ColorScale();
|
||||
private final ColorScale colorScale = new ColorScale(bgBaseColor);
|
||||
private final ChoiceBox<SamplerTheme> themeSelector = createThemeSelector();
|
||||
private final ComboBox<String> fontFamilyChooser = createFontFamilyChooser();
|
||||
private final Spinner<Integer> fontSizeSpinner = createFontSizeSpinner();
|
||||
@ -84,48 +84,35 @@ public final class ThemePage extends OutlinePage {
|
||||
public ThemePage() {
|
||||
super();
|
||||
|
||||
themeRepoManagerDialog = new Lazy<>(() -> {
|
||||
var dialog = new ThemeRepoManagerDialog();
|
||||
dialog.setClearOnClose(true);
|
||||
return dialog;
|
||||
});
|
||||
|
||||
contrastCheckerDialog = new Lazy<>(() -> {
|
||||
var dialog = new ContrastCheckerDialog(bgBaseColor);
|
||||
dialog.setClearOnClose(true);
|
||||
return dialog;
|
||||
});
|
||||
|
||||
sceneBuilderDialog = new Lazy<>(() -> {
|
||||
var dialog = new SceneBuilderDialog();
|
||||
dialog.setClearOnClose(true);
|
||||
dialog.setOnClose(dialog::reset);
|
||||
return dialog;
|
||||
});
|
||||
|
||||
colorPalette = new ColorPalette(colorBlock -> {
|
||||
ContrastCheckerDialog dialog = getContrastCheckerDialog();
|
||||
ContrastCheckerDialog dialog = contrastCheckerDialog.get();
|
||||
dialog.getContent().setValues(
|
||||
colorBlock.getFgColorName(),
|
||||
colorBlock.getFgColor(),
|
||||
colorBlock.getBgColorName(),
|
||||
colorBlock.getBgColor()
|
||||
);
|
||||
overlay.setContent(dialog, HPos.CENTER);
|
||||
overlay.toFront();
|
||||
});
|
||||
|
||||
themeRepoManagerDialog = new Lazy<>(() -> {
|
||||
var dialog = new ThemeRepoManagerDialog();
|
||||
dialog.setOnCloseRequest(() -> {
|
||||
overlay.removeContent();
|
||||
overlay.toBack();
|
||||
});
|
||||
|
||||
return dialog;
|
||||
});
|
||||
|
||||
contrastCheckerDialog = new Lazy<>(() -> {
|
||||
var dialog = new ContrastCheckerDialog(getBgBaseColorProperty());
|
||||
dialog.setOnCloseRequest(() -> {
|
||||
overlay.removeContent();
|
||||
overlay.toBack();
|
||||
});
|
||||
|
||||
return dialog;
|
||||
});
|
||||
|
||||
sceneBuilderDialog = new Lazy<>(() -> {
|
||||
var dialog = new SceneBuilderDialog();
|
||||
dialog.setOnCloseRequest(() -> {
|
||||
overlay.removeContent();
|
||||
overlay.toBack();
|
||||
dialog.reset();
|
||||
});
|
||||
|
||||
return dialog;
|
||||
});
|
||||
dialog.show(getScene());
|
||||
}, bgBaseColor);
|
||||
|
||||
DefaultEventBus.getInstance().subscribe(ThemeEvent.class, e -> {
|
||||
var eventType = e.getEventType();
|
||||
@ -136,16 +123,26 @@ public final class ThemePage extends OutlinePage {
|
||||
if (eventType == EventType.THEME_CHANGE || eventType == EventType.COLOR_CHANGE) {
|
||||
colorPalette.updateColorInfo(Duration.seconds(1));
|
||||
colorScale.updateColorInfo(Duration.seconds(1));
|
||||
fontFamilyChooser.getSelectionModel().select(DEFAULT_FONT_ID);
|
||||
fontSizeSpinner.getValueFactory().setValue(DEFAULT_FONT_SIZE);
|
||||
}
|
||||
});
|
||||
|
||||
// mandatory base bg for flatten color calc
|
||||
Styles.appendStyle(this, "-fx-background-color", "-color-bg-default");
|
||||
backgroundProperty().addListener(
|
||||
(obs, old, val) -> bgBaseColor.set(val != null && !val.getFills().isEmpty()
|
||||
? (Color) val.getFills().get(0).getFill()
|
||||
: Color.WHITE
|
||||
));
|
||||
|
||||
addPageHeader();
|
||||
addNode(createThemeManagementSection());
|
||||
addSection("Scene Builder", createSceneBuilderSection());
|
||||
addSection("Color Palette", createColorPaletteSection());
|
||||
addSection("Color Scale", createColorScaleSection());
|
||||
|
||||
Platform.runLater(this::selectCurrentTheme);
|
||||
//Platform.runLater(this::selectCurrentTheme);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -161,9 +158,8 @@ public final class ThemePage extends OutlinePage {
|
||||
themeRepoBtn.setTooltip(new Tooltip("Settings"));
|
||||
themeRepoBtn.setOnAction(e -> {
|
||||
ThemeRepoManagerDialog dialog = themeRepoManagerDialog.get();
|
||||
overlay.setContent(dialog, HPos.CENTER);
|
||||
dialog.getContent().update();
|
||||
overlay.toFront();
|
||||
dialog.show(getScene());
|
||||
});
|
||||
|
||||
var accentSelector = new AccentColorSelector();
|
||||
@ -185,8 +181,7 @@ public final class ThemePage extends OutlinePage {
|
||||
sceneBuilderBtn.setGraphic(new ImageView(SCENE_BUILDER_ICON));
|
||||
sceneBuilderBtn.setOnAction(e -> {
|
||||
SceneBuilderDialog dialog = sceneBuilderDialog.get();
|
||||
overlay.setContent(dialog, HPos.CENTER);
|
||||
overlay.toFront();
|
||||
dialog.show(getScene());
|
||||
});
|
||||
|
||||
var description = BBCodeParser.createFormattedText("""
|
||||
@ -231,7 +226,18 @@ public final class ThemePage extends OutlinePage {
|
||||
|
||||
private ChoiceBox<SamplerTheme> createThemeSelector() {
|
||||
var choiceBox = new ChoiceBox<SamplerTheme>();
|
||||
choiceBox.getItems().setAll(TM.getRepository().getAll());
|
||||
|
||||
var themes = TM.getRepository().getAll();
|
||||
choiceBox.getItems().setAll(themes);
|
||||
|
||||
// set initial value
|
||||
var currentTheme = Objects.requireNonNullElse(TM.getTheme(), TM.getDefaultTheme());
|
||||
themes.stream()
|
||||
.filter(t -> Objects.equals(currentTheme.getName(), t.getName()))
|
||||
.findFirst()
|
||||
.ifPresent(t -> choiceBox.getSelectionModel().select(t));
|
||||
|
||||
// must be after setting the initial value
|
||||
choiceBox.getSelectionModel().selectedItemProperty().addListener((obs, old, val) -> {
|
||||
if (val != null && getScene() != null) {
|
||||
TM.setTheme(val);
|
||||
@ -308,12 +314,4 @@ public final class ThemePage extends OutlinePage {
|
||||
.ifPresent(t -> themeSelector.getSelectionModel().select(t));
|
||||
}
|
||||
}
|
||||
|
||||
private ContrastCheckerDialog getContrastCheckerDialog() {
|
||||
return contrastCheckerDialog.get();
|
||||
}
|
||||
|
||||
private ReadOnlyObjectProperty<Color> getBgBaseColorProperty() {
|
||||
return colorPalette.bgBaseColorProperty();
|
||||
}
|
||||
}
|
||||
|
@ -3,25 +3,22 @@
|
||||
package atlantafx.sampler.page.general;
|
||||
|
||||
import atlantafx.base.theme.Styles;
|
||||
import atlantafx.sampler.layout.OverlayDialog;
|
||||
import atlantafx.sampler.layout.ModalDialog;
|
||||
import java.io.File;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.stage.FileChooser;
|
||||
import javafx.stage.FileChooser.ExtensionFilter;
|
||||
import org.kordamp.ikonli.javafx.FontIcon;
|
||||
import org.kordamp.ikonli.material2.Material2MZ;
|
||||
|
||||
class ThemeRepoManagerDialog extends OverlayDialog<ThemeRepoManager> {
|
||||
class ThemeRepoManagerDialog extends ModalDialog {
|
||||
|
||||
private final ThemeRepoManager repoManager = new ThemeRepoManager();
|
||||
|
||||
public ThemeRepoManagerDialog() {
|
||||
setId("theme-repo-manager-dialog");
|
||||
setTitle("Theme Manager");
|
||||
setContent(repoManager);
|
||||
super();
|
||||
|
||||
var addBtn = new Button("Add", new FontIcon(Material2MZ.PLUS));
|
||||
var addBtn = new Button("Add custom theme", new FontIcon(Material2MZ.PLUS));
|
||||
addBtn.getStyleClass().add(Styles.ACCENT);
|
||||
addBtn.setOnAction(e -> {
|
||||
var fileChooser = new FileChooser();
|
||||
@ -32,8 +29,15 @@ class ThemeRepoManagerDialog extends OverlayDialog<ThemeRepoManager> {
|
||||
}
|
||||
});
|
||||
|
||||
footerBox.getChildren().add(0, addBtn);
|
||||
footerBox.setAlignment(Pos.CENTER_LEFT);
|
||||
setId("theme-repo-manager-dialog");
|
||||
header.setTitle("Theme Manager");
|
||||
content.setBody(repoManager);
|
||||
content.setMinSize(800, 500);
|
||||
content.setMaxSize(800, 500);
|
||||
|
||||
var footer = createDefaultFooter();
|
||||
footer.getChildren().add(0, addBtn);
|
||||
content.setFooter(footer);
|
||||
}
|
||||
|
||||
public ThemeRepoManager getContent() {
|
||||
|
@ -26,7 +26,6 @@ record MediaFile(File file) {
|
||||
// is costly and that instance is not even reusable.
|
||||
public void readMetadata(Consumer<Metadata> callback) {
|
||||
var media = new Media(file.toURI().toString());
|
||||
System.out.println(file.toURI().toString());
|
||||
var mediaPlayer = new MediaPlayer(media);
|
||||
|
||||
// The media information is obtained asynchronously and so not necessarily
|
||||
|
@ -4,4 +4,3 @@
|
||||
@use "root";
|
||||
@use "main";
|
||||
@use "sidebar";
|
||||
@use "overlay";
|
||||
|
@ -1,33 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
.overlay {
|
||||
-fx-background-color: transparent;
|
||||
|
||||
>.scroll-pane {
|
||||
>.viewport {
|
||||
>* {
|
||||
>.scrollable-content {
|
||||
-fx-background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.overlay-dialog {
|
||||
-fx-background-color: -color-bg-default;
|
||||
-fx-background-radius: 5px;
|
||||
-fx-border-radius: 5px;
|
||||
-fx-border-width: 1px;
|
||||
-fx-border-color: -color-border-default;
|
||||
|
||||
>.header {
|
||||
-fx-padding: 10px 5px 5px 20px;
|
||||
}
|
||||
|
||||
>.footer {
|
||||
-fx-border-width: 1 0 0 0;
|
||||
-fx-border-color: -color-border-default;
|
||||
-fx-padding: 10px 20px 10px 20px;
|
||||
}
|
||||
}
|
@ -22,7 +22,6 @@
|
||||
}
|
||||
|
||||
.page {
|
||||
|
||||
>.scroll-pane .user-content {
|
||||
-fx-padding: 0;
|
||||
|
||||
@ -67,4 +66,13 @@
|
||||
@include ac.primerCoralDark();
|
||||
}
|
||||
}
|
||||
|
||||
.modal-dialog {
|
||||
-fx-background-color: transparent;
|
||||
|
||||
.card {
|
||||
-fx-border-width: 0;
|
||||
-fx-padding: 10px 20px 10px 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,6 @@
|
||||
-fx-hgap: 20px;
|
||||
-fx-vgap: 20px;
|
||||
|
||||
// mandatory base bg for flatten color calc
|
||||
-fx-background-color: -color-bg-default;
|
||||
|
||||
>.column {
|
||||
>.cell {
|
||||
-fx-text-fill: -color-fg-default;
|
||||
|
@ -4,10 +4,8 @@
|
||||
|
||||
.contrast-checker {
|
||||
|
||||
-fx-background-color: -color-contrast-checker-bg;
|
||||
-fx-hgap: 40px;
|
||||
-fx-vgap: 20px;
|
||||
-fx-padding: 20px;
|
||||
|
||||
.label {
|
||||
-fx-text-fill: -color-contrast-checker-fg;
|
||||
@ -118,20 +116,17 @@
|
||||
-color-dialog-bg: white;
|
||||
-color-dialog-fg: black;
|
||||
|
||||
>.header {
|
||||
-fx-background-color: -color-dialog-bg;
|
||||
-color-dialog-pane-bg: -color-contrast-checker-bg;
|
||||
-color-dialog-pane-close-fg: -color-contrast-checker-fg;
|
||||
-color-dialog-pane-close-bg-hover: derive(-color-contrast-checker-bg, 30%);
|
||||
|
||||
>.title {
|
||||
-fx-text-fill: -color-dialog-fg;
|
||||
}
|
||||
-fx-background-color: transparent;
|
||||
|
||||
>.close-button {
|
||||
-color-button-fg: -color-dialog-fg;
|
||||
-color-button-bg-hover: derive(-color-dialog-bg, 30%);
|
||||
-color-button-border-hover: transparent;
|
||||
-color-button-border-focused: transparent;
|
||||
.card {
|
||||
-fx-background-color: -color-contrast-checker-bg;
|
||||
|
||||
.title {
|
||||
-fx-text-fill: -color-contrast-checker-fg;
|
||||
}
|
||||
}
|
||||
|
||||
-fx-border-color: -color-dialog-bg;
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
@use "color-palette" as palette;
|
||||
|
||||
#theme-repo-manager {
|
||||
-fx-padding: 10px 20px 10px 20px;
|
||||
-fx-spacing: 10px;
|
||||
|
||||
>.info {
|
||||
@ -70,10 +69,3 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#theme-repo-manager-dialog {
|
||||
-fx-min-width: 800px;
|
||||
-fx-pref-width: 800px;
|
||||
-fx-min-height: 500px;
|
||||
-fx-max-height: 500px;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user