Skip to content

Add allow_close[] element to formspecs #15971

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 16, 2025

Conversation

v-rob
Copy link
Contributor

@v-rob v-rob commented Apr 2, 2025

Fixes #10380.

  • Adds a new allow_close[<bool>] element that prevent the user from closing the formspec. Main menu code uses this option.
  • Uncloseable formspecs can still be closed with button_exit[].
  • Attempts to close an uncloseable formspec result in the try_quit event field. This distinguishes real quits from attempts to quit, and allows mods to have custom exit behavior.

To do

This PR is Ready For Review. However, how to handle the pause menu for uncloseable menus is still up for debate. Currently Ctrl + Escape exits to menu as an escape hatch.

How to test

Make sure that all of the main menu formspecs are uncloseable (including with Ctrl + Escape) while everything else remains closeable. /test_formspec has a bit of uncloseable testing code as well.

@v-rob v-rob force-pushed the uncloseable-formspecs branch from f446345 to f6c2e75 Compare April 2, 2025 04:15
@v-rob v-rob added @ Script API Roadmap The change matches an item on the current roadmap Feature ✨ PRs that add or enhance a feature Formspec UI/UX labels Apr 2, 2025
@Zughy
Copy link
Contributor

Zughy commented Apr 2, 2025

feedback on how to handle the pause menu for uncloseable menus

Should we? If the game is poorly designed, it's not really our fault. Like, the best solution is probably to overlap the two menus when Esc is pressed, but I'm pretty sure it's not doable at the moment; we could swap them and go back to the formspec when pause menu is closed. At the same time, a case like @rollerozxa 's wouldn't really appreciate to pause the game main screen. An unpausable[] element? Maybe just for game devs with the debug privilege we could have a shortcut e.g. Ctrl + Esc?

Will this also fix the annoyance of closing Luanti by accident when pressing Esc in the main menu? There probably was an issue about it

@Wuzzy2
Copy link
Contributor

Wuzzy2 commented Apr 2, 2025

As I wrote elsewhere already, I think it is very important to have at least SOME emergency exit in case a game has a buggy formspec that the player cannot escape from.

Yes, "If the game is poorly designed, it's not really our fault.", BUT it would be still very annoying if a bad game forces players to kill Luanti entirely. That would be a downgrade, because currently, a broken game just returns you to the main menu. So please do not ignore the emergency exit.

Like, the best solution is probably to overlap the two menus when Esc is pressed, but I'm pretty sure it's not doable at the moment; we could swap them and go back to the formspec when pause menu is closed.

But what happens if there are multiple minetest.show_formspec calls while the player is still in pause? Swapping doesn't sound right. I think the game client could internally store the current active game formspec in some variable, and it is always stored there, independent from the pause menu. With game formspec I mean any formspec caused by the game, so engine formspecs like the pause menu do NOT count.
The game basically only decides to not render this "active formspec" while the pause menu is open, because it renders the pause menu instead. So my solution is keeping track of the active game formspec at all times (even during an open pause menu), but it is only rendered when the pause menu is not shown.

At the same time, a case like @rollerozxa 's wouldn't really appreciate to pause the game main screen. An unpausable[] element? Maybe just for game devs with the debug privilege we could have a shortcut e.g. Ctrl + Esc?

Wait, what? No, that's a terrible idea. Exiting the game should be just a clientside feature, privileges should be completely irrelevant. We're not suggesting to "pause the main screen". The name "pause menu" is kind of a misnomer. What we really mean is the menu that appears when you hit Esc . It only actually pauses in singleplayer (where this issue does not even apply). In multiplayer, it does NOT pause and we don't want it to pause during multiplayer. So we only mean the menu in multiplayer.

@rubenwardy
Copy link
Contributor

We already support multiple Menus - the url open dialog is shown as a modal from formspecs, for example.

So there would be multiple GUIFormspecMenu instances, the root one would be updated by show_formspec but the pause menu is shown instead of that when active

@rubenwardy
Copy link
Contributor

also closeable[false] or prevent_closing[] might be clearer than uncloseable. Other GUI libraries call this cancelable

@rubenwardy
Copy link
Contributor

Another thing is that it's already possible to wreck the pause menu with prepends (unless that was fixed). So this wouldn't change anything in terms of security, just in terms of accidentally making poor UX

@appgurueu
Copy link
Contributor

We already support multiple Menus - the url open dialog is shown as a modal from formspecs, for example.

Yes. There is a very barebones implementation for "stacking" menus virtually in mainmenumanager.(cpp|h). It should be possible to use that here.

