Modal pane improvements

This commit is contained in:
crschnick 2023-05-17 15:03:51 +00:00
parent f8f1b90581
commit 21da5bd828
12 changed files with 123 additions and 135 deletions

View file

@ -0,0 +1,44 @@
package io.xpipe.app.comp.base;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.SimpleComp;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.control.TextArea;
import javafx.scene.layout.Region;
import lombok.AccessLevel;
import lombok.experimental.FieldDefaults;
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
public class ErrorOverlayComp extends SimpleComp {
Comp<?> background;
Property<String> text;
public ErrorOverlayComp(Comp<?> background, Property<String> text) {
this.background = background;
this.text = text;
}
@Override
protected Region createSimple() {
var content = new SimpleObjectProperty<ModalOverlayComp.OverlayContent>();
this.text.addListener((observable, oldValue, newValue) -> {
var comp = Comp.of(() -> {
var l = new TextArea();
l.textProperty().bind(text);
l.setWrapText(true);
l.getStyleClass().add("error-overlay-comp");
l.setEditable(false);
return l;
});
content.set(new ModalOverlayComp.OverlayContent("error", comp, null, () -> {}));
});
content.addListener((observable, oldValue, newValue) -> {
if (newValue == null) {
this.text.setValue(null);
}
});
return new ModalOverlayComp(background, content).createRegion();
}
}

View file

@ -1,77 +0,0 @@
package io.xpipe.app.comp.base;
import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.fxcomps.util.PlatformThread;
import io.xpipe.app.fxcomps.util.SimpleChangeListener;
import io.xpipe.app.util.ThreadHelper;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.TextArea;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import lombok.AccessLevel;
import lombok.experimental.FieldDefaults;
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
public class MessageComp extends SimpleComp {
Property<Boolean> shown = new SimpleBooleanProperty();
ObservableValue<String> text;
int msShown;
public MessageComp(ObservableValue<String> text, int msShown) {
this.text = PlatformThread.sync(text);
this.msShown = msShown;
}
public void show() {
shown.setValue(true);
if (msShown != -1) {
ThreadHelper.runAsync(() -> {
try {
Thread.sleep(msShown);
} catch (InterruptedException ignored) {
}
shown.setValue(false);
});
}
}
@Override
protected Region createSimple() {
var l = new TextArea();
l.textProperty().bind(text);
l.setWrapText(true);
l.getStyleClass().add("message");
l.setEditable(false);
var sp = new StackPane(l);
sp.getStyleClass().add("message-comp");
SimpleChangeListener.apply(PlatformThread.sync(shown), n -> {
if (n) {
l.setMinHeight(Region.USE_PREF_SIZE);
l.setPrefHeight(Region.USE_COMPUTED_SIZE);
l.setMaxHeight(Region.USE_PREF_SIZE);
sp.setMinHeight(Region.USE_PREF_SIZE);
sp.setPrefHeight(Region.USE_COMPUTED_SIZE);
sp.setMaxHeight(Region.USE_PREF_SIZE);
} else {
l.setMinHeight(0);
l.setPrefHeight(0);
l.setMaxHeight(0);
sp.setMinHeight(0);
sp.setPrefHeight(0);
sp.setMaxHeight(0);
}
});
return sp;
}
}

View file

