Buttons 0.9

Started by billarhos, 26 May 2019, 08:26:21

billarhos


  • Buttons can blink, meaning that over a period of time can change background and text appearence. For instance can tongle between normal sprite and focused sprite. (global timer)
  • Every state (Normal, hover, etc) can have its own text color.
  • Every text for every state can have its own outline border.
  • Outline can have a thickness value.
  • Every text can have its own style (regular, bold).
  • Every text can have its own size.
  • Every text can have its own vertical and horizontal alignment on a given position inside the button (i can show you some button images if that is not clear).
  • A button can trigger (or not) from one or more keys. In my game i give the owner the ability to add any key he wants for every available button.
  • Having 9,there is no need of having "space" and "enter" as default keys out of the box.
  • Focusing in my opinion is over estimated but essential when you want to navigate with tab box. Bilinking over rules hovering and focusing.
  • Pressed time for "m_spriteDown" must be configurable. Action of triggering must be on the last frame. Zero value triggers the button at once showing one down frame.
  • Clicks or key presses can have "continuality" or not. Meaning that over pressing time, buttons can re-triggered as long as mouse or key is down.
  • A button can be tongle - switch button. (I saw you think for a different widget. It is not a bad idea having different widget. In my case is configurable (setTongle)).
  • Hovering can be disabled in touch screens because it is unnecessary (for all widgets).
  • Batch for rendering.

Those are some stuff that i have implemented in my codes over the years. Buttons and lists are the more demanding widgets in my opinion.

billarhos

Having different text position or and text size you can have very pretty pressed states. The text can grow or can be positioned a little downwards during the pressed event.

texus

Just wanted to let you know that I haven't forgotten about this yet, I just haven't had the time yet to go over the list in detail.

billarhos

Do not worry. All those need time for a proper discussion.



enum button_States
{
Normal,
Hover,
Down,
Disabled,
Focused
};

Sprite m_sprite[5];
Color   m_borderColor[5];
Color   m_backgroundColor[5];
Color    m_TextColor[5];

void setBackgroundColor(button_States state, Color color);
void setTextColor(button_States state, Color color);


Having a simple enum for all button states, you can simplify the code so you can have one function for all states.


texus

QuoteEvery state (Normal, hover, etc) can have its own text color.
QuoteEvery text can have its own style (regular, bold).
This is already possible in TGUI, so they don't need further discussion.

QuoteOutline can have a thickness value.
This will definitely be the case once I add support for outlines.

QuoteEvery text for every state can have its own outline border.
Do you mean outline color or also thickness? Colors I can agree with, but I feel like nobody would ever change the thickness per state even if I made it possible.

QuoteEvery text can have its own size.
Do you mean for every state? If yes then the text size would have to become part of the renderer. The problem with doing that is that the renderer would include a "size". My idea is to let the renderer contain stuff like colors and let the widget have any size that it wants (so e.g. item height and text size are part of the widget itself). Putting text sizes in the renderer means that a renderer is only suitable for widgets of certain sizes (e.g. a renderer with text size 12px is useless for a button of height 200px), which I want to avoid. So this might be a bit difficult to implement.

QuoteButtons can blink, meaning that over a period of time can change background and text appearence. For instance can tongle between normal sprite and focused sprite. (global timer)
This doesn't look very easy to implement as it requires a "global" state which overrides other focus/hover states. It might be better to implement this in user code. Of course it would be easier if the gui supported it directly, but it looks like a very niche feature. Same goes for other points below where I mention it can be done in your own code, it doesn't mean that it shouldn't be in the gui at all, just that it would get rather low priority.

QuoteEvery text can have its own vertical and horizontal alignment on a given position inside the button (i can show you some button images if that is not clear).
Could you show some examples of cases where not centering the text looks good?

QuoteA button can trigger (or not) from one or more keys. In my game i give the owner the ability to add any key he wants for every available button.
To me this sounds like something that should be done in user code. The user has full control over what keys are pressed and what he wants to do in these cases. I could make things easier by adding a function to Button that calls the connected signal handlers so that the user doesn't has to call them manually.
This probably can't even be implemented at the level of the button itself as key pressed are only passed when the widget is focused and I assume you also mean key presses when the button isn't focused. If you did mean only triggering on these keys when the button is focused then I would like to hear some examples of cases where you use other keys than space and return.

