fjvallarino / monomer

An easy to use, cross platform, GUI library for writing Haskell applications.
BSD 3-Clause "New" or "Revised" License
577 stars 42 forks source link

Feature Request: Allow popups to be closed when an internal button is pressed. #322

Open fallen-icarus opened 3 months ago

fallen-icarus commented 3 months ago

I am trying to use a popup menu of buttons that then directs the user to different widgets depending on what button is pressed. The popup can nicely hide the list of possible actions to minimize clutter. What I have is effectively a vstack of buttons that appears when the popup is opened. However, currently when a button inside a popup is clicked, the popup is not closed despite the button action occurring. Therefore, when the user is moved to the new widget, the UI is effectively frozen since the popup blocks all events to the new widget. I would like the popup to automatically close once the user clicks one of the buttons inside of the popup.

I got it to work by altering the code for the popup widget:

I understand not everyone may want this functionality so is there any way to make this configurable? I have not tried it, but I think it is also possible to use a dropdown menu. However, the popup seems more intuitive and the type signatures are more inline with the behavior I am after.

Deltaspace0 commented 3 months ago

Isn't it possible to just do something like that: popup `nodeVisible` showPopup showPopup is a field in your App state and the button toggles this state

Deltaspace0 commented 3 months ago

Here's example: https://github.com/Deltaspace0/monomer-chess/blob/master/src/UI.hs widgetIf _amShowPromotionMenu promAlert promAlert is popup widget and _amShowPromotionMenu is a field. When button inside is clicked, the event sets this field to False and the popup is automatically closed.

fallen-icarus commented 3 months ago

I appreciate the quick response!

Neither widgetIf nor nodeVisible work for me. I already have a showPopup field in my app state that gets set to False whenever any of the inner buttons are clicked. But the new widget that appears is always frozen.

It looks like your popup brings up an alert widget; I don't think this is the same as what I am trying to do. The alert widget has a close button; the close button for the alert widget is meant to remove the alert widget from the tree. My buttons add a widget to the tree; it brings the user to a new form that when closed, returns the user to the widget with the popup. Like I said, I am able to click buttons inside the popup which would be the close button for the alert widget. However, I am unable to interact with any widgets that get added to the tree due to clicking buttons in the popup. So the apples-to-apples comparison would be if your alert's close button actually caused a new widget with buttons to appear on top of the alert that was opened by the popup.

I apologize if this wording is confusing. I am new to front-end stuff. Here is a snippet from my code:

morePopup :: AppModel -> AppNode
morePopup _ = do
  vstack
    [ tooltip_ "More" [tooltipDelay 1000] $
        button remixMoreLine (HomeEvent ShowMorePopup)
    , customPopup (toLensVL $ #homeModel % #showMorePopup) $
        vstack
          [ button "Edit Name" (HomeEvent $ ChangePaymentWalletName StartAdding)
          , separatorLine `styleBasic` [fgColor black, padding 5]
          , button "Delete Wallet" (HomeEvent $ DeletePaymentWallet GetDeleteConfirmation)
          ]
    ]

editPaymentWalletWidget :: AppModel -> AppNode
editPaymentWalletWidget _ = do
  let editFields = 
        vstack_ [childSpacing]
          [ hstack 
              [ label "Wallet Name:"
              , spacer
              , textField (toLensVL $ #extraTextField) 
                  `styleBasic` [width 500]
              ]
          ]

  centerWidget $ vstack 
    [ editFields
    , spacer
    , hstack 
        [ filler
        , mainButton "Confirm" $ HomeEvent $ ChangePaymentWalletName ConfirmAdding
        , spacer
        , button "Cancel" $ HomeEvent $ ChangePaymentWalletName CancelAdding
        ]
    ] `styleBasic` [bgColor customGray3, padding 20, width 700]

confirmDeleteWidget :: AppModel -> AppNode
confirmDeleteWidget model = do
  centerWidget $ vstack_ [childSpacing]
    [ spacer
    , centerWidgetH $ label $ mconcat
        [ "Are you sure you would like to delete '"
        , model ^. #homeModel % #selectedWallet % #alias
        , "'?"
        ]
    , hstack 
        [ filler
        , mainButton "Confirm" $ HomeEvent $ DeletePaymentWallet ConfirmDeletion
        , spacer
        , button "Cancel" $ HomeEvent $ DeletePaymentWallet CancelDeletion
        ]
    ] `styleBasic` [bgColor customGray3, padding 20, width 700]

In my morePopup, I am able to click either the "Edit Name" button or the "Delete Wallet" button (these buttons are at the same level as your close alert button). Depending on which is clicked, the UI either brings up the editPaymentWalletWidget or the confirmDeleteWidget. Both widgets have their own buttons and fields to interact with, and both widgets are frozen if they are opened by buttons within the popup.