mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-09-15 08:48:04 +12:00
Modal pane improvements
This commit is contained in:
parent
f8f1b90581
commit
21da5bd828
12 changed files with 123 additions and 135 deletions
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.step {
|
||||
-fx-padding: 1em 1.5em 0.5em 1.5em;
|
||||
-fx-padding: 0;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
.error-overlay-comp {
|
||||
-fx-padding: 1.0em;
|
||||
-fx-border-width: 1px;
|
||||
-fx-border-radius: 2px;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -80,3 +80,7 @@
|
|||
-fx-pref-height: 0;
|
||||
}
|
||||
|
||||
.multi-step-comp > .jfx-tab-pane .tab-content-area {
|
||||
-fx-padding: 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue