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
Improves some text field behavior. #8118
Conversation
name.OnEscKey = () => | ||
{ | ||
name.Text = c.Name; | ||
Ui.Root.Get<TextFieldWidget>("CHAT_TEXTFIELD").TakeKeyboardFocus(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a generic utility function, so shouldn't make any assumptions about the UI state. You could instead pass in a defaultFocus
widget, and then give that focus if it is non-null.
I think the idea behind this is good, but the implementation introduces some unsettling coupling. I think a better approach would be to add a FocusPriority integer to widgets, and then have YieldFocus walk the tree and automatically focus the highest priority (> 0) widget that is visible. |
00de59a
to
ea48d38
Compare
OK I implemented keyboard focus management as a stack. When a widget takes focus, it adds itself on top of the stack. When it yields focus, it removes itself from the stack so the one below it becomes the current focus. This also allows for automatic focus yielding at widget removal since ForceYieldKeyboardFocus() method is called when a widget is removed. When the map chooser window for example is closed, its focus is removed from the stack and the chat text field of the lobby automatically gets the focus. There is no need to manually yield focus at widget removal or window closure. |
@@ -24,9 +24,9 @@ public static class Ui | |||
public static int LastTickTime = Game.RunTime; | |||
|
|||
static readonly Stack<Widget> WindowList = new Stack<Widget>(); | |||
static readonly Stack<Widget> KeyboardFocusWidget = new Stack<Widget>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't a widget anymore.
I fixed the issues Phrohdoh pointed out. |
32b9ad9
to
722b726
Compare
} | ||
|
||
public virtual bool TryYieldKeyboardFocus() | ||
{ | ||
return true; | ||
} | ||
|
||
public virtual bool YieldKeyboardFocus() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are YieldKeyboardFocus() and TakeKeyboardFocus() virtual? Shouldn't only TryYieldKeyboardFocus() be virtual so a subclass can add conditions for yielding focus?
bb9e5e0
to
dffa9ae
Compare
Can you elaborate on that? What gets improved/changed? |
Here's what this PR does:
|
Rebased. |
@@ -24,9 +24,9 @@ public static class Ui | |||
public static int LastTickTime = Game.RunTime; | |||
|
|||
static readonly Stack<Widget> WindowList = new Stack<Widget>(); | |||
static readonly Stack<Widget> KeyboardFocusList = new Stack<Widget>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't these be called WindowStack and KeyboardFocusStack? Since List is a different type of collection.
ca5ebb5
to
1c2e482
Compare
I changed the focus management from stack to widget priority. @pchote was right, it's much better and simpler now. |
c94dbfb
to
0a886b5
Compare
Not really sure what has changed now. Pressing ESC seems to do the same as before and TAB cycling does nothing. I thought that was the addition here. |
Pressing Esc switches text field focus? It should only remove focus and not give it to another text field... And this doesn't implement tab cycling. I just tested it and when you press Esc in settings text field, it only removes focus. So the issue you mentioned there should be fixed. Does this not work like this for you? |
I see. ESC seems to do nothing there in current bleed so this works as promised. ✅ |
This still doesn't look right: you've removed the tracking of the currently focused keyboard widget, and added tracking of the current priority (which is a different thing)...? At best this appears to walk the whole widget tree each key press to find the current widget, but at worst there may be cases where this directs input to the wrong widget. |
Reviewers please note that this is a significant change to the core input plumbing, and it must be reviewed based on design as well as function. "works as promised" isn't sufficient criteria for merging if it hurts performance or generally muddies the engine code. |
Yes, for each key press, this walks the whole widget tree but only those that are visible. Currently focused widget is the one that has the highest priority. I think if the priorities are set correctly and widgets that are not visible have correct IsVisible() value, this wouldn't direct input to wrong widget. Since TakeKeyboardFocus() calls are not necessary now, priority is the only thing that determines focus. So there is no difference between current focus and highest visible priority... |
The idea of having a focus priority assigned for each widget, and using this to decide what widget should be focused when you don't have an explicit assignment is good (and this was what I asked for originally). Removing the focus tracking, and instead manipulating the widget focus priorities at runtime (and then walking the widget tree for every keyboard event) is not good. Please reintroduce |
OK, I'll change this like that. |
Also improves some text field behavior.
When should
What about tabs? It would also need to be called when the active tab is changed. And ingame chat widget would also need it I think... So this would make it more complicated than it currently is. And the benefit would be caching the current focus widget and not checking widget tree at every key press. But is this worth it? Currently, this code checks the entire Which one is better, checking highest priority at each key press and eliminating the use of |
And I just realized, in the current version, it is not necessary to call |
Actually, focus caching would be implemented with a separate |
OK, current focus widget must be cached because So, for TextField widgets, this patch in fact walks widget tree in every tick, not just at every key press! So... how should I do this for tabs? Manually adding |
As I understand, this is potentially quite dangerous. Also nobody seems to be willing to review it. Can you please explain in short what this PR does, why, and how, so we can decide if it's something we actually want? |
I decided to scrap the focus management idea and opened a different PR with just the text field improvements: #8680. |
A priority based automatic focus management would be better but I couldn't do it in a simple way... |
This patch improves text field behavior in game lobby, settings menu and asset browser.