+1 vote

My goal is for the Esc key to work intuitively with my game's menu system such that pressing it dismisses the top-level window.

I have created a button shortcut keyed off the ui_cancel action that is associated with Esc. As anticipated, pressing the key triggers the button's pressed signal and performs the function of closing the window.

The problem that I am encountering is that SceneTree.SetInputAsHandled() is not called, so a single key press dismisses all open windows, not just the top-most one.

Is there a setting somewhere that I missed?

asked Jul 18 in Engine by JimArtificer (852 points)

2 Answers

0 votes
Best answer

Here is the solution that I settled on:

  • Convert the root node of the dialog window scenes I created to be of type Popup.
  • Open the windows with the popup_centered() function. (There are variants of the popup function that can set the size.)
    https://docs.godotengine.org/en/stable/classes/class_popup.html#methods
  • Rely on the default Popup handling of the ui_cancel action to close the top window.
  • Give the (invisible) root Popup node a full rect layout to prevent clicks outside the window from closing it.

    • Note: This is done because Popup.Exclusive will prevent clicks outside the window from closing it, but will also ignore ui_cancel.

Also note that there is a show_modal() function on the Control node, but this does not seem to function for Controls that are not children of Popup.

answered Jul 19 by JimArtificer (852 points)
0 votes

had a similar problem
'solved' it by only setting the shortcut when the dialog becomes active
and storing the ui stack so i can restore shortcuts and focus when 'active window' changes

func _clearFocus() -> void:
    var accept = _acceptStack[0]
    if accept != null: accept.shortcut = null
    var cancel = _cancelStack[0]
    if cancel != null: cancel.shortcut = null

func _applyFocus() -> void:
    _focusStack[0].grab_focus()
    var accept = _acceptStack[0]
    if accept != null: accept.shortcut = _accept
    var cancel = _cancelStack[0]
    if cancel != null: cancel.shortcut = _cancel

func _popFocus() -> void:
    _clearFocus()
    _focusStack.pop_front()
    _acceptStack.pop_front()
    _cancelStack.pop_front()
    _applyFocus()

func _pushFocus(focus: Control, accept: Control, cancel: Control):
    _clearFocus()
    _focusStack.push_front(focus)
    _acceptStack.push_front(accept)
    _cancelStack.push_front(cancel)
    _applyFocus()

func _focus(focus: Control, accept: Control, cancel: Control):
    _clearFocus()
    _focusStack[0] = focus
    _acceptStack[0] = accept
    _cancelStack[0] = cancel
    _applyFocus()
answered Jul 19 by rakkarage (1,300 points)

Thank you for the answer. I have also posted my solution.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.