@ -2,12 +2,12 @@ package io.xpipe.app.comp.base;
import atlantafx.base.controls.ModalPane;
import atlantafx.base.theme.Styles;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.fxcomps.util.PlatformThread;
import io.xpipe.app.fxcomps.util.Shortcuts;
import javafx.beans.property.Property;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
@ -33,8 +33,9 @@ public class ModalOverlayComp extends SimpleComp {
@Value
public static class OverlayContent {
ObservableValue<String> title;
String titleKey;
Comp<?> content;
String finishKey;
Runnable onFinish;
}
@ -45,6 +46,7 @@ public class ModalOverlayComp extends SimpleComp {
protected Region createSimple() {
var bgRegion = background.createRegion();
var modal = new ModalPane();
modal.getStyleClass().add("modal-overlay-comp");
var pane = new StackPane(bgRegion, modal);
pane.setPickOnBounds(false);
PlatformThread.sync(overlayContent).addListener((observable, oldValue, newValue) -> {
@ -54,23 +56,26 @@ public class ModalOverlayComp extends SimpleComp {
if (newValue != null) {
var r = newValue.content.createRegion();
var finishButton = new Button("Finish");
Styles.toggleStyleClass(finishButton, Styles.FLAT);
finishButton.setOnAction(event -> {
newValue.onFinish.run();
overlayContent.setValue(null);
});
var buttonBar = new ButtonBar();
buttonBar.getButtons().addAll(finishButton);
var box = new VBox(r, buttonBar);
var box = new VBox(r);
box.setSpacing(15);
box.setPadding(new Insets(15));
var tp = new TitledPane(newValue.title.getValue(), box);
if (newValue.finishKey != null) {
var finishButton = new Button(AppI18n.get(newValue.finishKey));
Styles.toggleStyleClass(finishButton, Styles.FLAT);
finishButton.setOnAction(event -> {
newValue.onFinish.run();
overlayContent.setValue(null);
});
var buttonBar = new ButtonBar();
buttonBar.getButtons().addAll(finishButton);
box.getChildren().add(buttonBar);
}
var tp = new TitledPane(AppI18n.get(newValue.titleKey), box);
tp.setMaxWidth(400);
tp.setCollapsible(false);
tp.getStyleClass().add("elevated-3");
var closeButton = new Button(null, new FontIcon("mdi2w-window-close"));
closeButton.setOnAction(event -> {
@ -84,6 +89,7 @@ public class ModalOverlayComp extends SimpleComp {
AnchorPane.setRightAnchor(closeButton, 10.0);
var stack = new StackPane(tp, close);
stack.setPadding(new Insets(10));
stack.setOnMouseClicked(event -> {
if (overlayContent.getValue() != null) {
overlayContent.setValue(null);

View file

@ -1,7 +1,6 @@
package io.xpipe.app.comp.source.store;
import io.xpipe.app.comp.base.InstallExtensionComp;
import io.xpipe.app.comp.base.MessageComp;
import io.xpipe.app.comp.base.ErrorOverlayComp;
import io.xpipe.app.comp.base.MultiStepComp;
import io.xpipe.app.core.AppExtensionManager;
import io.xpipe.app.core.AppFont;
@ -9,7 +8,6 @@ import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppWindowHelper;
import io.xpipe.app.core.mode.OperationMode;
import io.xpipe.app.ext.DataStoreProvider;
import io.xpipe.app.ext.DownloadModuleInstall;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.CompStructure;
import io.xpipe.app.fxcomps.augment.GrowAugment;
@ -25,6 +23,7 @@ import io.xpipe.app.util.*;
import io.xpipe.core.store.DataStore;
import javafx.application.Platform;
import javafx.beans.property.*;
import javafx.geometry.Insets;
import javafx.scene.control.Alert;
import javafx.scene.control.Separator;
import javafx.scene.layout.BorderPane;
@ -48,7 +47,6 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
BooleanProperty busy = new SimpleBooleanProperty();
Property<Validator> validator = new SimpleObjectProperty<>(new SimpleValidator());
Property<String> messageProp = new SimpleStringProperty();
MessageComp message = new MessageComp(messageProp, 10000);
BooleanProperty finished = new SimpleBooleanProperty();
Property<DataStoreEntry> entry = new SimpleObjectProperty<>();
BooleanProperty changedSinceError = new SimpleBooleanProperty();
@ -188,7 +186,14 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
@Override
public CompStructure<? extends Region> createBase() {
var back = Comp.of(this::createLayout);
var message = new ErrorOverlayComp(back, messageProp);
return message.createStructure();
}
private Region createLayout() {
var layout = new BorderPane();
layout.setPadding(new Insets(20));
var providerChoice = new DsStoreProviderChoiceComp(filter, provider);
if (provider.getValue() != null) {
providerChoice.apply(struc -> struc.get().setDisable(true));
@ -197,37 +202,33 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
SimpleChangeListener.apply(provider, n -> {
if (n != null) {
var install = n.getRequiredAdditionalInstallation();
if (install != null && AppExtensionManager.getInstance().isInstalled(install)) {
layout.setCenter(new InstallExtensionComp((DownloadModuleInstall) install).createRegion());
validator.setValue(new SimpleValidator());
return;
}
// var install = n.getRequiredAdditionalInstallation();
// if (install != null && AppExtensionManager.getInstance().isInstalled(install)) {
// layout.setCenter(new InstallExtensionComp((DownloadModuleInstall)
// install).createRegion());
// validator.setValue(new SimpleValidator());
// return;
// }
var d = n.guiDialog(input);
var propVal = new SimpleValidator();
var propR = createStoreProperties(d == null || d.getComp() == null ? null : d.getComp(), propVal);
var box = new VBox(propR);
box.setSpacing(7);
layout.setCenter(propR);
layout.setCenter(box);
validator.setValue(new ChainedValidator(List.of(d != null && d.getValidator() != null ? d.getValidator() : new SimpleValidator(), propVal)));
validator.setValue(new ChainedValidator(List.of(
d != null && d.getValidator() != null ? d.getValidator() : new SimpleValidator(), propVal)));
} else {
layout.setCenter(null);
validator.setValue(new SimpleValidator());
}
});
layout.setBottom(message.createRegion());
var sep = new Separator();
sep.getStyleClass().add("spacer");
var top = new VBox(providerChoice.createRegion(), sep);
top.getStyleClass().add("top");
layout.setTop(top);
// layout.getStyleClass().add("data-input-creation-step");
return Comp.of(() -> layout).createStructure();
return layout;
}
@Override
@ -275,7 +276,6 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
.getText();
TrackEvent.info(msg);
messageProp.setValue(msg);
message.show();
changedSinceError.setValue(false);
return false;
}
@ -287,7 +287,6 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
PlatformThread.runLaterIfNeeded(parent::next);
} catch (Exception ex) {
messageProp.setValue(ExceptionConverter.convertMessage(ex));
message.show();
changedSinceError.setValue(false);
ErrorEvent.fromThrowable(ex).omit().reportable(false).handle();
}

View file

@ -42,7 +42,7 @@ public class TranslatableComboBoxControl<V extends Translatable>
readOnlyLabel.getStyleClass().add("read-only-label");
comboBox.setMaxWidth(Double.MAX_VALUE);
comboBox.setVisibleRowCount(4);
comboBox.setVisibleRowCount(10);
node.setAlignment(Pos.CENTER_LEFT);
node.getChildren().addAll(comboBox, readOnlyLabel);

View file

@ -9,6 +9,9 @@ setLock=Set lock
changeLock=Change lock
lockCreationAlertTitle=Create Lock
lockCreationAlertHeader=Set your new lock password
finish=Finish
error=Error
ok=Ok
password=Password
unlockAlertTitle=Unlock workspace
unlockAlertHeader=Enter your lock password to continue

View file

@ -1,5 +1,5 @@
.step {
-fx-padding: 1em 1.5em 0.5em 1.5em;
-fx-padding: 0;
}
.spacer {

View file

@ -0,0 +1,5 @@
.error-overlay-comp {
-fx-padding: 1.0em;
-fx-border-width: 1px;
-fx-border-radius: 2px;
}

View file

@ -0,0 +1,20 @@
.modal-overlay-comp .titled-pane {
-fx-font-size: 1.6em;
-fx-padding: 0;
-fx-border-radius: 0;
}
.modal-overlay-comp {
-fx-border-radius: 0;
-fx-background-radius: 0;
}
.modal-overlay-comp .titled-pane > * {
-fx-font-size: 1.0em;
-fx-border-radius: 0;
}
.modal-overlay-comp .titled-pane > * {
-fx-background-radius: 0;
}

View file

@ -80,3 +80,7 @@
-fx-pref-height: 0;
}
.multi-step-comp > .jfx-tab-pane .tab-content-area {
-fx-padding: 0;
}

View file

@ -13,21 +13,6 @@
-fx-padding: 1.2em;
}
.message-comp {
-fx-background-color: #FF9999AA;
-fx-border-width: 1px;
-fx-border-color:-color-accent-fg;
-fx-border-radius: 2px;
}
.message {
-fx-padding: 0.0em;
-fx-background-color: transparent;
-fx-border-width: 1px;
-fx-border-color:-color-accent-fg;
-fx-border-radius: 2px;
}
.radio-button {
-fx-background-color:transparent;
}

View file

@ -7,7 +7,6 @@ import io.xpipe.app.browser.action.BrowserAction;
import io.xpipe.app.browser.action.LeafAction;
import io.xpipe.app.browser.icon.FileBrowserIcons;
import io.xpipe.app.comp.base.ModalOverlayComp;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.fxcomps.Comp;
import javafx.beans.property.SimpleStringProperty;
import javafx.scene.Node;
@ -55,11 +54,11 @@ public class NewItemAction implements BrowserAction, BranchAction {
@Override
public void execute(OpenFileSystemModel model, List<FileBrowserEntry> entries) throws Exception {
var name = new SimpleStringProperty();
model.getOverlay().setValue(new ModalOverlayComp.OverlayContent(AppI18n.observable("newFile"), Comp.of(() -> {
model.getOverlay().setValue(new ModalOverlayComp.OverlayContent("newFile", Comp.of(() -> {
var creationName = new TextField();
creationName.textProperty().bindBidirectional(name);
return creationName;
}), () -> {
}), "finish", () -> {
model.createFileAsync(name.getValue());
}));
}
@ -78,11 +77,11 @@ public class NewItemAction implements BrowserAction, BranchAction {
@Override
public void execute(OpenFileSystemModel model, List<FileBrowserEntry> entries) throws Exception {
var name = new SimpleStringProperty();
model.getOverlay().setValue(new ModalOverlayComp.OverlayContent(AppI18n.observable("newDirectory"), Comp.of(() -> {
model.getOverlay().setValue(new ModalOverlayComp.OverlayContent("newDirectory", Comp.of(() -> {
var creationName = new TextField();
creationName.textProperty().bindBidirectional(name);
return creationName;
}), () -> {
}), "finish", () -> {
model.createDirectoryAsync(name.getValue());
}));
}