diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index dcba32bcb19..f9ce7516f61 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -158,8 +158,8 @@ shared.tradeAmount=Trade amount shared.tradeVolume=Trade volume shared.invalidKey=The key you entered was not correct. shared.enterPrivKey=Enter private key to unlock: -shared.makerFeeTxId=Maker fee transaction ID: -shared.takerFeeTxId=Taker fee transaction ID: +shared.makerFeeTxId=Maker fee transaction ID +shared.takerFeeTxId=Taker fee transaction ID shared.payoutTxId=Payout transaction ID: shared.contractAsJson=Contract in JSON format: shared.viewContractAsJson=View contract in JSON format @@ -175,7 +175,7 @@ shared.unlock=Unlock shared.toReceive=to receive shared.toSpend=to spend shared.btcAmount=BTC amount -shared.yourLanguage=Your languages: +shared.yourLanguage=Your languages shared.addLanguage=Add language shared.total=Total shared.totalsNeeded=Funds needed diff --git a/desktop/src/main/java/bisq/desktop/bisq.css b/desktop/src/main/java/bisq/desktop/bisq.css index e573e319a99..b9c47edf3aa 100644 --- a/desktop/src/main/java/bisq/desktop/bisq.css +++ b/desktop/src/main/java/bisq/desktop/bisq.css @@ -1187,24 +1187,6 @@ textfield */ -fx-padding: 15 5 0 5; } -#currency-info-label { - -fx-border-radius: 0 4 4 0; - -fx-padding: 4 4 4 4; - -fx-background-color: -bs-rd-grey-background-bottom; - -fx-border-color: -bs-medium-grey; - -fx-border-style: solid solid solid none; - -fx-border-insets: 0 0 0 -2; -} - -#currency-info-label-disabled { - -fx-border-radius: 0 4 4 0; - -fx-padding: 4 4 4 4; - -fx-background-color: -bs-bg-grey7; - -fx-border-color: -bs-bg-grey7; - -fx-border-style: solid solid solid none; - -fx-border-insets: 0 0 0 -2; -} - #toggle-price-left { -fx-border-radius: 4 0 0 4; -fx-padding: 4 4 4 4; diff --git a/desktop/src/main/java/bisq/desktop/components/InfoInputTextField.java b/desktop/src/main/java/bisq/desktop/components/InfoInputTextField.java index 1215937dc8a..1630a6a0fd1 100644 --- a/desktop/src/main/java/bisq/desktop/components/InfoInputTextField.java +++ b/desktop/src/main/java/bisq/desktop/components/InfoInputTextField.java @@ -141,6 +141,10 @@ public String getText() { return text.get(); } + public final StringProperty textProperty() { + return text; + } + /////////////////////////////////////////////////////////////////////////////////////////// // Private diff --git a/desktop/src/main/java/bisq/desktop/main/account/AccountView.java b/desktop/src/main/java/bisq/desktop/main/account/AccountView.java index c991be418e7..e03ef4f1718 100644 --- a/desktop/src/main/java/bisq/desktop/main/account/AccountView.java +++ b/desktop/src/main/java/bisq/desktop/main/account/AccountView.java @@ -53,6 +53,10 @@ import javafx.event.EventHandler; +import javafx.collections.ListChangeListener; + +import java.util.List; + @FxmlView public class AccountView extends ActivatableView { @@ -70,6 +74,7 @@ public class AccountView extends ActivatableView { private ArbitratorRegistrationView arbitratorRegistrationView; private Scene scene; private EventHandler keyEventEventHandler; + private ListChangeListener tabListChangeListener; @Inject private AccountView(CachingViewLoader viewLoader, Navigation navigation) { @@ -80,6 +85,8 @@ private AccountView(CachingViewLoader viewLoader, Navigation navigation) { @Override public void initialize() { + root.setTabClosingPolicy(TabPane.TabClosingPolicy.ALL_TABS); + fiatAccountsTab.setText(Res.get("account.menu.paymentAccount").toUpperCase()); altcoinAccountsTab.setText(Res.get("account.menu.altCoinsAccountView").toUpperCase()); notificationTab.setText(Res.get("account.menu.notifications").toUpperCase()); @@ -100,13 +107,17 @@ public void initialize() { if (Utilities.isAltOrCtrlPressed(KeyCode.R, event) && arbitratorRegistrationTab == null) { arbitratorRegistrationTab = new Tab(Res.get("account.tab.arbitratorRegistration").toUpperCase()); - arbitratorRegistrationTab.setClosable(false); + arbitratorRegistrationTab.setClosable(true); root.getTabs().add(arbitratorRegistrationTab); + + navigation.navigateTo(MainView.class, AccountView.class, ArbitratorRegistrationView.class); } }; tabChangeListener = (ov, oldValue, newValue) -> { - if (newValue == fiatAccountsTab) { + if (arbitratorRegistrationTab != null) { + navigation.navigateTo(MainView.class, AccountView.class, ArbitratorRegistrationView.class); + } else if (newValue == fiatAccountsTab) { navigation.navigateTo(MainView.class, AccountView.class, FiatAccountsView.class); } else if (newValue == altcoinAccountsTab) { navigation.navigateTo(MainView.class, AccountView.class, AltCoinAccountsView.class); @@ -118,19 +129,33 @@ public void initialize() { navigation.navigateTo(MainView.class, AccountView.class, SeedWordsView.class); } else if (newValue == backupTab) { navigation.navigateTo(MainView.class, AccountView.class, BackupView.class); - } else if (newValue == arbitratorRegistrationTab) { - navigation.navigateTo(MainView.class, AccountView.class, ArbitratorRegistrationView.class); } else { navigation.navigateTo(MainView.class, AccountView.class, FiatAccountsView.class); } }; + + tabListChangeListener = change -> { + change.next(); + List removedTabs = change.getRemoved(); + if (removedTabs.size() == 1 && removedTabs.get(0).equals(arbitratorRegistrationTab)) + onArbitratorRegistrationTabRemoved(); + }; + } + + private void onArbitratorRegistrationTabRemoved() { + arbitratorRegistrationTab = null; + + navigation.navigateTo(MainView.class, AccountView.class, FiatAccountsView.class); } @SuppressWarnings("PointlessBooleanExpression") @Override protected void activate() { navigation.addListener(navigationListener); + root.getSelectionModel().selectedItemProperty().addListener(tabChangeListener); + root.getTabs().addListener(tabListChangeListener); + scene = root.getScene(); if (scene != null) scene.addEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler); @@ -168,6 +193,7 @@ else if (root.getSelectionModel().getSelectedItem() == backupTab) protected void deactivate() { navigation.removeListener(navigationListener); root.getSelectionModel().selectedItemProperty().removeListener(tabChangeListener); + root.getTabs().removeListener(tabListChangeListener); if (scene != null) scene.removeEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler); diff --git a/desktop/src/main/java/bisq/desktop/main/account/arbitratorregistration/ArbitratorRegistrationView.java b/desktop/src/main/java/bisq/desktop/main/account/arbitratorregistration/ArbitratorRegistrationView.java index ccabf67feef..2ea0418b8ec 100644 --- a/desktop/src/main/java/bisq/desktop/main/account/arbitratorregistration/ArbitratorRegistrationView.java +++ b/desktop/src/main/java/bisq/desktop/main/account/arbitratorregistration/ArbitratorRegistrationView.java @@ -34,6 +34,7 @@ import bisq.core.locale.Res; import bisq.common.UserThread; +import bisq.common.util.Tuple2; import bisq.common.util.Tuple3; import com.google.inject.name.Named; @@ -53,7 +54,6 @@ import javafx.scene.layout.Priority; import javafx.scene.layout.VBox; -import javafx.geometry.HPos; import javafx.geometry.Insets; import javafx.geometry.VPos; @@ -64,8 +64,7 @@ import javafx.util.Callback; import javafx.util.StringConverter; -import static bisq.desktop.util.FormBuilder.addButton; -import static bisq.desktop.util.FormBuilder.addButtonAfterGroup; +import static bisq.desktop.util.FormBuilder.add2ButtonsAfterGroup; import static bisq.desktop.util.FormBuilder.addMultilineLabel; import static bisq.desktop.util.FormBuilder.addTitledGroupBg; @@ -142,12 +141,10 @@ private void buildUI() { gridPane.setHgap(5); gridPane.setVgap(5); ColumnConstraints columnConstraints1 = new ColumnConstraints(); - columnConstraints1.setHalignment(HPos.RIGHT); columnConstraints1.setHgrow(Priority.SOMETIMES); columnConstraints1.setMinWidth(200); - ColumnConstraints columnConstraints2 = new ColumnConstraints(); - columnConstraints2.setHgrow(Priority.ALWAYS); - gridPane.getColumnConstraints().addAll(columnConstraints1, columnConstraints2); + columnConstraints1.setMaxWidth(500); + gridPane.getColumnConstraints().addAll(columnConstraints1); root.getChildren().add(gridPane); addTitledGroupBg(gridPane, gridRow, 3, Res.get("account.tab.arbitratorRegistration")); @@ -162,10 +159,10 @@ private void buildUI() { languagesListView.disableProperty().bind(model.registrationEditDisabled); languagesListView.setMinHeight(3 * Layout.LIST_ROW_HEIGHT + 2); languagesListView.setMaxHeight(6 * Layout.LIST_ROW_HEIGHT + 2); - languagesListView.setCellFactory(new Callback, ListCell>() { + languagesListView.setCellFactory(new Callback<>() { @Override public ListCell call(ListView list) { - return new ListCell() { + return new ListCell<>() { final Label label = new AutoTooltipLabel(); final ImageView icon = ImageUtil.getImageViewById(ImageUtil.REMOVE_ICON); final Button removeButton = new AutoTooltipButton("", icon); @@ -192,10 +189,10 @@ public void updateItem(final String item, boolean empty) { } }); - languageComboBox = FormBuilder.addComboBox(gridPane, ++gridRow); + languageComboBox = FormBuilder.addComboBox(gridPane, ++gridRow); languageComboBox.disableProperty().bind(model.registrationEditDisabled); languageComboBox.setPromptText(Res.get("shared.addLanguage")); - languageComboBox.setConverter(new StringConverter() { + languageComboBox.setConverter(new StringConverter<>() { @Override public String toString(String code) { return LanguageUtil.getDisplayName(code); @@ -208,11 +205,12 @@ public String fromString(String s) { }); languageComboBox.setOnAction(e -> onAddLanguage()); - Button registerButton = addButtonAfterGroup(gridPane, ++gridRow, Res.get("account.arbitratorRegistration.register")); + final Tuple2 buttonButtonTuple2 = add2ButtonsAfterGroup(gridPane, ++gridRow, Res.get("account.arbitratorRegistration.register"), Res.get("account.arbitratorRegistration.revoke")); + Button registerButton = buttonButtonTuple2.first; registerButton.disableProperty().bind(model.registrationEditDisabled); registerButton.setOnAction(e -> onRegister()); - Button revokeButton = addButton(gridPane, ++gridRow, Res.get("account.arbitratorRegistration.revoke")); + Button revokeButton = buttonButtonTuple2.second; revokeButton.setDefaultButton(false); revokeButton.disableProperty().bind(model.revokeButtonDisabled); revokeButton.setOnAction(e -> onRevoke()); diff --git a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferView.java b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferView.java index 7f489f8f151..8ac64506f18 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferView.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferView.java @@ -42,7 +42,6 @@ import bisq.desktop.main.overlays.windows.QRCodeWindow; import bisq.desktop.main.portfolio.PortfolioView; import bisq.desktop.main.portfolio.openoffer.OpenOffersView; -import bisq.desktop.util.FormBuilder; import bisq.desktop.util.GUIUtil; import bisq.desktop.util.Layout; import bisq.desktop.util.Transitions; @@ -134,7 +133,7 @@ public abstract class MutableOfferView extends private ScrollPane scrollPane; protected GridPane gridPane; private TitledGroupBg payFundsTitledGroupBg, setDepositTitledGroupBg, paymentTitledGroupBg; - private JFXSpinner waitingForFundsBusyAnimation; + private JFXSpinner waitingForFundsSpinner; private AutoTooltipButton nextButton, cancelButton1, cancelButton2, placeOfferButton; private Button priceTypeToggleButton; private InputTextField buyerSecurityDepositInputTextField, fixedPriceTextField, marketBasedPriceTextField; @@ -158,7 +157,7 @@ public abstract class MutableOfferView extends currencyTextFieldBox; private HBox fundingHBox, firstRowHBox, secondRowHBox, placeOfferBox, amountValueCurrencyBox, priceAsPercentageValueCurrencyBox, volumeValueCurrencyBox, priceValueCurrencyBox, - minAmountValueCurrencyBox, advancedOptionsBox; + minAmountValueCurrencyBox, advancedOptionsBox, paymentGroupBox; private Subscription isWaitingForFundsSubscription, balanceSubscription, cancelButton2StyleSubscription; private ChangeListener amountFocusedListener, minAmountFocusedListener, volumeFocusedListener, @@ -236,8 +235,8 @@ protected void doActivate() { addListeners(); addSubscriptions(); - if (waitingForFundsBusyAnimation != null) - waitingForFundsBusyAnimation.setProgress(-1); + if (waitingForFundsSpinner != null) + waitingForFundsSpinner.setProgress(-1); //directionLabel.setText(model.getDirectionLabel()); amountDescriptionLabel.setText(model.getAmountDescription()); @@ -280,8 +279,8 @@ protected void deactivate() { removeListeners(); removeSubscriptions(); - if (waitingForFundsBusyAnimation != null) - waitingForFundsBusyAnimation.setProgress(0); + if (waitingForFundsSpinner != null) + waitingForFundsSpinner.setProgress(0); } } @@ -456,7 +455,7 @@ private void onShowPayFundsScreen() { .show(); } - waitingForFundsBusyAnimation.setProgress(-1); + waitingForFundsSpinner.setProgress(-1); payFundsTitledGroupBg.setVisible(true); totalToPayTextField.setVisible(true); @@ -660,7 +659,7 @@ private void removeBindings() { private void addSubscriptions() { isWaitingForFundsSubscription = EasyBind.subscribe(model.isWaitingForFunds, isWaitingForFunds -> { - waitingForFundsBusyAnimation.setProgress(isWaitingForFunds ? -1 : 0); + waitingForFundsSpinner.setProgress(isWaitingForFunds ? -1 : 0); waitingForFundsLabel.setVisible(isWaitingForFunds); waitingForFundsLabel.setManaged(isWaitingForFunds); }); @@ -944,23 +943,23 @@ private void addPaymentGroup() { paymentTitledGroupBg = addTitledGroupBg(gridPane, gridRow, 1, Res.get("shared.selectTradingAccount")); GridPane.setColumnSpan(paymentTitledGroupBg, 2); - HBox hBox = new HBox(); - hBox.setAlignment(Pos.CENTER_LEFT); - hBox.setSpacing(62); - hBox.setPadding(new Insets(10, 0, 18, 0)); + paymentGroupBox = new HBox(); + paymentGroupBox.setAlignment(Pos.CENTER_LEFT); + paymentGroupBox.setSpacing(62); + paymentGroupBox.setPadding(new Insets(10, 0, 18, 0)); - final Tuple3> tradingAccountBoxTuple = FormBuilder.addTopLabelComboBox( + final Tuple3> tradingAccountBoxTuple = addTopLabelComboBox( Res.get("shared.tradingAccount"), Res.get("shared.selectTradingAccount")); - final Tuple3> currencyBoxTuple = FormBuilder.addTopLabelComboBox( + final Tuple3> currencyBoxTuple = addTopLabelComboBox( Res.get("shared.currency"), Res.get("list.currency.select")); currencySelection = currencyBoxTuple.first; - hBox.getChildren().addAll(tradingAccountBoxTuple.first, currencySelection); + paymentGroupBox.getChildren().addAll(tradingAccountBoxTuple.first, currencySelection); - GridPane.setRowIndex(hBox, gridRow); - GridPane.setColumnSpan(hBox, 2); - GridPane.setMargin(hBox, new Insets(Layout.FIRST_ROW_DISTANCE, 0, 0, 0)); - gridPane.getChildren().add(hBox); + GridPane.setRowIndex(paymentGroupBox, gridRow); + GridPane.setColumnSpan(paymentGroupBox, 2); + GridPane.setMargin(paymentGroupBox, new Insets(Layout.FIRST_ROW_DISTANCE, 0, 0, 0)); + gridPane.getChildren().add(paymentGroupBox); paymentAccountsComboBox = tradingAccountBoxTuple.third; paymentAccountsComboBox.setMinWidth(300); @@ -987,18 +986,18 @@ public TradeCurrency fromString(String s) { currencyTextFieldBox.setVisible(false); editOfferElements.add(currencyTextFieldBox); - hBox.getChildren().add(currencyTextFieldBox); + paymentGroupBox.getChildren().add(currencyTextFieldBox); } protected void hidePaymentGroup() { paymentTitledGroupBg.setVisible(false); - paymentAccountsComboBox.setVisible(false); - currencyComboBox.setVisible(false); - currencyTextFieldBox.setVisible(false); + paymentGroupBox.setManaged(false); + paymentGroupBox.setVisible(false); } private void addAmountPriceGroup() { - amountTitledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 2, Res.get("createOffer.setAmountPrice"), Layout.COMPACT_GROUP_DISTANCE); + amountTitledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 2, + Res.get("createOffer.setAmountPrice"), Layout.COMPACT_GROUP_DISTANCE); GridPane.setColumnSpan(amountTitledGroupBg, 2); addAmountPriceFields(); @@ -1006,7 +1005,8 @@ private void addAmountPriceGroup() { } private void addOptionsGroup() { - setDepositTitledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 1, Res.get("shared.advancedOptions"), Layout.COMPACT_GROUP_DISTANCE); + setDepositTitledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 1, + Res.get("shared.advancedOptions"), Layout.COMPACT_GROUP_DISTANCE); advancedOptionsBox = new HBox(); advancedOptionsBox.setSpacing(40); @@ -1034,9 +1034,7 @@ private void addOptionsGroup() { close(); model.getDataModel().swapTradeToSavings(); }); - cancelButton1.setId("cancel-button"); - GridPane.setMargin(nextButton, new Insets(-35, 0, 0, 0)); nextButton.setOnAction(e -> { if (model.isPriceInRange()) { if (DevEnv.isDaoTradingActivated()) @@ -1054,10 +1052,8 @@ protected void hideOptionsGroup() { nextButton.setManaged(false); cancelButton1.setVisible(false); cancelButton1.setManaged(false); - buyerSecurityDepositInputTextField.setVisible(false); - buyerSecurityDepositInputTextField.setManaged(false); - buyerSecurityDepositBtcLabel.setVisible(false); - buyerSecurityDepositBtcLabel.setManaged(false); + advancedOptionsBox.setVisible(false); + advancedOptionsBox.setManaged(false); } private void showFeeOption() { @@ -1155,11 +1151,16 @@ private void addFundingGroup() { Button fundFromExternalWalletButton = new AutoTooltipButton(Res.get("shared.fundFromExternalWalletButton")); fundFromExternalWalletButton.setDefaultButton(false); fundFromExternalWalletButton.setOnAction(e -> GUIUtil.showFeeInfoBeforeExecute(this::openWallet)); - waitingForFundsBusyAnimation = new JFXSpinner(); + waitingForFundsSpinner = new JFXSpinner(); waitingForFundsLabel = new AutoTooltipLabel(); waitingForFundsLabel.setPadding(new Insets(5, 0, 0, 0)); - fundingHBox.getChildren().addAll(fundFromSavingsWalletButton, label, fundFromExternalWalletButton, waitingForFundsBusyAnimation, waitingForFundsLabel); + fundingHBox.getChildren().addAll(fundFromSavingsWalletButton, + label, + fundFromExternalWalletButton, + waitingForFundsSpinner, + waitingForFundsLabel); + GridPane.setRowIndex(fundingHBox, ++gridRow); GridPane.setColumnSpan(fundingHBox, 2); GridPane.setMargin(fundingHBox, new Insets(5, 0, 0, 0)); @@ -1284,7 +1285,6 @@ private void addAmountPriceFields() { firstRowHBox.setAlignment(Pos.CENTER_LEFT); firstRowHBox.getChildren().addAll(amountBox, xLabel, percentagePriceBox, resultLabel, volumeBox); GridPane.setRowIndex(firstRowHBox, gridRow); - GridPane.setColumnIndex(firstRowHBox, 0); GridPane.setMargin(firstRowHBox, new Insets(Layout.COMPACT_FIRST_ROW_AND_GROUP_DISTANCE, 10, 0, 0)); gridPane.getChildren().add(firstRowHBox); } @@ -1351,7 +1351,7 @@ private void addSecondRow() { Label fakeXLabel = new Label(); fakeXIcon = getIconForLabel(MaterialDesignIcon.CLOSE, "2em", fakeXLabel); - fakeXLabel.setPadding(new Insets(14, 3, 0, 3)); + fakeXLabel.setPadding(new Insets(24, 3, 0, 3)); fakeXLabel.setVisible(false); // we just use it to get the same layout as the upper row // Fixed/Percentage toggle diff --git a/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferView.java b/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferView.java index 2cb749ae503..c4ef8458d92 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferView.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferView.java @@ -25,9 +25,8 @@ import bisq.desktop.components.AutoTooltipLabel; import bisq.desktop.components.AutoTooltipSlideToggleButton; import bisq.desktop.components.BalanceTextField; -import bisq.desktop.components.BusyAnimation; import bisq.desktop.components.FundsTextField; -import bisq.desktop.components.InfoTextField; +import bisq.desktop.components.InfoInputTextField; import bisq.desktop.components.InputTextField; import bisq.desktop.components.TitledGroupBg; import bisq.desktop.main.MainView; @@ -43,9 +42,9 @@ import bisq.desktop.main.overlays.windows.QRCodeWindow; import bisq.desktop.main.portfolio.PortfolioView; import bisq.desktop.main.portfolio.pendingtrades.PendingTradesView; -import bisq.desktop.util.FormBuilder; import bisq.desktop.util.GUIUtil; import bisq.desktop.util.Layout; +import bisq.desktop.util.Transitions; import bisq.core.locale.CurrencyUtil; import bisq.core.locale.Res; @@ -61,6 +60,7 @@ import bisq.common.app.DevEnv; import bisq.common.util.Tuple2; import bisq.common.util.Tuple3; +import bisq.common.util.Tuple4; import bisq.common.util.Utilities; import org.bitcoinj.core.Coin; @@ -70,6 +70,11 @@ import javax.inject.Inject; +import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon; + +import com.jfoenix.controls.JFXSpinner; +import com.jfoenix.controls.JFXTextField; + import javafx.scene.control.Button; import javafx.scene.control.ComboBox; import javafx.scene.control.Label; @@ -85,7 +90,7 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import javafx.scene.layout.VBox; -import javafx.scene.text.Font; +import javafx.scene.text.Text; import javafx.geometry.HPos; import javafx.geometry.Insets; @@ -107,9 +112,7 @@ import org.jetbrains.annotations.NotNull; -import static bisq.desktop.util.FormBuilder.getAmountCurrencyBox; -import static bisq.desktop.util.FormBuilder.getNonEditableValueCurrencyBox; -import static bisq.desktop.util.FormBuilder.getNonEditableValueCurrencyBoxWithInfo; +import static bisq.desktop.util.FormBuilder.*; import static javafx.beans.binding.Bindings.createStringBinding; @FxmlView @@ -118,27 +121,33 @@ public class TakeOfferView extends ActivatableViewAndModel paymentAccountsComboBox; - private Label directionLabel, amountDescriptionLabel, + private Label amountDescriptionLabel, paymentMethodLabel, priceCurrencyLabel, priceAsPercentageLabel, volumeCurrencyLabel, priceDescriptionLabel, volumeDescriptionLabel, - waitingForFundsLabel, offerAvailabilityLabel, amountCurrency, priceAsPercentageDescription; + waitingForFundsLabel, offerAvailabilityLabel, amountCurrency, priceAsPercentageDescription, + tradeFeeDescriptionLabel, resultLabel, tradeFeeInBtcLabel, tradeFeeInBsqLabel; private InputTextField amountTextField; private TextField paymentMethodTextField, currencyTextField, priceTextField, priceAsPercentageTextField, volumeTextField, amountRangeTextField; private FundsTextField totalToPayTextField; private AddressTextField addressTextField; private BalanceTextField balanceTextField; - private AutoTooltipButton nextButton, cancelButton1, cancelButton2, takeOfferButton; - private ImageView imageView, qrCodeImageView; - private BusyAnimation waitingForFundsBusyAnimation, offerAvailabilityBusyAnimation; + private Text xIcon, fakeXIcon; + private Button nextButton, cancelButton1, cancelButton2; + private AutoTooltipButton takeOfferButton; + private ImageView qrCodeImageView; + private JFXSpinner waitingForFundsSpinner, offerAvailabilitySpinner; private Notification walletFundedNotification; private OfferView.CloseHandler closeHandler; private Subscription cancelButton2StyleSubscription, balanceSubscription, @@ -150,13 +159,9 @@ public class TakeOfferView extends ActivatableViewAndModel amountFocusedListener, getShowWalletFundedNotificationListener; - private InfoTextField volumeInfoTextField; + private InfoInputTextField volumeInfoTextField; private AutoTooltipSlideToggleButton tradeFeeInBtcToggle, tradeFeeInBsqToggle; private ChangeListener tradeFeeInBtcToggleListener, tradeFeeInBsqToggleListener; - private AutoTooltipLabel tradeFeeDescriptionLabel; - private TextField tradeFeeInBtcTextField, tradeFeeInBsqTextField; - private VBox tradeFeeBox; - /////////////////////////////////////////////////////////////////////////////////////////// // Constructor, lifecycle @@ -167,13 +172,15 @@ private TakeOfferView(TakeOfferViewModel model, Navigation navigation, BSFormatter formatter, BsqFormatter bsqFormatter, - OfferDetailsWindow offerDetailsWindow) { + OfferDetailsWindow offerDetailsWindow, + Transitions transitions) { super(model); this.navigation = navigation; this.formatter = formatter; this.bsqFormatter = bsqFormatter; this.offerDetailsWindow = offerDetailsWindow; + this.transitions = transitions; } @Override @@ -182,6 +189,7 @@ protected void initialize() { addGridPane(); addPaymentGroup(); addAmountPriceGroup(); + addOptionsGroup(); addButtons(); addOfferAvailabilityLabel(); @@ -224,31 +232,14 @@ protected void initialize() { setIsCurrencyForMakerFeeBtc(!newValue); }; - boolean currencyForMakerFeeBtc = model.dataModel.isCurrencyForTakerFeeBtc(); - tradeFeeInBtcToggle.setSelected(currencyForMakerFeeBtc); - tradeFeeInBsqToggle.setSelected(!currencyForMakerFeeBtc); - - if (!DevEnv.isDaoActivated()) { - tradeFeeInBtcToggle.setVisible(false); - tradeFeeInBtcToggle.setManaged(false); - tradeFeeInBsqToggle.setVisible(false); - tradeFeeInBsqToggle.setManaged(false); - - tradeFeeBox.setVisible(false); - tradeFeeBox.setManaged(false); - - tradeFeeDescriptionLabel.setVisible(false); - tradeFeeDescriptionLabel.setManaged(false); - } - GUIUtil.focusWhenAddedToScene(amountTextField); } private void setIsCurrencyForMakerFeeBtc(boolean isCurrencyForMakerFeeBtc) { model.setIsCurrencyForTakerFeeBtc(isCurrencyForMakerFeeBtc); if (DevEnv.isDaoActivated()) { - tradeFeeInBtcTextField.setOpacity(isCurrencyForMakerFeeBtc ? 1 : 0.3); - tradeFeeInBsqTextField.setOpacity(isCurrencyForMakerFeeBtc ? 0.3 : 1); + tradeFeeInBtcLabel.setOpacity(isCurrencyForMakerFeeBtc ? 1 : 0.3); + tradeFeeInBsqLabel.setOpacity(isCurrencyForMakerFeeBtc ? 0.3 : 1); } } @@ -258,8 +249,8 @@ protected void activate() { addSubscriptions(); addListeners(); - if (offerAvailabilityBusyAnimation != null && !model.showPayFundsScreenDisplayed.get()) { - offerAvailabilityBusyAnimation.play(); + if (offerAvailabilitySpinner != null && !model.showPayFundsScreenDisplayed.get()) { + offerAvailabilitySpinner.setProgress(-1); offerAvailabilityLabel.setVisible(true); offerAvailabilityLabel.setManaged(true); } else { @@ -267,8 +258,8 @@ protected void activate() { offerAvailabilityLabel.setManaged(false); } - if (waitingForFundsBusyAnimation != null && model.isWaitingForFunds.get()) { - waitingForFundsBusyAnimation.play(); + if (waitingForFundsSpinner != null && model.isWaitingForFunds.get()) { + waitingForFundsSpinner.setProgress(-1); waitingForFundsLabel.setVisible(true); waitingForFundsLabel.setManaged(true); } else { @@ -311,6 +302,20 @@ protected void activate() { .dontShowAgainId("FiatValuesRoundedWarning") .show(); } + + boolean currencyForMakerFeeBtc = model.dataModel.isCurrencyForTakerFeeBtc(); + tradeFeeInBtcToggle.setSelected(currencyForMakerFeeBtc); + tradeFeeInBsqToggle.setSelected(!currencyForMakerFeeBtc); + + if (!DevEnv.isDaoActivated()) { + tradeFeeInBtcToggle.setVisible(false); + tradeFeeInBtcToggle.setManaged(false); + tradeFeeInBsqToggle.setVisible(false); + tradeFeeInBsqToggle.setManaged(false); + + tradeFeeDescriptionLabel.setVisible(false); + tradeFeeDescriptionLabel.setManaged(false); + } } @Override @@ -319,11 +324,11 @@ protected void deactivate() { removeSubscriptions(); removeListeners(); - if (offerAvailabilityBusyAnimation != null) - offerAvailabilityBusyAnimation.stop(); + if (offerAvailabilitySpinner != null) + offerAvailabilitySpinner.setProgress(0); - if (waitingForFundsBusyAnimation != null) - waitingForFundsBusyAnimation.stop(); + if (waitingForFundsSpinner != null) + waitingForFundsSpinner.setProgress(0); } /////////////////////////////////////////////////////////////////////////////////////////// @@ -335,17 +340,11 @@ public void initWithData(Offer offer) { priceAsPercentageInputBox.setVisible(offer.isUseMarketBasedPrice()); if (model.getOffer().getDirection() == OfferPayload.Direction.SELL) { - imageView.setId("image-buy-large"); - directionLabel.setId("direction-icon-label-buy"); - takeOfferButton.setId("buy-button-big"); takeOfferButton.updateText(Res.get("takeOffer.takeOfferButton", Res.get("shared.buy"))); nextButton.setId("buy-button"); priceAsPercentageDescription.setText(Res.get("shared.aboveInPercent")); } else { - imageView.setId("image-sell-large"); - directionLabel.setId("direction-icon-label-sell"); - takeOfferButton.setId("sell-button-big"); nextButton.setId("sell-button"); takeOfferButton.updateText(Res.get("takeOffer.takeOfferButton", Res.get("shared.sell"))); @@ -355,6 +354,7 @@ public void initWithData(Offer offer) { boolean showComboBox = model.getPossiblePaymentAccounts().size() > 1; paymentAccountsComboBox.setVisible(showComboBox); paymentAccountsComboBox.setManaged(showComboBox); + paymentAccountsComboBox.setMouseTransparent(!showComboBox); paymentMethodTextField.setVisible(!showComboBox); paymentMethodTextField.setManaged(!showComboBox); paymentMethodLabel.setVisible(!showComboBox); @@ -362,17 +362,13 @@ public void initWithData(Offer offer) { if (!showComboBox) paymentMethodTextField.setText(Res.get(model.getPaymentMethod().getId())); currencyTextField.setText(model.dataModel.getCurrencyNameAndCode()); - directionLabel.setText(model.getDirectionLabel()); amountDescriptionLabel.setText(model.getAmountDescription()); if (model.isRange()) { amountRangeTextField.setText(model.getAmountRange()); amountRangeBox.setVisible(true); } else { - amountTextField.setMouseTransparent(true); - amountTextField.setEditable(false); - amountTextField.setFocusTraversable(false); - amountCurrency.setId("currency-info-label-disabled"); + amountTextField.setDisable(true); } priceTextField.setText(model.getPrice()); @@ -451,26 +447,54 @@ private void onTakeOffer() { @SuppressWarnings("PointlessBooleanExpression") private void onShowPayFundsScreen() { + scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED); + nextButton.setVisible(false); nextButton.setManaged(false); nextButton.setOnAction(null); cancelButton1.setVisible(false); cancelButton1.setManaged(false); cancelButton1.setOnAction(null); - offerAvailabilityBusyAnimation.stop(); + offerAvailabilitySpinner.setProgress(0); + offerAvailabilitySpinner.setVisible(false); + offerAvailabilitySpinner.setManaged(false); offerAvailabilityLabel.setVisible(false); offerAvailabilityLabel.setManaged(false); tradeFeeInBtcToggle.setMouseTransparent(true); tradeFeeInBsqToggle.setMouseTransparent(true); + int delay = 500; + int diff = 100; + + transitions.fadeOutAndRemove(advancedOptionsGroup, delay, (event) -> { + }); + delay -= diff; + transitions.fadeOutAndRemove(advancedOptionsBox, delay); + model.onShowPayFundsScreen(); amountTextField.setMouseTransparent(true); + amountTextField.setDisable(false); amountTextField.setFocusTraversable(false); + + amountRangeTextField.setMouseTransparent(true); + amountRangeTextField.setDisable(false); + amountRangeTextField.setFocusTraversable(false); + priceTextField.setMouseTransparent(true); + priceTextField.setDisable(false); + priceTextField.setFocusTraversable(false); + priceAsPercentageTextField.setMouseTransparent(true); + priceAsPercentageTextField.setDisable(false); + priceAsPercentageTextField.setFocusTraversable(false); + volumeTextField.setMouseTransparent(true); + volumeTextField.setDisable(false); + volumeTextField.setFocusTraversable(false); + + updateOfferElementsStyle(); balanceTextField.setTargetAmount(model.dataModel.getTotalToPayAsCoin().get()); @@ -501,9 +525,9 @@ private void onShowPayFundsScreen() { cancelButton2.setVisible(true); - waitingForFundsBusyAnimation.play(); + waitingForFundsSpinner.setProgress(-1); - payFundsPane.setVisible(true); + payFundsTitledGroupBg.setVisible(true); totalToPayTextField.setVisible(true); addressTextField.setVisible(true); qrCodeImageView.setVisible(true); @@ -533,6 +557,25 @@ private void onShowPayFundsScreen() { qrCodeImageView.setImage(qrImage); } + private void updateOfferElementsStyle() { + final String activeInputStyle = "input-with-border"; + final String readOnlyInputStyle = "input-with-border-readonly"; + amountValueCurrencyBox.getStyleClass().remove(activeInputStyle); + amountValueCurrencyBox.getStyleClass().add(readOnlyInputStyle); + priceAsPercentageValueCurrencyBox.getStyleClass().remove(activeInputStyle); + priceAsPercentageValueCurrencyBox.getStyleClass().add(readOnlyInputStyle); + volumeValueCurrencyBox.getStyleClass().remove(activeInputStyle); + volumeValueCurrencyBox.getStyleClass().add(readOnlyInputStyle); + priceValueCurrencyBox.getStyleClass().remove(activeInputStyle); + priceValueCurrencyBox.getStyleClass().add(readOnlyInputStyle); + minAmountValueCurrencyBox.getStyleClass().remove(activeInputStyle); + minAmountValueCurrencyBox.getStyleClass().add(readOnlyInputStyle); + + resultLabel.getStyleClass().add("small"); + xIcon.setStyle(String.format("-fx-font-family: %s; -fx-font-size: %s;", MaterialDesignIcon.CLOSE.fontFamily(), "1em")); + fakeXIcon.setStyle(String.format("-fx-font-family: %s; -fx-font-size: %s;", MaterialDesignIcon.CLOSE.fontFamily(), "1em")); + } + /////////////////////////////////////////////////////////////////////////////////////////// // Navigation /////////////////////////////////////////////////////////////////////////////////////////// @@ -549,45 +592,45 @@ private void close() { private void addBindings() { amountTextField.textProperty().bindBidirectional(model.amount); - volumeInfoTextField.textProperty().bindBidirectional(model.volume); + volumeTextField.textProperty().bindBidirectional(model.volume); totalToPayTextField.textProperty().bind(model.totalToPay); addressTextField.amountAsCoinProperty().bind(model.dataModel.getMissingCoin()); amountTextField.validationResultProperty().bind(model.amountValidationResult); - priceCurrencyLabel.textProperty().bind(createStringBinding(() -> formatter.getCurrencyPair(model.dataModel.getCurrencyCode()))); + priceCurrencyLabel.textProperty().bind(createStringBinding(() -> formatter.getCounterCurrency(model.dataModel.getCurrencyCode()))); priceAsPercentageLabel.prefWidthProperty().bind(priceCurrencyLabel.widthProperty()); nextButton.disableProperty().bind(model.isNextButtonDisabled); - tradeFeeInBtcTextField.textProperty().bind(model.tradeFeeInBtcWithFiat); - tradeFeeInBsqTextField.textProperty().bind(model.tradeFeeInBsqWithFiat); + tradeFeeInBtcLabel.textProperty().bind(model.tradeFeeInBtcWithFiat); + tradeFeeInBsqLabel.textProperty().bind(model.tradeFeeInBsqWithFiat); tradeFeeDescriptionLabel.textProperty().bind(model.tradeFeeDescription); // funding fundingHBox.visibleProperty().bind(model.dataModel.getIsBtcWalletFunded().not().and(model.showPayFundsScreenDisplayed)); fundingHBox.managedProperty().bind(model.dataModel.getIsBtcWalletFunded().not().and(model.showPayFundsScreenDisplayed)); waitingForFundsLabel.textProperty().bind(model.spinnerInfoText); + takeOfferBox.visibleProperty().bind(model.dataModel.getIsBtcWalletFunded().and(model.showPayFundsScreenDisplayed)); + takeOfferBox.managedProperty().bind(model.dataModel.getIsBtcWalletFunded().and(model.showPayFundsScreenDisplayed)); takeOfferButton.disableProperty().bind(model.isTakeOfferButtonDisabled); - takeOfferButton.visibleProperty().bind(model.dataModel.getIsBtcWalletFunded().and(model.showPayFundsScreenDisplayed)); - takeOfferButton.managedProperty().bind(model.dataModel.getIsBtcWalletFunded().and(model.showPayFundsScreenDisplayed)); } private void removeBindings() { amountTextField.textProperty().unbindBidirectional(model.amount); - volumeInfoTextField.textProperty().unbindBidirectional(model.volume); + volumeTextField.textProperty().unbindBidirectional(model.volume); totalToPayTextField.textProperty().unbind(); addressTextField.amountAsCoinProperty().unbind(); amountTextField.validationResultProperty().unbind(); priceCurrencyLabel.textProperty().unbind(); priceAsPercentageLabel.prefWidthProperty().unbind(); nextButton.disableProperty().unbind(); - tradeFeeInBtcTextField.textProperty().unbind(); - tradeFeeInBsqTextField.textProperty().unbind(); + tradeFeeInBtcLabel.textProperty().unbind(); + tradeFeeInBsqLabel.textProperty().unbind(); tradeFeeDescriptionLabel.textProperty().unbind(); // funding fundingHBox.visibleProperty().unbind(); fundingHBox.managedProperty().unbind(); waitingForFundsLabel.textProperty().unbind(); - takeOfferButton.visibleProperty().unbind(); - takeOfferButton.managedProperty().unbind(); + takeOfferBox.visibleProperty().unbind(); + takeOfferBox.managedProperty().unbind(); takeOfferButton.disableProperty().unbind(); } @@ -632,7 +675,8 @@ private void addSubscriptions() { isOfferAvailableSubscription = EasyBind.subscribe(model.isOfferAvailable, isOfferAvailable -> { if (isOfferAvailable) { - offerAvailabilityBusyAnimation.stop(); + offerAvailabilitySpinner.setProgress(0); + offerAvailabilitySpinner.setVisible(false); if (!DevEnv.isDaoActivated() && !model.isRange() && !model.showPayFundsScreenDisplayed.get()) showNextStepAfterAmountIsSet(); } @@ -642,7 +686,7 @@ private void addSubscriptions() { }); isWaitingForFundsSubscription = EasyBind.subscribe(model.isWaitingForFunds, isWaitingForFunds -> { - waitingForFundsBusyAnimation.setIsRunning(isWaitingForFunds); + waitingForFundsSpinner.setProgress(-1); waitingForFundsLabel.setVisible(isWaitingForFunds); waitingForFundsLabel.setManaged(isWaitingForFunds); }); @@ -740,7 +784,7 @@ private void removeListeners() { private void addScrollPane() { scrollPane = new ScrollPane(); scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); - scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED); + scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); scrollPane.setFitToWidth(true); scrollPane.setFitToHeight(true); AnchorPane.setLeftAnchor(scrollPane, 0d); @@ -752,6 +796,7 @@ private void addScrollPane() { private void addGridPane() { gridPane = new GridPane(); + gridPane.getStyleClass().add("content-pane"); gridPane.setPadding(new Insets(30, 25, -1, 25)); gridPane.setHgap(5); gridPane.setVgap(5); @@ -768,11 +813,15 @@ private void addGridPane() { } private void addPaymentGroup() { - paymentAccountTitledGroupBg = FormBuilder.addTitledGroupBg(gridPane, gridRow, 2, Res.get("takeOffer.paymentInfo")); - GridPane.setColumnSpan(paymentAccountTitledGroupBg, 3); + paymentAccountTitledGroupBg = addTitledGroupBg(gridPane, gridRow, 1, Res.get("takeOffer.paymentInfo")); + GridPane.setColumnSpan(paymentAccountTitledGroupBg, 2); + + final Tuple4, Label, TextField, HBox> paymentAccountTuple = addComboBoxTopLabelTextField(gridPane, + gridRow, Res.get("shared.selectTradingAccount"), + Res.get("shared.paymentMethod"), Layout.FIRST_ROW_DISTANCE); - paymentAccountsComboBox = FormBuilder.addComboBox(gridPane, gridRow, Res.getWithCol("shared.tradingAccount"), Layout.FIRST_ROW_DISTANCE); - paymentAccountsComboBox.setPromptText(Res.get("shared.selectTradingAccount")); + paymentAccountsComboBox = paymentAccountTuple.first; + HBox.setMargin(paymentAccountsComboBox, new Insets(Layout.FLOATING_LABEL_DISTANCE, 0, 0, 0)); paymentAccountsComboBox.setConverter(GUIUtil.getPaymentAccountsComboBoxStringConverter()); paymentAccountsComboBox.setVisible(false); paymentAccountsComboBox.setManaged(false); @@ -781,46 +830,70 @@ private void addPaymentGroup() { model.onPaymentAccountSelected(paymentAccountsComboBox.getSelectionModel().getSelectedItem()); }); - Tuple3 tuple3 = FormBuilder.addTopLabelTextField(gridPane, gridRow, Res.get("shared.paymentMethod"), "", Layout.FIRST_ROW_DISTANCE); - paymentMethodLabel = tuple3.first; - paymentMethodTextField = tuple3.second; - currencyTextField = FormBuilder.addTopLabelTextField(gridPane, ++gridRow, Res.getWithCol("shared.tradeCurrency"), "").second; + paymentMethodLabel = paymentAccountTuple.second; + paymentMethodTextField = paymentAccountTuple.third; + paymentMethodTextField.setMinWidth(250); + paymentMethodTextField.setEditable(false); + paymentMethodTextField.setMouseTransparent(true); + paymentMethodTextField.setFocusTraversable(false); + + currencyTextField = new JFXTextField(); + currencyTextField.setMinWidth(250); + currencyTextField.setEditable(false); + currencyTextField.setMouseTransparent(true); + currencyTextField.setFocusTraversable(false); + + final Tuple2 tradeCurrencyTuple = getTopLabelWithVBox(Res.get("shared.tradeCurrency"), currencyTextField); + HBox.setMargin(tradeCurrencyTuple.second, new Insets(5, 0, 0, 0)); + + final HBox hBox = paymentAccountTuple.forth; + hBox.setSpacing(30); + hBox.setAlignment(Pos.CENTER_LEFT); + hBox.setPadding(new Insets(10, 0, 18, 0)); + + hBox.getChildren().add(tradeCurrencyTuple.second); } private void addAmountPriceGroup() { - TitledGroupBg titledGroupBg = FormBuilder.addTitledGroupBg(gridPane, ++gridRow, 2, - Res.get("takeOffer.setAmountPrice"), Layout.GROUP_DISTANCE); - GridPane.setColumnSpan(titledGroupBg, 3); - - imageView = new ImageView(); - imageView.setPickOnBounds(true); - directionLabel = new AutoTooltipLabel(); - directionLabel.setAlignment(Pos.CENTER); - directionLabel.setPadding(new Insets(-5, 0, 0, 0)); - directionLabel.setId("direction-icon-label"); - VBox imageVBox = new VBox(); - imageVBox.setAlignment(Pos.CENTER); - imageVBox.setSpacing(12); - imageVBox.getChildren().addAll(imageView, directionLabel); - GridPane.setRowIndex(imageVBox, gridRow); - GridPane.setRowSpan(imageVBox, 2); - GridPane.setMargin(imageVBox, new Insets(Layout.FIRST_ROW_AND_GROUP_DISTANCE, 10, 10, 10)); - gridPane.getChildren().add(imageVBox); + TitledGroupBg titledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 2, + Res.get("takeOffer.setAmountPrice"), Layout.COMPACT_GROUP_DISTANCE); + GridPane.setColumnSpan(titledGroupBg, 2); addAmountPriceFields(); addSecondRow(); } + private void addOptionsGroup() { + advancedOptionsGroup = addTitledGroupBg(gridPane, ++gridRow, 1, Res.get("shared.advancedOptions"), Layout.COMPACT_GROUP_DISTANCE); + + advancedOptionsBox = new HBox(); + advancedOptionsBox.setSpacing(40); + + GridPane.setRowIndex(advancedOptionsBox, gridRow); + GridPane.setColumnIndex(advancedOptionsBox, 0); + GridPane.setHalignment(advancedOptionsBox, HPos.LEFT); + GridPane.setMargin(advancedOptionsBox, new Insets(Layout.COMPACT_FIRST_ROW_AND_GROUP_DISTANCE, 0, 0, 0)); + gridPane.getChildren().add(advancedOptionsBox); + + advancedOptionsBox.getChildren().addAll(getTradeFeeFieldsBox()); + } + private void addButtons() { - nextButton = new AutoTooltipButton(Res.get("shared.nextStep")); + Tuple3 tuple = add2ButtonsWithBox(gridPane, ++gridRow, + Res.get("shared.nextStep"), Res.get("shared.cancel"), 15, true); + + buttonBox = tuple.third; + + nextButton = tuple.first; + nextButton.setMaxWidth(200); nextButton.setDefaultButton(true); nextButton.setOnAction(e -> { showNextStepAfterAmountIsSet(); }); - cancelButton1 = new AutoTooltipButton(Res.get("shared.cancel")); + cancelButton1 = tuple.second; + cancelButton1.setMaxWidth(200); cancelButton1.setDefaultButton(false); - cancelButton1.setId("cancel-button"); cancelButton1.setOnAction(e -> { model.dataModel.swapTradeToSavings(); close(); @@ -865,32 +938,28 @@ private void showFeeOption() { } private void addOfferAvailabilityLabel() { - offerAvailabilityBusyAnimation = new BusyAnimation(); + offerAvailabilitySpinner = new JFXSpinner(); offerAvailabilityLabel = new AutoTooltipLabel(Res.get("takeOffer.fundsBox.isOfferAvailable")); - HBox hBox = new HBox(); - hBox.setSpacing(10); - hBox.setAlignment(Pos.CENTER_LEFT); - hBox.getChildren().addAll(nextButton, cancelButton1, offerAvailabilityBusyAnimation, offerAvailabilityLabel); - - GridPane.setRowIndex(hBox, ++gridRow); - GridPane.setColumnIndex(hBox, 1); - GridPane.setMargin(hBox, new Insets(-30, 0, 0, 0)); - gridPane.getChildren().add(hBox); + buttonBox.getChildren().addAll(offerAvailabilitySpinner, offerAvailabilityLabel); } private void addFundingGroup() { // don't increase gridRow as we removed button when this gets visible - payFundsPane = FormBuilder.addTitledGroupBg(gridPane, gridRow, 3, Res.get("takeOffer.fundsBox.title"), Layout.GROUP_DISTANCE); - GridPane.setColumnSpan(payFundsPane, 3); - payFundsPane.setVisible(false); - - totalToPayTextField = FormBuilder.addFundsTextfield(gridPane, gridRow, - Res.get("shared.totalsNeeded"), Layout.FIRST_ROW_AND_GROUP_DISTANCE); + payFundsTitledGroupBg = addTitledGroupBg(gridPane, gridRow, 3, + Res.get("takeOffer.fundsBox.title"), Layout.COMPACT_GROUP_DISTANCE); + payFundsTitledGroupBg.getStyleClass().add("last"); + GridPane.setColumnSpan(payFundsTitledGroupBg, 2); + payFundsTitledGroupBg.setVisible(false); + + totalToPayTextField = addFundsTextfield(gridPane, gridRow, + Res.get("shared.totalsNeeded"), Layout.COMPACT_FIRST_ROW_AND_GROUP_DISTANCE); totalToPayTextField.setVisible(false); qrCodeImageView = new ImageView(); qrCodeImageView.setVisible(false); + qrCodeImageView.setFitHeight(150); + qrCodeImageView.setFitWidth(150); qrCodeImageView.getStyleClass().add("qr-code"); Tooltip.install(qrCodeImageView, new Tooltip(Res.get("shared.openLargeQRWindow"))); qrCodeImageView.setOnMouseClicked(e -> GUIUtil.showFeeInfoBeforeExecute( @@ -900,13 +969,14 @@ private void addFundingGroup() { GridPane.setRowIndex(qrCodeImageView, gridRow); GridPane.setColumnIndex(qrCodeImageView, 1); GridPane.setRowSpan(qrCodeImageView, 3); - GridPane.setMargin(qrCodeImageView, new Insets(Layout.FIRST_ROW_AND_GROUP_DISTANCE - 9, 0, 0, 5)); + GridPane.setValignment(qrCodeImageView, VPos.BOTTOM); + GridPane.setMargin(qrCodeImageView, new Insets(Layout.FIRST_ROW_DISTANCE - 9, 0, 0, 10)); gridPane.getChildren().add(qrCodeImageView); - addressTextField = FormBuilder.addAddressTextField(gridPane, ++gridRow, Res.get("shared.tradeWalletAddress")); + addressTextField = addAddressTextField(gridPane, ++gridRow, Res.get("shared.tradeWalletAddress")); addressTextField.setVisible(false); - balanceTextField = FormBuilder.addBalanceTextField(gridPane, ++gridRow, Res.get("shared.tradeWalletBalance")); + balanceTextField = addBalanceTextField(gridPane, ++gridRow, Res.get("shared.tradeWalletBalance")); balanceTextField.setVisible(false); fundingHBox = new HBox(); @@ -915,35 +985,53 @@ private void addFundingGroup() { fundingHBox.setSpacing(10); Button fundFromSavingsWalletButton = new AutoTooltipButton(Res.get("shared.fundFromSavingsWalletButton")); fundFromSavingsWalletButton.setDefaultButton(true); - fundFromSavingsWalletButton.setDefaultButton(false); + fundFromSavingsWalletButton.getStyleClass().add("action-button"); fundFromSavingsWalletButton.setOnAction(e -> model.fundFromSavingsWallet()); Label label = new AutoTooltipLabel(Res.get("shared.OR")); label.setPadding(new Insets(5, 0, 0, 0)); Button fundFromExternalWalletButton = new AutoTooltipButton(Res.get("shared.fundFromExternalWalletButton")); fundFromExternalWalletButton.setDefaultButton(false); fundFromExternalWalletButton.setOnAction(e -> GUIUtil.showFeeInfoBeforeExecute(this::openWallet)); - waitingForFundsBusyAnimation = new BusyAnimation(false); + waitingForFundsSpinner = new JFXSpinner(); waitingForFundsLabel = new AutoTooltipLabel(); waitingForFundsLabel.setPadding(new Insets(5, 0, 0, 0)); fundingHBox.getChildren().addAll(fundFromSavingsWalletButton, label, fundFromExternalWalletButton, - waitingForFundsBusyAnimation, + waitingForFundsSpinner, waitingForFundsLabel); GridPane.setRowIndex(fundingHBox, ++gridRow); - GridPane.setColumnIndex(fundingHBox, 1); - GridPane.setMargin(fundingHBox, new Insets(15, 10, 0, 0)); + GridPane.setMargin(fundingHBox, new Insets(5, 0, 0, 0)); gridPane.getChildren().add(fundingHBox); - takeOfferButton = (AutoTooltipButton) FormBuilder.addButtonAfterGroup(gridPane, gridRow, ""); - takeOfferButton.setVisible(false); - takeOfferButton.setManaged(false); + takeOfferBox = new HBox(); + takeOfferBox.setSpacing(10); + GridPane.setRowIndex(takeOfferBox, gridRow); + GridPane.setColumnSpan(takeOfferBox, 2); + GridPane.setMargin(takeOfferBox, new Insets(5, 20, 0, 0)); + gridPane.getChildren().add(takeOfferBox); + + takeOfferButton = new AutoTooltipButton(); + takeOfferButton.setOnAction(e -> onTakeOffer()); takeOfferButton.setMinHeight(40); takeOfferButton.setPadding(new Insets(0, 20, 0, 20)); - takeOfferButton.setOnAction(e -> onTakeOffer()); - cancelButton2 = (AutoTooltipButton) FormBuilder.addButton(gridPane, ++gridRow, Res.get("shared.cancel")); + takeOfferBox.getChildren().add(takeOfferButton); + takeOfferBox.visibleProperty().addListener((observable, oldValue, newValue) -> { + if (newValue) { + fundingHBox.getChildren().remove(cancelButton2); + takeOfferBox.getChildren().add(cancelButton2); + } else if (!fundingHBox.getChildren().contains(cancelButton2)) { + takeOfferBox.getChildren().remove(cancelButton2); + fundingHBox.getChildren().add(cancelButton2); + } + }); + + cancelButton2 = new AutoTooltipButton(Res.get("shared.cancel")); + + fundingHBox.getChildren().add(cancelButton2); + cancelButton2.setOnAction(e -> { if (model.dataModel.getIsBtcWalletFunded().get()) { new Popup<>().warning(Res.get("takeOffer.alreadyFunded.askCancel")) @@ -981,8 +1069,8 @@ private String getBitcoinURI() { private void addAmountPriceFields() { // amountBox - Tuple3 amountValueCurrencyBoxTuple = getAmountCurrencyBox(Res.get("takeOffer.amount.prompt")); - HBox amountValueCurrencyBox = amountValueCurrencyBoxTuple.first; + Tuple3 amountValueCurrencyBoxTuple = getEditableValueBox(Res.get("takeOffer.amount.prompt")); + amountValueCurrencyBox = amountValueCurrencyBoxTuple.first; amountTextField = amountValueCurrencyBoxTuple.second; amountCurrency = amountValueCurrencyBoxTuple.third; Tuple2 amountInputBoxTuple = getTradeInputBox(amountValueCurrencyBox, model.getAmountDescription()); @@ -990,31 +1078,34 @@ private void addAmountPriceFields() { VBox amountBox = amountInputBoxTuple.second; // x - Label xLabel = new AutoTooltipLabel("x"); - xLabel.setFont(Font.font("Helvetica-Bold", 20)); - xLabel.setPadding(new Insets(14, 3, 0, 3)); + Label xLabel = new Label(); + xIcon = getIconForLabel(MaterialDesignIcon.CLOSE, "2em", xLabel); + xIcon.getStyleClass().add("opaque-icon"); + xLabel.setPadding(new Insets(24, 3, 0, 3)); // price - Tuple3 priceValueCurrencyBoxTuple = getNonEditableValueCurrencyBox(); - HBox priceValueCurrencyBox = priceValueCurrencyBoxTuple.first; + Tuple3 priceValueCurrencyBoxTuple = getNonEditableValueBox(); + priceValueCurrencyBox = priceValueCurrencyBoxTuple.first; priceTextField = priceValueCurrencyBoxTuple.second; priceCurrencyLabel = priceValueCurrencyBoxTuple.third; Tuple2 priceInputBoxTuple = getTradeInputBox(priceValueCurrencyBox, Res.get("takeOffer.amountPriceBox.priceDescription")); priceDescriptionLabel = priceInputBoxTuple.first; + + getSmallIconForLabel(MaterialDesignIcon.LOCK, priceDescriptionLabel); + VBox priceBox = priceInputBoxTuple.second; // = - Label resultLabel = new AutoTooltipLabel("="); - resultLabel.setFont(Font.font("Helvetica-Bold", 20)); - resultLabel.setPadding(new Insets(14, 2, 0, 2)); + resultLabel = new AutoTooltipLabel("="); + resultLabel.getStyleClass().add("opaque-icon-character"); // volume - Tuple3 volumeValueCurrencyBoxTuple = getNonEditableValueCurrencyBoxWithInfo(); - HBox volumeValueCurrencyBox = volumeValueCurrencyBoxTuple.first; + Tuple3 volumeValueCurrencyBoxTuple = getNonEditableValueBoxWithInfo(); + volumeValueCurrencyBox = volumeValueCurrencyBoxTuple.first; volumeInfoTextField = volumeValueCurrencyBoxTuple.second; - volumeTextField = volumeInfoTextField.getTextField(); + volumeTextField = volumeInfoTextField.getInputTextField(); volumeCurrencyLabel = volumeValueCurrencyBoxTuple.third; Tuple2 volumeInputBoxTuple = getTradeInputBox(volumeValueCurrencyBox, model.volumeDescriptionLabel.get()); volumeDescriptionLabel = volumeInputBoxTuple.first; @@ -1025,71 +1116,65 @@ private void addAmountPriceFields() { hBox.setAlignment(Pos.CENTER_LEFT); hBox.getChildren().addAll(amountBox, xLabel, priceBox, resultLabel, volumeBox); GridPane.setRowIndex(hBox, gridRow); - GridPane.setColumnIndex(hBox, 1); - GridPane.setMargin(hBox, new Insets(Layout.FIRST_ROW_AND_GROUP_DISTANCE, 10, 0, 0)); - GridPane.setColumnSpan(hBox, 2); + GridPane.setMargin(hBox, new Insets(Layout.COMPACT_FIRST_ROW_AND_GROUP_DISTANCE, 10, 0, 0)); gridPane.getChildren().add(hBox); } private void addSecondRow() { - Tuple3 priceAsPercentageTuple = getNonEditableValueCurrencyBox(); - HBox priceAsPercentageValueCurrencyBox = priceAsPercentageTuple.first; + Tuple3 priceAsPercentageTuple = getNonEditableValueBox(); + priceAsPercentageValueCurrencyBox = priceAsPercentageTuple.first; priceAsPercentageTextField = priceAsPercentageTuple.second; priceAsPercentageLabel = priceAsPercentageTuple.third; Tuple2 priceAsPercentageInputBoxTuple = getTradeInputBox(priceAsPercentageValueCurrencyBox, Res.get("shared.distanceInPercent")); priceAsPercentageDescription = priceAsPercentageInputBoxTuple.first; - priceAsPercentageDescription.setPrefWidth(220); + + getSmallIconForLabel(MaterialDesignIcon.CHART_LINE, priceAsPercentageDescription); + priceAsPercentageInputBox = priceAsPercentageInputBoxTuple.second; priceAsPercentageLabel.setText("%"); - priceAsPercentageLabel.getStyleClass().add("percentage-label"); - Tuple3 amountValueCurrencyBoxTuple = getNonEditableValueCurrencyBox(); + Tuple3 amountValueCurrencyBoxTuple = getNonEditableValueBox(); amountRangeTextField = amountValueCurrencyBoxTuple.second; - Tuple2 amountInputBoxTuple = getTradeInputBox(amountValueCurrencyBoxTuple.first, + minAmountValueCurrencyBox = amountValueCurrencyBoxTuple.first; + Tuple2 amountInputBoxTuple = getTradeInputBox(minAmountValueCurrencyBox, Res.get("takeOffer.amountPriceBox.amountRangeDescription")); amountRangeBox = amountInputBoxTuple.second; amountRangeBox.setVisible(false); - Label xLabel = new AutoTooltipLabel("x"); - xLabel.setFont(Font.font("Helvetica-Bold", 20)); - xLabel.setPadding(new Insets(14, 3, 0, 3)); - xLabel.setVisible(false); // we just use it to get the same layout as the upper row - - // Trade fee - setupTradeFeeFields(); + Label fakeXLabel = new Label(); + fakeXIcon = getIconForLabel(MaterialDesignIcon.CLOSE, "2em", fakeXLabel); + fakeXLabel.setPadding(new Insets(14, 3, 0, 3)); + fakeXLabel.setVisible(false); // we just use it to get the same layout as the upper row HBox hBox = new HBox(); hBox.setSpacing(5); hBox.setAlignment(Pos.CENTER_LEFT); - HBox.setMargin(tradeFeeBox, new Insets(0, 0, 0, 22)); - hBox.getChildren().addAll(amountRangeBox, xLabel, priceAsPercentageInputBox, tradeFeeBox); + hBox.getChildren().addAll(amountRangeBox, fakeXLabel, priceAsPercentageInputBox); GridPane.setRowIndex(hBox, ++gridRow); - GridPane.setColumnIndex(hBox, 1); - GridPane.setMargin(hBox, new Insets(5, 10, 5, 0)); - GridPane.setColumnSpan(hBox, 2); + GridPane.setMargin(hBox, new Insets(0, 10, 18, 0)); gridPane.getChildren().add(hBox); } - private void setupTradeFeeFields() { - tradeFeeInBtcTextField = new TextField(); - tradeFeeInBtcTextField.setMouseTransparent(true); - tradeFeeInBtcTextField.setId("trade-fee-textfield"); - tradeFeeInBtcTextField.setPadding(new Insets(-6, 5, -8, 0)); + private VBox getTradeFeeFieldsBox() { + tradeFeeInBtcLabel = new Label(); + tradeFeeInBtcLabel.setMouseTransparent(true); + tradeFeeInBtcLabel.setId("trade-fee-textfield"); - tradeFeeInBsqTextField = new TextField(); - tradeFeeInBsqTextField.setMouseTransparent(true); - tradeFeeInBsqTextField.setId("trade-fee-textfield"); - tradeFeeInBsqTextField.setPadding(new Insets(-9, 5, -7, 0)); + tradeFeeInBsqLabel = new Label(); + tradeFeeInBsqLabel.setMouseTransparent(true); + tradeFeeInBsqLabel.setId("trade-fee-textfield"); VBox vBox = new VBox(); - vBox.getStyleClass().add("input-with-border"); - vBox.getChildren().addAll(tradeFeeInBtcTextField, tradeFeeInBsqTextField); + vBox.setSpacing(6); + vBox.setMaxWidth(300); + vBox.setAlignment(DevEnv.isDaoActivated() ? Pos.CENTER_RIGHT : Pos.CENTER_LEFT); + vBox.getChildren().addAll(tradeFeeInBtcLabel, tradeFeeInBsqLabel); tradeFeeInBtcToggle = new AutoTooltipSlideToggleButton(); tradeFeeInBtcToggle.setText("BTC"); @@ -1102,10 +1187,6 @@ private void setupTradeFeeFields() { VBox tradeFeeToggleButtonBox = new VBox(); tradeFeeToggleButtonBox.getChildren().addAll(tradeFeeInBtcToggle, tradeFeeInBsqToggle); - tradeFeeDescriptionLabel = new AutoTooltipLabel("Select trade fee currency"); - tradeFeeDescriptionLabel.setId("input-description-label"); - tradeFeeDescriptionLabel.setPrefWidth(170); - HBox hBox = new HBox(); hBox.getChildren().addAll(vBox, tradeFeeToggleButtonBox); hBox.setMinHeight(47); @@ -1113,9 +1194,11 @@ private void setupTradeFeeFields() { HBox.setHgrow(vBox, Priority.ALWAYS); HBox.setHgrow(tradeFeeToggleButtonBox, Priority.NEVER); - tradeFeeBox = new VBox(); - tradeFeeBox.setSpacing(2); - tradeFeeBox.getChildren().addAll(tradeFeeDescriptionLabel, hBox); + final Tuple2 tradeInputBox = getTradeInputBox(hBox, Res.get("createOffer.tradeFee.descriptionBSQEnabled")); + + tradeFeeDescriptionLabel = tradeInputBox.first; + + return tradeInputBox.second; } diff --git a/desktop/src/main/java/bisq/desktop/main/overlays/windows/OfferDetailsWindow.java b/desktop/src/main/java/bisq/desktop/main/overlays/windows/OfferDetailsWindow.java index 247adfce145..555a9f7c5f5 100644 --- a/desktop/src/main/java/bisq/desktop/main/overlays/windows/OfferDetailsWindow.java +++ b/desktop/src/main/java/bisq/desktop/main/overlays/windows/OfferDetailsWindow.java @@ -22,7 +22,6 @@ import bisq.desktop.components.BusyAnimation; import bisq.desktop.main.overlays.Overlay; import bisq.desktop.main.overlays.popups.Popup; -import bisq.desktop.util.FormBuilder; import bisq.desktop.util.Layout; import bisq.core.locale.BankUtil; @@ -286,7 +285,7 @@ else if (BankUtil.isBankNameRequired(countryCode)) if (isF2F) { addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("payment.f2f.city"), offer.getF2FCity()); - TextArea textArea = FormBuilder.addTopLabelTextArea(gridPane, ++rowIndex, Res.get("payment.f2f.extra"), "").second; + TextArea textArea = addConfirmationLabelTextArea(gridPane, ++rowIndex, Res.get("payment.f2f.extra"), "", 0).second; textArea.setText(offer.getF2FExtraInfo()); textArea.setMinHeight(33); textArea.setMaxHeight(textArea.getMinHeight()); @@ -324,7 +323,7 @@ else if (BankUtil.isBankNameRequired(countryCode)) addConfirmationLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, Res.get("offerDetailsWindow.acceptedArbitrators"), formatter.arbitratorAddressesToString(offer.getArbitratorNodeAddresses())); if (offer.getOfferFeePaymentTxId() != null) - FormBuilder.addLabelTxIdTextField(gridPane, ++rowIndex, Res.get("shared.makerFeeTxId"), offer.getOfferFeePaymentTxId()); + addLabelTxIdTextField(gridPane, ++rowIndex, Res.get("shared.makerFeeTxId"), offer.getOfferFeePaymentTxId()); if (placeOfferHandlerOptional.isPresent()) { addTitledGroupBg(gridPane, ++rowIndex, 1, Res.get("offerDetailsWindow.commitment"), Layout.GROUP_DISTANCE); diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/editoffer/EditOfferView.java b/desktop/src/main/java/bisq/desktop/main/portfolio/editoffer/EditOfferView.java index 1ce9a921e3d..43bbef4d7f6 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/editoffer/EditOfferView.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/editoffer/EditOfferView.java @@ -19,6 +19,7 @@ import bisq.desktop.Navigation; import bisq.desktop.common.view.FxmlView; +import bisq.desktop.components.AutoTooltipButton; import bisq.desktop.components.BusyAnimation; import bisq.desktop.main.offer.MutableOfferView; import bisq.desktop.main.overlays.popups.Popup; @@ -39,11 +40,13 @@ import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.image.ImageView; +import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; +import javafx.geometry.HPos; import javafx.geometry.Insets; +import javafx.geometry.Pos; -import static bisq.desktop.util.FormBuilder.addButton; import static bisq.desktop.util.FormBuilder.addButtonBusyAnimationLabelAfterGroup; @FxmlView @@ -168,6 +171,10 @@ private void addConfirmEditGroup() { int tmpGridRow = 4; final Tuple4 editOfferTuple = addButtonBusyAnimationLabelAfterGroup(gridPane, tmpGridRow++, Res.get("editOffer.confirmEdit")); + final HBox editOfferConfirmationBox = editOfferTuple.forth; + editOfferConfirmationBox.setAlignment(Pos.CENTER_LEFT); + GridPane.setHalignment(editOfferConfirmationBox, HPos.LEFT); + confirmButton = editOfferTuple.first; confirmButton.setMinHeight(40); confirmButton.setPadding(new Insets(0, 20, 0, 20)); @@ -176,10 +183,11 @@ private void addConfirmEditGroup() { busyAnimation = editOfferTuple.second; Label spinnerInfoLabel = editOfferTuple.third; - cancelButton = addButton(gridPane, tmpGridRow, Res.get("shared.cancel")); + cancelButton = new AutoTooltipButton(Res.get("shared.cancel")); cancelButton.setDefaultButton(false); cancelButton.setId("cancel-button"); cancelButton.setOnAction(event -> close()); + editOfferConfirmationBox.getChildren().add(cancelButton); confirmButton.setOnAction(e -> { if (model.isPriceInRange()) { diff --git a/desktop/src/main/java/bisq/desktop/util/FormBuilder.java b/desktop/src/main/java/bisq/desktop/util/FormBuilder.java index d8ce61953da..a1c44a6f16a 100644 --- a/desktop/src/main/java/bisq/desktop/util/FormBuilder.java +++ b/desktop/src/main/java/bisq/desktop/util/FormBuilder.java @@ -190,7 +190,6 @@ public static Label addMultilineLabel(GridPane gridPane, int rowIndex, String te label.setWrapText(true); GridPane.setHalignment(label, HPos.LEFT); GridPane.setRowIndex(label, rowIndex); - GridPane.setColumnSpan(label, 2); GridPane.setMargin(label, new Insets(top, 0, 0, 0)); gridPane.getChildren().add(label); return label; @@ -259,6 +258,10 @@ public static Tuple3 addTopLabelTextField(GridPane gridP return new Tuple3<>(topLabelWithVBox.first, textField, topLabelWithVBox.second); } + /////////////////////////////////////////////////////////////////////////////////////////// + // Confirmation Fields + /////////////////////////////////////////////////////////////////////////////////////////// + public static Tuple2 addConfirmationLabelLabel(GridPane gridPane, int rowIndex, String title1, String title2) { return addConfirmationLabelLabel(gridPane, rowIndex, title1, title2, 0); } @@ -276,6 +279,22 @@ public static Tuple2 addConfirmationLabelLabel(GridPane gridPane, return new Tuple2<>(label1, label2); } + public static Tuple2 addConfirmationLabelTextArea(GridPane gridPane, int rowIndex, String title1, String title2, double top) { + Label label = addLabel(gridPane, rowIndex, title1); + label.getStyleClass().add("confirmation-label"); + + TextArea textArea = addTextArea(gridPane, rowIndex, title1); + ((JFXTextArea) textArea).setLabelFloat(false); + + GridPane.setColumnIndex(textArea, 1); + GridPane.setMargin(label, new Insets(top, 0, 0, 0)); + GridPane.setHalignment(label, HPos.LEFT); + GridPane.setMargin(textArea, new Insets(top, 0, 0, 0)); + + return new Tuple2<>(label, textArea); + } + + /////////////////////////////////////////////////////////////////////////////////////////// // Label + TextFieldWithIcon /////////////////////////////////////////////////////////////////////////////////////////// @@ -444,6 +463,8 @@ public static Tuple2 addLabelTxIdTextField(GridPane gridPa public static Tuple2 addLabelTxIdTextField(GridPane gridPane, int rowIndex, String title, String value, double top) { Label label = addLabel(gridPane, rowIndex, title, top); + label.getStyleClass().add("confirmation-label"); + GridPane.setHalignment(label, HPos.LEFT); TxIdTextField txTextField = new TxIdTextField(); txTextField.setup(value); @@ -874,15 +895,23 @@ private static Label getTopLabel(String title) { public static Tuple2 addTopLabelWithVBox(GridPane gridPane, int rowIndex, String title, Node node, double top) { - Label label = getTopLabel(title); - VBox vBox = getTopLabelVBox(0); - vBox.getChildren().addAll(label, node); + final Tuple2 topLabelWithVBox = getTopLabelWithVBox(title, node); + VBox vBox = topLabelWithVBox.second; GridPane.setRowIndex(vBox, rowIndex); GridPane.setColumnIndex(vBox, 0); GridPane.setMargin(vBox, new Insets(top + Layout.FLOATING_LABEL_DISTANCE, 0, 0, 0)); gridPane.getChildren().add(vBox); + return new Tuple2<>(topLabelWithVBox.first, vBox); + } + + @NotNull + public static Tuple2 getTopLabelWithVBox(String title, Node node) { + Label label = getTopLabel(title); + VBox vBox = getTopLabelVBox(0); + vBox.getChildren().addAll(label, node); + return new Tuple2<>(label, vBox); } @@ -951,6 +980,44 @@ public static Tuple3, ComboBox> addTopLabelComboBox return new Tuple3<>(topLabelWithVBox.first, comboBox1, comboBox2); } + /////////////////////////////////////////////////////////////////////////////////////////// + // Label + ComboBox + TextField + /////////////////////////////////////////////////////////////////////////////////////////// + + public static Tuple4, Label, TextField, HBox> addComboBoxTopLabelTextField(GridPane gridPane, + int rowIndex, + String titleCombobox, + String titleTextfield) { + return addComboBoxTopLabelTextField(gridPane, rowIndex, titleCombobox, titleTextfield, 0); + } + + public static Tuple4, Label, TextField, HBox> addComboBoxTopLabelTextField(GridPane gridPane, + int rowIndex, + String titleCombobox, + String titleTextfield, + double top) { + HBox hBox = new HBox(); + hBox.setSpacing(10); + + ComboBox comboBox = new JFXComboBox<>(); + comboBox.setPromptText(titleCombobox); + ((JFXComboBox) comboBox).setLabelFloat(true); + + TextField textField = new JFXTextField(); + + final VBox topLabelVBox = getTopLabelVBox(5); + final Label topLabel = getTopLabel(titleTextfield); + topLabelVBox.getChildren().addAll(topLabel, textField); + + hBox.getChildren().addAll(comboBox, topLabelVBox); + + GridPane.setRowIndex(hBox, rowIndex); + GridPane.setMargin(hBox, new Insets(top, 0, 0, 0)); + gridPane.getChildren().add(hBox); + + return new Tuple4<>(comboBox, topLabel, textField, hBox); + } + /////////////////////////////////////////////////////////////////////////////////////////// // Label + ComboBox + Button @@ -1309,6 +1376,12 @@ public static Tuple2 add2Buttons(GridPane gridPane, public static Tuple2 add2Buttons(GridPane gridPane, int rowIndex, String title1, String title2, double top, boolean hasPrimaryButton) { + final Tuple3 buttonButtonHBoxTuple3 = add2ButtonsWithBox(gridPane, rowIndex, title1, title2, top, hasPrimaryButton); + return new Tuple2<>(buttonButtonHBoxTuple3.first, buttonButtonHBoxTuple3.second); + } + + public static Tuple3 add2ButtonsWithBox(GridPane gridPane, int rowIndex, String title1, + String title2, double top, boolean hasPrimaryButton) { HBox hBox = new HBox(); hBox.setSpacing(10); @@ -1332,7 +1405,7 @@ public static Tuple2 add2Buttons(GridPane gridPane, int rowIndex GridPane.setColumnIndex(hBox, 0); GridPane.setMargin(hBox, new Insets(top, 10, 0, 0)); gridPane.getChildren().add(hBox); - return new Tuple2<>(button1, button2); + return new Tuple3<>(button1, button2, hBox); } /////////////////////////////////////////////////////////////////////////////////////////// @@ -1466,52 +1539,23 @@ public static Tuple3 getEditableValueBoxWithInf return new Tuple3<>(box, infoInputTextField, label); } - public static Tuple3 getNonEditableValueCurrencyBox() { - TextField textField = new InputTextField(); - textField.setPrefWidth(190); - textField.setAlignment(Pos.CENTER_RIGHT); - textField.setMouseTransparent(true); - textField.setEditable(false); - textField.setFocusTraversable(false); + public static Tuple3 getNonEditableValueBox() { + final Tuple3 editableValueBox = getEditableValueBox(""); + final TextField textField = editableValueBox.second; - Label currency = new AutoTooltipLabel(Res.getBaseCurrencyCode()); - currency.setId("currency-info-label-disabled"); + textField.setDisable(true); - HBox box = new HBox(); - box.getChildren().addAll(textField, currency); - return new Tuple3<>(box, textField, currency); + return new Tuple3<>(editableValueBox.first, editableValueBox.second, editableValueBox.third); } - public static Tuple3 getNonEditableValueCurrencyBoxWithInfo() { - InfoTextField infoTextField = new InfoTextField(); - infoTextField.setIconsLeftAligned(); - TextField textField = infoTextField.getTextField(); - textField.setPrefWidth(190); - textField.setAlignment(Pos.CENTER_RIGHT); - textField.setMouseTransparent(true); - textField.setEditable(false); - textField.setFocusTraversable(false); + public static Tuple3 getNonEditableValueBoxWithInfo() { - Label currency = new AutoTooltipLabel(Res.getBaseCurrencyCode()); - currency.setId("currency-info-label-disabled"); + final Tuple3 editableValueBoxWithInfo = getEditableValueBoxWithInfo(""); - HBox box = new HBox(); - box.getChildren().addAll(infoTextField, currency); - return new Tuple3<>(box, infoTextField, currency); - } + TextField textField = editableValueBoxWithInfo.second.getInputTextField(); + textField.setDisable(true); - public static Tuple3 getAmountCurrencyBox(String promptText) { - InputTextField input = new InputTextField(); - input.setPrefWidth(190); - input.setAlignment(Pos.CENTER_RIGHT); - input.setPromptText(promptText); - - Label currency = new AutoTooltipLabel(Res.getBaseCurrencyCode()); - currency.setId("currency-info-label"); - - HBox box = new HBox(); - box.getChildren().addAll(input, currency); - return new Tuple3<>(box, input, currency); + return editableValueBoxWithInfo; } ///////////////////////////////////////////////////////////////////////////////////////////