QuoteHaving 9,there is no need of having "space" and "enter" as default keys out of the box.
I actually want these things to work out of the box. I want TGUI to be as easy to use a possible, so things that most people want should be the default behavior.
The big problem is that I don't have a specific target audience for TGUI which means that it is hard to predict what most people would want and people use TGUI in very different situations and will want different behaviors.
If triggering on space and return remains the default then I do agree that there should be some way to disable the behavior for those that don't want it.

QuoteFocusing in my opinion is over estimated but essential when you want to navigate with tab box. Bilinking over rules hovering and focusing.
Being able to tab between widgets is the main reason why focusing even exists in TGUI. That and figuring out which edit box should get the key presses.
If blinking overrules focusing, then basically you can't do anything while something is blinking (except for e.g. pressing the blinking button)?

QuotePressed time for "m_spriteDown" must be configurable. Action of triggering must be on the last frame. Zero value triggers the button at once showing one down frame.
Do you mean that the down state should automatically jump to normal state even when keeping the mouse button pressed? Can you give some examples where this is used?

QuoteClicks or key presses can have "continuality" or not. Meaning that over pressing time, buttons can re-triggered as long as mouse or key is down.
This could be useful for implementing custom spin buttons where you have one button with a "-" and one button with a "+". Is that what you had in mind or did you know another use case for this?
Although for a spin button I feel like it should trigger immediately on mouse down, then after a "long" time trigger a second time and then each time after a "short" time trigger again. So that would be different from the "continuality", which wouldn't trigger immediately after mouse down? Or maybe it does trigger immediately on mouse down when this "continuality" setting is enabled?

QuoteA button can be tongle - switch button. (I saw you think for a different widget. It is not a bad idea having different widget. In my case is configurable (setTongle)).
I'm not sure how to best implement this, but this is the one thing on your list that I find the most important (which doesn't mean that it will be the first thing to be added though).

QuoteHovering can be disabled in touch screens because it is unnecessary (for all widgets).
Touch screen support is something that needs further investigation. TGUI was written as a desktop gui and I've never really used it on a touch screen (except for some brief tests with android), so some there are probably some other improvements that could be made as well. So maybe there should be some global toggle to change touch screen friendliness which would disable hovering for all widgets. The main problem would be to figure out whether a touch screen is used or not, but that would be up to the user. If the user doesn't explicitly asks to disable the hover states then I don't think I should make that decision in TGUI because I can't be certain that the device will only be used as a touch screen.

QuoteBatch for rendering.
Currently TGUI 0.9-dev is being designed such that all rendering has to go through a minimal interface. Drawing to the screen is only possible through this interface so everything that gets rendered will be batchable together with other widgets.

QuoteHaving different text position or and text size you can have very pretty pressed states. The text can grow or can be positioned a little downwards during the pressed event.
This would look nice but I fear that this is hard to do. The user would have to hardcode the text position in the renderer?

QuoteHaving a simple enum for all button states, you can simplify the code so you can have one function for all states.
That would indeed simplify things.
Ideally I would just have some properties that you can set directly instead of needing setters and getters but that will probably never work (because the widget needs to be notified about some changes such as border thickness and because I would like to be able to cache rendering in 0.9-dev which is only possible if I can detect that changes were made).
Given the huge amount of tunable things in the renderer I even considered having the property, setter and getter (both declaration and definition) generated with a define. The big issue with that is that I wouldn't be able to document the properties.

billarhos

#5
Let's disccus it one by one.

Quote
    Every text for every state can have its own outline border.

Quote
Do you mean outline color or also thickness? Colors I can agree with, but I feel like nobody would ever change the thickness per state even if I made it possible.

I mean both color and thickness.
Let's say we have a color text for every state. When you have white color for text and black color for outline color (normal state) is cool but when you use blue (pressed state) for text color and outline color is still black(1 outline color) is not so cool. We always look for a outline color that matches all text colors.

When you have a thickness value per state then you can easily make some cool effects without changing background color. (different text position inside button for every state also make things cool but this is next to our conversation)

When i say cool effects i mean pressing, hovering, disabling, focusing event can look awesome.



texus

For other widgets I'll keep the amount of out-of-the-box customizability with outlines limited, but I guess for buttons I can put some extra effort into it and allow a different outline thickness (and color) for every state. Buttons are probably the most used widgets after all.

