focusPrevious()

Started by Heinrich, 29 August 2013, 13:07:31

Heinrich

Hello again,

How about you add focusPrevious() to widget class. So you can easily make your gui keyboard navigable. Of course you could do this by retaining some pointers to the widgets and handle it all manually, but in the simplest case, you would add some buttons and call focusNext() and focusPrevious() when Left or Right key is pressed.
I suppose I could do this as well by adding the widgets into a grid and use get(), but it would be a nice convenience function.
Also, I added some small issue on your bug tracker, which is well hidden.

glhf
Heinrich

texus

I currently don't have much time, but such function could indeed by handy so I'll add it soon (within a week or so).

It will require me to write some extra code, because the focusNextWidget was actually pretty simple. It just calls the unfocus function of the parent, knowing that that will lead to the next widget being focused. A focusPreviousWidget function would have to really look for the right widget to focus.

When I add the function I will also make another change. I don't think focusNextWidget should be in Widget, so I'll probably move it to Container and then add the focusPreviousWidget to Container (so you call gui.focusNextWidget()).

Heinrich

What would happen if there is no next or previous widget?I think the first widget in the same hierarchy level should be called.

From the class hierarchy I infer that if you put it in Container, you would no longer be able to do the following (since I noticed tgui::Gui does not inherit from Container, as I would have expected):

button0(gui)
button1(gui)

if(LeftKey) gui.focusPrevious();
else if(RightKey)gui.focusNext();

So Containers would be mandatory from then on. I suppose adding widgets directly to gui is only for quick demonstration anyway.

Heinrich

I just tested navigation with keyboard and noticed that the hover image does not get used when a widget is focused. How can I manually set a widget as "being hovered on"?

texus

Gui is a special case. It is only not inheriting from Container (anymore) because it solves other design problems. Whatever gets added to Container will also be added to Gui, so you don't have to worry about Gui not having those functions.

QuoteI just tested navigation with keyboard and noticed that the hover image does not get used when a widget is focused.
The focus image is drawn on top of the normal and hover ones, so if your focus image isn't transparent then you won't see the hover image. Or are u using the Black style?

QuoteHow can I manually set a widget as "being hovered on"?
You normally don't do this, so there is no function to do so. You could always call the mouseMoved function with mouse coordinates that lie on top of the widget, but this will be undone when then moving the mouse again. Basically you just aren't supposed to do this.

QuoteWhat would happen if there is no next or previous widget?
I think it is most logical that the widget stays focused and nothing changes (Currently the widget gets unfocused).

Heinrich

QuoteThe focus image is drawn on top of the normal and hover ones, so if your focus image isn't transparent then you won't see the hover image.
That is good to know.

QuoteOr are u using the Black style?
I do.

Heinrich

"SeparateHoverImage = false" in Black.conf

Oh, I see. ::)

Heinrich

Well, I am confused. What is the focusedImage? From what I can see it is neither defined in Black nor BabyBlue. Is there even such a thing? There seems to be no change in appearance at all whether a Button is focused or not.

texus

#8
Maybe I should explain a bit how I got to the current design (of which parts still date back from the first release).
I had a bit of a problem with hover and focused images in the past. If those would be two different images, which one would you display when the button is both focused and hovered? At that time, both hover and focus images were transparent and drawn on top of the normal image, so that it looked good. Later I decided that hover images shouldn't always be transparent and I added a SeparateHoverImage image flag to control whether or no the hover image was drawn on top of the normal image or it would be a seperate image. Focus image however remained being drawn on top of the hover image to avoid the question of which of the two should be visible.

And then the part why there isn't a focused image in the black style.
Although tgui supports using the tab key to focus the next widget, tgui aims mostly on games. So this is a very unneeded possibility. Because in games you normally don't need a focused image (with what you are doing now as an exception), the focused images were removed from the default styles.

What you want to do, is make a copy of the Black.conf file and add the following lines to the Button section:
FocusedImage_L = "Black.png" (  0, 175,  50, 50)
FocusedImage_M = "Black.png" ( 50, 175, 100, 50)
FocusedImage_R = "Black.png" (150, 175,  50, 50)

And then load your edited version instead of Black.conf.

That will give the buttons back their focus images, allows them to be focused again, and will most likely solve #14 that you just created on github.