You can pass a GameFormSpec* around till you get it to GUIFormSpecMenu so you can open the pause menu from there - without closing the underlying formspec. (Something might not work quite as expected here, though - when I tried this, the pause menu somehow became uncloseable, and I haven't yet looked into why, but maybe I made a mistake elsewhere.)

@Zughy Zughy added this to the 5.12.0 milestone Apr 2, 2025
@Zughy
Copy link
Contributor

Zughy commented Apr 2, 2025

(I've put the PR in the 5.12 milestone due to the high priority label of the issue)

@v-rob
Copy link
Contributor Author

v-rob commented Apr 2, 2025

We already support multiple Menus - the url open dialog is shown as a modal from formspecs, for example.

So there would be multiple GUIFormspecMenu instances, the root one would be updated by show_formspec but the pause menu is shown instead of that when active

This is definitely how we'd want to implement this. I would first want to check that GUIFormSpecMenu isn't mutating any global state behind the scenes anywhere since it's a big ball of mud, but otherwise having multiple instances of it seems like the most obvious choice to me.

@v-rob
Copy link
Contributor Author

v-rob commented Apr 2, 2025

More daring is the idea of changing the key to exit an in-game formspec. Maybe one of the function keys? Tab? And then Esc is reserved exclusively for the pause menu (so an Esc press is never "seen" by the game, only by Luanti), and it can be opened even if a formspec is open. I am sure this idea will be very controversial.

(From @Wuzzy2 in the issue) This isn't terrible in some respects, since a pause menu should be accessible from anywhere. We already support closing formspecs with the inventory button (although it doesn't work directly in text fields). However, it strongly violates the principle of least surprise--coming to Luanti with no experience, I would expect Escape to get me out of whatever GUI I'm looking at.

It could also be argued that the pause menu should be customizable by the game anyway, rather than being hardcoded. In that case, there could be a bifurcation between the game pause menu (accessible by Escape only from outside a formspec, customizable like the inventory and death screen) and the current built-in Luanti pause menu (as an emergency escape, available anywhere). I still don't like this from a user point of view.

So far, my favorite solution is to use Ctrl + Escape, either to open the pause menu or to exit the game entirely. And given that the pause menu can't be opened directly from existing formspecs, and that doesn't seem to bother most people, the latter option might be for the best.

@Desour
Copy link
Member

Desour commented Apr 2, 2025

How about holding esc for longer (e.g. a second) to always open the pause menu? Might be more intuitive than ctrl esc.

@v-rob v-rob force-pushed the uncloseable-formspecs branch from f6c2e75 to 91bf635 Compare April 2, 2025 23:57
@v-rob v-rob changed the title Add uncloseable[] element to formspecs Add allow_close[] element to formspecs Apr 2, 2025
@v-rob v-rob force-pushed the uncloseable-formspecs branch from 91bf635 to 6353b92 Compare April 3, 2025 00:33
@v-rob
Copy link
Contributor Author

v-rob commented Apr 3, 2025

I have implemented Ctrl + Escape to automatically exit to menu whenever a formspec is open (and fixed a bug in the process where a formspec would stay open for a moment after "Shutting down" appears when the X button is pressed). The best solution is still open for debate.

I have also renamed the element to allow_close[], which seems clearer.

@v-rob v-rob marked this pull request as ready for review April 3, 2025 00:43
@v-rob
Copy link
Contributor Author

v-rob commented Apr 4, 2025

On further thought, I would argue that Ctrl + Escape to exit as in this PR is the correct implementation. Aside from concerns about malicious servers (which we have no protection against as it is!), there is no reason why the pause menu must be hardcoded, but could easily be customizable like the inventory or death screen, with Ctrl + Escape is always there as a failsafe.

Consider the following game flow: when a new player joins, they are shown a formspec with allow_close[false] that requires them to do some configuration before they are allowed to do anything else. If they try to escape out of it, they are shown a dialog that asks if they want to abort and exit the game. This is actually better UX than showing the generic pause menu.

Additionally, consider a competitive server or one with some sort of minigames. If a user wants to exit the minigame, what better place to put the button than in the pause menu next to the buttons that allow the user to exit the server? Certainly, one can (ab)use the inventory screen for this, but that's not ideal, especially if it's already being used for something else. Naturally, you'd need special functionality, e.g. a method of programmatically opening Luanti's settings menu, but that gives modders more useful control, not less.

Basically, if we hardcode the pause menu to open on allow_close[false], that's a point against modders having fine control over their UX. It wouldn't ruin everything by any means, but I think we should strive towards the ideal of modders having the control in this case.

Copy link
Contributor

@appgurueu appgurueu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good:

  • Test formspec works as expected; Ctrl + Esc works
  • All main menu (not pause menu settings) formspecs have allow_close[false] set
  • Main menu works as expected
  • C++ looks ok

Remaining questions:

  • Shouldn't dlg_version_info.lua have allow_close[false] as well?
  • It seems to me that the try_quit field might obsolete the MenuQuit "event"?
  • Shouldn't menu_lua_api.md document that allow_close[false] should be used, and that exit buttons should not be used?
  • Where is Ctrl + Esc documented; what do Android players do?

@v-rob
Copy link
Contributor Author

v-rob commented Apr 6, 2025

  • Shouldn't dlg_version_info.lua have allow_close[false] as well?

Must have missed that somehow, thanks. I'll give another, more careful look through builtin.

  • It seems to me that the try_quit field might obsolete the MenuQuit "event"?

The gotText calls are used for the main menu. I haven't looked into them and whether they can be obsoleted, but that is a little more extensive refactor. May be out of scope for this PR, but I'll look into it.

  • Shouldn't menu_lua_api.md document that allow_close[false] should be used, and that exit buttons should not be used?

Fair point; I did not remember the existence of that document.

  • Where is Ctrl + Esc documented; what do Android players do?

Doh! I meant to add it to the keys in README.md. Is there anywhere else keys are documented in the main repo?

As for Android, closing the app is always possible, but is suboptimal in a similar vein to Alt + F4. I'm open to suggestions, but I don't know what touchscreen scheme would make sense. On the bright side, all Android users should know how to close an app, whereas you can't expect all desktop users to know about Alt + F4. (They may not know about Ctrl + Escape either, but at least it will be documented...)

@v-rob
Copy link
Contributor Author

v-rob commented Apr 7, 2025

Added the docs and the missing allow_close[false] element. I don't want to remove any of the gotText() stuff in this PR since the necessary changes would run too deep.

@v-rob v-rob changed the title Add allow_close[] element to formspecs Add allow_close[] element to formspecs Apr 8, 2025
@grorp grorp added the Action / change needed Code still needs changes (PR) / more information requested (Issues) label Apr 15, 2025
@v-rob v-rob removed the Action / change needed Code still needs changes (PR) / more information requested (Issues) label Apr 15, 2025
Copy link
Member

@grorp grorp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Appears to work

For the Ctrl+Esc thing, I don't think there's a reasonable equivalent on Android, but I suppose users should be able to close the app just fine via the "Recents" screen if they need to

@v-rob v-rob force-pushed the uncloseable-formspecs branch 2 times, most recently from 7ad767b to 67ef3cc Compare April 16, 2025 06:12
@v-rob v-rob force-pushed the uncloseable-formspecs branch from 67ef3cc to b5dc0a6 Compare April 16, 2025 06:56
@v-rob v-rob merged commit fd85737 into luanti-org:master Apr 16, 2025
20 of 24 checks passed
@v-rob v-rob deleted the uncloseable-formspecs branch April 16, 2025 23:23
mjz19910 pushed a commit to mjz19910/luanti that referenced this pull request Apr 18, 2025
@grorp
Copy link
Member

grorp commented Apr 19, 2025

@v-rob looks like this is missing a formspec version bump and an entry in the formspec "Version History" section in lua_api.md

EDIT: now planning to bump in #16042

@v-rob
Copy link
Contributor Author

v-rob commented Apr 19, 2025

Ack! I completely forgot about that. I will make a patch for that if #16042 doesn't go through soon.

@Desour
Copy link
Member

Desour commented Apr 22, 2025

Ctrl + esc seems to open the start menu for me (LXDE, I didn't change that keybind). So it doesn't reach luanti.
And there's no option to change the keybind in luanti. :/

@sfan5
Copy link
Collaborator

sfan5 commented Apr 22, 2025

How about shift+esc? Or alt+esc?

@Desour
Copy link
Member

Desour commented Apr 22, 2025

How about shift+esc? Or alt+esc?

My actual shift key is broken x), the key I use for shift + esc doesn't seem to be bound. Alt+esc is bound (switches window focus).
For my case, I can also unbind ctrl+esc in my window manager, but other users may also have issues, also with other key combos.
Allowing any of alt/ctrl/shift + esc could be a good quick improvement. Having it bindable would be better though.

@v-rob
Copy link
Contributor Author

v-rob commented Apr 22, 2025

Bindable doesn't make too much sense to me, since you can't bind normal Esc. It could make sense to want to bind it to one of the F1 - F12 keys, but it would be strange to bind it to any key that has some function within a formspec or input field.

Shift + Esc is used in Firefox to open the Process Manager, so that's probably a safe keybinding to use. I doubt a major web browser would use keybindings reserved by some window managers.

@Desour

This comment was marked as off-topic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature ✨ PRs that add or enhance a feature Formspec One approval ✅ ◻️ Roadmap The change matches an item on the current roadmap @ Script API UI/UX
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Option to prevent formspecs to be closed
8 participants