Maybe I should also add FocusedHover and FocusedDown states? Right now you can't tell that a button is focused when it is being hovered.

billarhos

Maybe i am over reacting here with buttons and at the time i would like the best look of buttons maybe i ll push you into an overwork and more complicated source code. Cheer up. I have a brand new discussion list.

    1. Buttons can blink. Forget it. NO
    2. Every state (Normal, hover, etc) can have its own text color. This would look very nice if u use different sprite background colors. YES
    3. Every text for every state can have its own outline border. Keep one outline color. So NO.
    4. Outline can have a thickness value. Add one thickness value. So YES.
    5. Every text can have its own style (regular, bold). YES if possible.
    6. Every text can have its own size. No.
    7. Every text can have its own vertical and horizontal alignment on a given position inside the button. YES to position inside and YES to both alignments. (Have image)
    8. A button can trigger (or not) from one or more keys. In my game i give the owner the ability to add any key he wants for every available button. NO.
    9. Having 8,there is no need of having "space" and "enter" as default keys out of the box. NO AND YES. Default keys should be able to be disabled or not from a function.
    10. Focusing in my opinion is over estimated but essential when you want to navigate with tab box. Bilinking over rules hovering and focusing. FORGET IT.
    13. A button can be tongle - switch button. YES but i would propose it for a different widget so u can skip complexity.
    14. Hovering can be disabled in touch screens because it is unnecessary (for all widgets). YES AND NO. If i use same sprite for hovering no one understands if it is hovering. But i would be cool if i could disabled.
    15.Batch for rendering. YES

   11. Pressed time for "m_spriteDown" must be configurable. Action of triggering must be on the last frame. Zero value triggers the button at once showing one down frame.
   12. Clicks or key presses can have "continuality" or not. Meaning that over pressing time, buttons can re-triggered as long as mouse or key is down.

    In your code u wait for mouse up or key up event, correct?
   
   button->connect("MousePressed", [=]()
{
//mouse pressed event is triggering when mouse is up (after was down ok) correct?
});
   

   I ll come back on 11 and 12 if u answer my question.

billarhos

QuoteMaybe I should also add FocusedHover and FocusedDown states? Right now you can't tell that a button is focused when it is being hovered.

maybe my overreaction is contagious. lol. I think FocusedHover and FocusedDown states is too much. Hovering is just an effe. Correct? And is just for as long as mouse is on it.

i think priority order in rendering is: Disabled, Down, Hover, Focused, Normal.

texus

#9
QuoteIn your code u wait for mouse up or key up event, correct?
The pressed signal is triggered on mouse up.
For the space and return key the behavior turned out to be a bit less expected. It triggers on a key press event. Which means that if you currently hold the key it will trigger multiple times.

I was going to write that just like the Clicked signal the Pressed signal fires on mouse release, but that made me realize something: you can already "disable" the space and return keys. The difference between the Clicked and Pressed signal is exactly that: Clicked only fires when clicking the button while Pressed also fires when pressing the space or return key while the button is focused. So if you don't want to get a callback on space/return then you can just use the Clicked signal.

Edit: I just looked at how it happens in my browser. Buttons were triggered when releasing the space key but continuously when holding the return key. So maybe I should also have a look at how other libraries handle it.

billarhos

What happening if u call "mWindow.setKeyRepeatEnabled(false)". Still buttons trigering all the time via key down event?
I have never use key signals with tgui. I use the sfml's pollEvent  to trigger buttons via key presses aka shortcuts.

To clarify something. Space and enter do not have the same behaviour on buttons? if Yes how is this possible?

In my codes over the years i never used mouse up or key up events to fire an action on buttons. Instead i am using timers. (Or frame counters).
With counters-times i never worry about a thing. I can manipulate how quickly can be trigger an event
or if i want to do it repeatedly or once or even on up events just like u have it now in tgui.

texus

QuoteWhat happening if u call "mWindow.setKeyRepeatEnabled(false)". Still buttons trigering all the time via key down event?
Then it would only trigger once because the key press event would only be send once. It simply responds to the sf::Event::KeyPressed event that you get from SFML's pollEvent.