Edit: I should have noticed this earlier, but I must have missed the link that we were talking about focusing stuff while focus images were removed in the default style.

Heinrich

Hi texus,

Specifying the focus image in the .conf worked well, thank you for the clarification.
The bug issued ("Some Button::ButtonCallbacks not working") did not have anything to do with it, it is completely separate. I wanted to navigate the menu with the keyboard (which works fine now, I used setTextColor intermediately to hint at which button was focused, but now it works thanks to your help) and receive a callback when Return was pressed, which still doesn't. If I set the callback to "LeftMouseClicked" it works fine. I guess I can do a workaround by asking if sf::KeyBoard::isPressed(Return) and which button is currently focussed but I thought I would inform you, because unlike my previous ticket this looks like a genuine bug.

Heinrich

#10
By the way, I looked at some GUI frameworks in the past (namely sfgui), and I noticed nobody really does KeyBoard input. Which is strange, since I would have guessed that at least some people would make games that are supposed to be played with a gamepad. Especially all those "retro"-games.
Most of which, by the way I find quite alienating, for example because when I played them back then I'm quite fond to remember they tried everything to conceil pixelated fonts, not make them deliberately look blocky. I mean, why would you want a blocky font when clearly all sprites are in -and move at-  a much higher resolution. But I digress..
Well, anyway, being easily Keyboard-navigable (thus gamepad- or more generally mouseless-navigable) could be the distinct feature of your framework.

texus

Keyboard navigation is basically impossible to do directly in a gui library.
When in the menu, you might want to use the up and down arrow keys to navigate, but in the game the arrow keys shouldn't influence the buttons you have on your screen. So a gui lib can never respond directly to arrow keys, you have to handle everything yourself because you know exactly when everything should happen. But having focusPreviousWidget and focusNextWidget will make it easier to navigate with arrow keys (or game pad).

Together with adding focusPreviousWidget, I'm also going to try to merge EventManager into Container (which I have been planning to do for some time). This means the change will be a little bigger so you can expect it on september 4th or 5th.

Heinrich

QuoteKeyboard navigation is basically impossible to do directly in a gui library.
When in the menu, you might want to use the up and down arrow keys to navigate, but in the game the arrow keys shouldn't influence the buttons you have on your screen. So a gui lib can never respond directly to arrow keys, you have to handle everything yourself because you know exactly when everything should happen.
I suppose so, I never meant it this way. I meant it more like
QuoteBut having focusPreviousWidget and focusNextWidget will make it easier to navigate with arrow keys (or game pad).
This function alone makes it possible to use a non-mouse device to easily select entries without doing housekeeping with pointers to buttons yourself. For extra convenience, you could do a focusTop(), focusDown(), focusLeft(), focusRight() in Grid, I am doing this by get(row,col)->focus() which is also not a big deal of course. I guess most of those functions wouldn't require refactoring at all, merely some additional getters/setters (But please correct me if I'm wrong). Is focusFirstChildWidget() possible? I only found parent in the API. Also maybe callbacks with arbitrary KeyEvents. I know my wishlist is long and especially the Key stuff probably involves much more tedious typing than actual coding.

Heinrich

#13
Maybe also a possibility to disable mouse input to the gui? Currently, even when I set callbacks to ReturnKeyPressed only, I can still hover and focus with the mouse. Hovering is no big deal since I can change the image or set hover image off, but mouse focusing can really mess things up if you do keep track of focused stuff with pointers and change them according to KeyEvents.
I guess I could filter out mouse events before I relay them via gui.handleEvent(event). Again, it's convenience.

texus

QuoteFor extra convenience, you could do a focusTop(), focusDown(), focusLeft(), focusRight() in Grid
I don't want to add too many unneeded things to the gui, even if it is more convenient in your situation.
In most cases focusing isn't even used, so I don't think I need so many functions to focus another widget.

QuoteIs focusFirstChildWidget() possible?
You could use unfocusAllWidgets followed by focusNextWidget. That should have the same effect.

QuoteMaybe also a possibility to disable mouse input to the gui?
Yes but this requires me to add a function to disable the mouse, add a boolean to store the setting, add if statements in the event manager to ignore the mouse, make sure that child widgets also disable their mouse, ...
This isn't a big change, but compared to the fact that it only takes a single if statement on your side, I don't think its worth the effort.