godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.12k stars 69 forks source link

Allow Controls to automatically release focus when clicked off of #6501

Open 20milliliter opened 1 year ago

20milliliter commented 1 year ago

Describe the project you are working on

An application containing many Line/TextEdits and the like.

Describe the problem or limitation you are having in your project

Controls do not release focus when clicked outside of, and manually connecting to mouse_exited() on every one is not reasonable.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

Add an focus_release_on_outside_click option to Control to enable whether it should automatically release focus. Alternatively, add a new value for focus_mode to enable this behavior.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

On mouse click, the currently focused node releases focus if the click was outside of its boundaries.

If this enhancement will not be used often, can it be worked around with a few lines of script?

class_name FocusAutoReleaseControl extends Control

func _input(event):
    if not self.has_focus(): return
    if not event is InputEventMouseButton: return
    if not event.pressed: return
    var control_rect = self.get_rect()
    control_rect.position = Vector2.ZERO
    var local_rect = control_rect
    if local_rect.has_point(get_local_mouse_position()): return
    self.release_focus()

However, this only works if the given Control does not need to be extended by another script, as GDScript lacks multiple inheritance.

Is there a reason why this should be core and not an add-on in the asset library?

See above.

TheDuriel commented 1 year ago

Generally this is not going to be desirable. As it leaves a user without the ability to regain focus again.

For example, in most software I am familiar with, clicking on "nothing" may visually hide focus. But focus will continue from that element if the user starts using the arrow keys to navigate.

In game, I would not want to lose focus of a menu element if I click somewhere else. And I would expect focus to continue operating even if I do, and then try to change it using the arrow keys.


Consider that you can achieve the same behavior by placing a plain Control node as an invisible background, with mouse mode set to pass, and enable focus grabbing on that Control mode.

This means that if the user clicks "nothing", they will actually click on and grab focus with this control node. Which doesn't actually do anything with said focus afterwards. This also gives you one concrete place from which you can tell if the user has clicked "nothing".


You can also turn you example code into a generic component. Extend Node instead of Control, connect to the parents _gui_input() signal.

Calinou commented 1 year ago

For example, in most software I am familiar with, clicking on "nothing" may visually hide focus. But focus will continue from that element if the user starts using the arrow keys to navigate.

We could do something similar once that proposal is implemented.

20milliliter commented 1 year ago

For example, in most software I am familiar with, clicking on "nothing" may visually hide focus. But focus will continue from that element if the user starts using the arrow keys to navigate.

Fair. However, in the case of a text box, clicking on nothing also cancels editing if it was taking place. This is a change in functionality, not just visuals. #2011 would not suffice. [EDIT: After trying more things out I did find a few exceptions that does not cancel editing, only hiding the cursor. However, with most software I have, this behavior is the exception.]

No such "focus-limbo" state is possible with Line/TextEdits currently.


Consider that you can achieve the same behavior by placing a plain Control node as an invisible background, with mouse mode set to pass, and enable focus grabbing on that Control mode.

Could you explain this in more detail? I tried it and could not get it to work as you describe.

Swarkin commented 1 year ago

Any news on this? No option for automatic release of focus is the only thing that's been bothering me with this system.

TheDuriel commented 1 year ago

Place a control node behind your UI which acquires focus and does nothing, same effect. There's reason why this should not be a feature.

20milliliter commented 1 year ago

Could you explain this in more detail? I tried it and could not get it to work as you describe.

TheDuriel commented 1 year ago

A plain Control node. Focus enabled. Put behind all your other UI. There's nothing else to it.

Animeu commented 8 months ago

A plain Control node. Focus enabled. Put behind all your other UI. There's nothing else to it.

This does not work if you click on a control that has focus mode None and mouse filter Stop. That control will prevent clicking on the background control and focus will still present on the old control

Kris-kun commented 1 month ago

My suggestion: Add the focus_release_on_outside_click checkbox OP mentioned. If it's true and you click outside this control, the focus should be removed from this control (or set to the clicked control). The Scene could keep a reference to the last focused control. If you press a focus changing button (tab etc.), the last focused control should be focused again. If the last focused control does not exist (anymore), focus the first node that can be focused.

Would that be possible?

This would also partially fix a problem i have. I have a menu where i don't want to see any focused control as long as i click them with my mouse. When i press tab etc. for the first time, i want a control to take focus, but release the focus again when i click with my mouse. I would need a focus mode All except Click for this though.