QuoteTo clarify something. Space and enter do not have the same behaviour on buttons? if Yes how is this possible?
In TGUI they do have the same behavior, but I tested it on a simple HTML button with both firefox and chrome and it looks like they really do have different behavior for space and return. (I tested it via https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_button_test where I replaced the onclick event with "console.log('test')"). While looking into the onSelect event for edit box recently I saw really weird behavior with HTML as well so I wouldn't want to blindly copy their behavior, but it does raise questions about what the most common behavior is.

My linux system seems to repeat for both space and return key, so it seems to work exactly like TGUI works now (with setKeyRepeatEnabled set to true).

QuoteIn my codes over the years i never used mouse up or key up events to fire an action on buttons.
As far as I can tell it is the most common way to fire on mouse up events, all buttons that I come in contact with seem to work that way.

billarhos

Quoteso it seems to work exactly like TGUI works now (with setKeyRepeatEnabled set to true)

Perhaps this must be optional.

QuoteAs far as I can tell it is the most common way to fire on mouse up events, all buttons that I come in contact with seem to work that way.

U half correct. There are plenty workcases that things works differenet. Like slot games or DJ programs for example. These are working in different way. Events are on down.
Sometimes are totally configurable like effect buttons both on dj program and on the dj controller (mechanical like pioneer).
a. Effect starts on down and play once.
b. Effect starts on down and play until mouse or key up.
c. Effect starts on down and playing until it presses again.

but all those stuff has nothing to do with TGUI apart from that the event is triggering on down action and not on up.
In my opinion triggering stuff is more important than anything else.

If u thinking of letting this to the user then perhaps u can add some signals like pressdown, pressup.


texus

QuotePerhaps this must be optional.
What should be optional exactly?

QuoteLike slot games or DJ programs for example.
Slot games and dj programs aren't the ones where I imagine people tabbing between buttons and using space to activate them, so you would only need mouse events. If you only need the mouse events (or touch events) then you can use the MousePressed signal to get a callback when the button is pressed down.

texus

So the following will definately be in 0.9-dev when it gets released:
- Every state can have a text color and text style (already in 0.8)
- Button can have an outline thickness and outline color (same for all states)
- Batch for rendering

Things to look into for 0.9-dev:
- Toggle and switch buttons
- Way to disabling hover state
- "Continuality" option
- Way to handling space and return


For the "continuality", how about a "setPressRepeat(sf::Time duration)" function? If set to 0 (default) then the button triggers on mouse up, but when a duration is set it would trigger the pressed signal on mouse down and again after every "duration".


While I was thinking about adding an enablePressBySpaceOrReturn function to disable space and return keys, I'm not sure if that would be the best way. I've looked online for questions where people ask to disable the space key and found the following behaviors:
- For javascript, the solution would be to either intercept the key event or to unfocus the button when you receive the focus event.
- For windows apps / .Net, the solution was to either intercept the key event or set IsTabStop to false to prevent the button from gaining focus.
- For unity, "Navigation" has to be set to "None", which as far as I can tell on first sight means not allowing it to be focused.
- Other random results came up where it was impossible to change the behavior or where it was suggested to unfocus the button after it gains focus.

So I think it might be better to add a function that prevents the button from gaining focus, instead of adding a function that disables space and return.


QuoteEvery text can have its own vertical and horizontal alignment on a given position inside the button. YES to position inside and YES to both alignments.
This is still the part that I find the most difficult to provide a generic solution for. I agree that the buttons you showed look great, but I'm not sure how to best give enough control to set the text position for buttons like that.

Maybe I shouldn't try to get the functionality in TGUI but to just make it easy enough to add it yourself? Imagine if you would be able to inherit from renderer classes and the ButtonRenderer would have a virtual function like this:
Code (c++) Select
void ButtonRenderer::drawText(RenderTarget& target, const Button* button, const FloatRect& rect, const String& text) const
{
    const TextProperties& textProperties{getCurrentTextColor(button), getCurrentTextStyle(button), m_textOutlineThickness, m_textOutlineColor};
    const FloatRect& bounds = target.calcTextBounds(text, textProperties);
    target.drawText(text, textProperties, {rect.left + (rect.width - bounds.width) / 2.f, rect.top + (rect.height - bounds.height) / 2.f});
}


All you would have to do is inherit from ButtonRenderer, override just the drawText function with your own implementation and call button->setRenderer(...) with an instance of your custom renderer.