godotengine / godot-proposals

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

Add a CarouselButton node #5139

Open AlaraBread opened 2 years ago

AlaraBread commented 2 years ago

Describe the project you are working on

A racing game, with settings menus.

Describe the problem or limitation you are having in your project

The OptionButton is great for selecting from a list of options, but a carousel button is often preferred, especially when menus will be used with a controller. Without a CarouselButton, designing for controllers becomes much more cumbersome.

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

The CarouselButton would work similarly to the OptionButton, except when pressed, instead of showing a list of options, it would move to the next option. If ui_left or ui_right is pressed while it is focused, it would move to the previous and next options, respectively. If the left or right arrows on the side of the button are clicked on, it should also switch options accordingly.

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

This is made in gdscript using this script:

extends Button

export(Array, String) var options := ["1", "2","3"]

var selected_ind:int = 0

signal selected_updated(dir)

func _ready():
    update_text()

func _on_Left_focus_entered():
    select(selected_ind-1)
    grab_focus()
    emit_signal("selected_updated", false)

func _on_Right_focus_entered():
    select(selected_ind+1)
    grab_focus()
    emit_signal("selected_updated", true)

func select(i:int):
    selected_ind = posmod(i, len(options))
    update_text()

func update_text():
    text = options[selected_ind]

func _on_Selector_pressed():
    _on_Right_focus_entered()

https://user-images.githubusercontent.com/59781761/184006413-63a75f22-9017-467c-bf49-bcd79ce62d61.mp4

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

It is possible to make a carousel button in gdscript, but it is an extremely common use case. That should not be required. If you need proof, you can type "console video game settings menu" into an image search engine, and you will find countless images of carousel buttons.

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

In my opinion, if OptionButton can be core, so should CarouselButton.

Calinou commented 2 years ago

For convenience, right-clicking the button with the mouse should also go to the previous option.

Wrap-around behavior should be configurable with a property (probably enabled by default, but there are certain scenarios where it makes sense to disable it). Arrows should have a "disabled" appearance when one of the extremes is reached and wraparound is disabled, probably with a disabled_modulate theme color that multiplies the icon's color.

It may also be worth considering whether you can make ui_left and ui_right cycle through options in an OptionButton. This lets controller users change options easily while not affecting mouse usability. I tend to prefer dropdowns to carousel buttons for mouse usage, as you can see all options at once easily.

me2beats commented 1 year ago

I think I support the idea only if you can easily set the content between these buttons. That it will not necessarily be a label with text. It can be for example a TextureRect like "select the character" screen.

AlaraBread commented 1 year ago

I think I support the idea only if you can easily set the content between these buttons. That it will not necessarily be a label with text. It can be for example a TextureRect like "select the character" screen.

The PR I made lets you use an icon instead of text. If that isn't versatile enough for you, you can also make a texturerect as a child of a carouselbutton and change its contents based on the selected item.

Calinou commented 1 year ago

I'd suggest also adding a series of blips on the bottom to denote how many items can be selected, and which item you've currently selected (image from Dead Space Remake):

image

Blips can be drawn using StyleBoxes to maximize flexibility, with one theme item for a selected blip and another for an unselected blip. There would be two additional theme constants for the blip separation[^1], blip height and total width.

[^1]: Individual blip width is determined automatically to allow for a large number of items to display correctly.


Reposting my comment from https://github.com/godotengine/godot/pull/64535 to justify why a CarouselButton in core may be a good idea in the end:

Carousel buttons are generally more popular in game menus (as they're more controller-friendly), while OptionButtons are more popular in non-game applications. I don't think there's a "one size fits all" solution here :slightly_smiling_face:

On the other hand, this makes me wonder if we could have a single node to do both. You'd have a show_carousel_buttons property in OptionButton that defaults to false. When set to true, it displays two buttons to cycle between options and the dropdown arrow icon is hidden. However, you can still click on the text itself to display a dropdown. This allows for good UX on both keyboard/mouse and controller inputs.

Edit: I have a WIP implementation in a branch: https://github.com/Calinou/godot/tree/optionbutton-add-carousel

Shadowblitz16 commented 8 months ago

Guys you have no idea how useful this is. I am been fighting godot gui for ages trying to impliment something like this.

I do think though the left and right arrows should be treated as the same control. As in they aren't treated as a seperate focus object.

When you focus the carousel button ui_left and ui_right should be treated as if you pressed the left and right arrows not just focus them.

Also I think the arrows and blips should beable to be enabled or disabled for the user's style.

I would give this 100 hearts if I could.

dsnopek commented 8 months ago

I have used a custom control like this in pretty much every game I've made! So, I think this would be very useful. However, I'm unsure if a builtin one would allow enough customization (both visual and behavior).

YuriSizov commented 8 months ago

There is absolutely nothing wrong with having it as an asset on the library supported by community and scripted in GDScript. We should have more useful widgets added this way.

Shadowblitz16 commented 8 months ago

There is absolutely nothing wrong with having it as an asset on the library supported by community and scripted in GDScript. We should have more useful widgets added this way.

Built in ones would mean no theme support for the control. Also for such a useful thing the community had plenty of time to put one on the asset library, yet there isn't one.

I have used a custom control like this in pretty much every game I've made! So, I think this would be very useful. However, I'm unsure if a builtin one would allow enough customization (both visual and behavior).

If it's added to core both visual and behavior can improved in the future. The existing built in controls already aren't very flexable and need improvement.

YuriSizov commented 8 months ago

Also for such a useful thing the community had plenty of time to put one on the asset library, yet there isn't one.

Doesn't that mean it's not so useful/needed by many if nobody bothered to make one?

dsnopek commented 8 months ago

Also for such a useful thing the community had plenty of time to put one on the asset library, yet there isn't one.

Doesn't that mean it's not so useful/needed by many if nobody bothered to make one?

For me, I never bothered to put this is the asset library because I end up rewriting/replacing parts of the control for each project that I use it in, because I want it to look or work a little differently in each game (although, I do usually start by copy-pasting an earlier version of it). When done as a one-off, it's a fairly simple control to make. Trying to make it customizable and flexible enough to work for multiple games would lead to a level of complexity that I personally haven't felt like delving into yet. :-) Anyway, that's part of why I'm not sure a builtin one would be flexible enough - if it existed, I suspect I'd still make a custom one.

Shadowblitz16 commented 8 months ago

Also for such a useful thing the community had plenty of time to put one on the asset library, yet there isn't one.

Doesn't that mean it's not so useful/needed by many if nobody bothered to make one?

No dsnopek just said he makes one for every game. I said I needed one but didn't know how to impliment it.

If that was the case we would have an asset for everything someone has ever made in godot in the asset manager.

The issue is not usefulness, The issue is someone putting thier time and effort into maintaining a asset instead of putting thier time and effort into thier game.

Also if you upload a asset that means people are going to suggest features which means more time and effort.

And if features aren't added then people either create thier own for thier own game or if they are like me and can't get it working, they end up either just waiting or using a diffrent control even though it doesn't have the functiality they need.

And the cycle repeats

I think the another reason why there isn't one is because not many people plan to export to consoles. this sort of control is nessary for any gamepad or keyboard related gui

AThousandShips commented 8 months ago

Based on people actually implementing it, this is very specific to specific use cases, so it doesn't feel like something that can be made generic enough, or not without a lot of complex customisation, and since it's already a relatively fringe component it feels like few if any would find a built in one useful or sufficient

Shadowblitz16 commented 8 months ago

Based on people actually implementing it, this is very specific to specific use cases, so it doesn't feel like something that can be made generic enough, or not without a lot of complex customisation, and since it's already a relatively fringe component it feels like few if any would find a built in one useful or sufficient

The main thing this control would be useful for is game console gui. Almost all triple A game console games have this sort of thing in thier game.

here is an example from call of duty image

here is an example from fortnite image

here is an example from minecraft (it doesn't have the arrows) image

here is an example from halo image

here is an example from far cry image

I can keep posting until you guys get the point.

YuriSizov commented 8 months ago

No dsnopek just said he makes one for every game.

Yet another reason why it doesn't really fit to the set of built-in widget, as David also explained.

I said I needed one

I hear you, but if this is indeed needed by many then it's very unlikely that everyone who needs it also doesn't know how to create one. So based on your own words, there isn't enough interest in the community to actually make it and use it. And when someone needs it, they create a widget that fits a particular project. None of this leads to a carousel button being implemented in the engine.

Shadowblitz16 commented 8 months ago

No dsnopek just said he makes one for every game.

Yet another reason why it doesn't really fit to the set of built-in widget, as David also explained.

I said I needed one

I hear you, but if this is indeed needed by many then it's very unlikely that everyone who needs it also doesn't know how to create one. So based on your own words, there isn't enough interest in the community to actually make it and use it. And when someone needs it, they create a widget that fits a particular project. None of this leads to a carousel button being implemented in the engine.

Dude did you literally just skip the 5 posts of diffrent games that use this? I feel like the only reason you dislike this suggetion is because I love it.

How do you get not needed in core from he uses one in every game?

Is it used often => yes definitly Can be be worked around in a few lines of script => no it takes alot to actually get this to work ... esspecially if you want the options to be configurable from the control itself instead of making it local and editing the children.

AThousandShips commented 8 months ago

Many games need some form of inventory management, that doesn't mean this should be in core, because it's too specific, it's not sufficiently generic, most who need it won't find it useful if we add it to core, because it can't be flexible enough

Or rather, making it flexible enough makes it far too inefficient or complicated to configure, genericness and usability for widely different cases has diminishing returns

I'd say (based on David's experience, and the stylistic differences in your examples) this applies to this too

dsnopek commented 8 months ago

@Shadowblitz16:

The issue is not usefulness, The issue is someone putting thier time and effort into maintaining a asset instead of putting thier time and effort into thier game.

I think this probably is the reason that an asset like this doesn't exist yet. I think it's probably possible to make a generic, reusable control that would work for something like ~80% of games. But creating and maintaining it would really be a lot of work, and would require a very motivated maintainer and community.

However, I don't think that it gets any easier by making it a control that's builtin to Godot. In fact, it probably gets a little harder. As an asset built with scene files and GDScript, pretty much any Godot user could potentially contribute improvements and fixes, or fork it and make it work the way they want. But as a builtin control in C++, the number of people who could maintain or contribute to it is much smaller, and forking it means forking and recompiling the engine.

I said I needed one but didn't know how to impliment it.

I don't know if this'll help in your case, but here's a Godot 3 one:

And here's one from an unfinished Godot 4 game (the repo was private - I just made it public right now to share this, so please be understanding about the messy state of that project :-)):

This second one is more complicated, but it's not because of Godot 4 - it's this game that needs a little bit more complex behavior. (It's a local multiplayer co-op game, so multiple people with multiple controllers connected, sometimes all using the same UI at the same time.)

Shadowblitz16 commented 2 months ago

There is a spinbutton plugin now but it's completely unusable due to the fact that Godot's theme system is so horrid. https://github.com/yudinikita/godot-spin-button

I can't figure out what theme override does what and even then the arrow icons are hard coded into the node rather then the theme, the control doesn't shrink down more then 20 pixels high and the navigation part doesn't match the title part in size.

This needs an official node or series of node's. This sort of thing should 100% be part of core because while the node may be complicated it is..

  1. hard to implement due to Godot only supporting single focus
  2. makes games look, feel, and work better on non desktop systems
  3. is often used in AAA game's menus
  4. makes Godot's controls not desktop only oriented

Also you guys should try to cover everyone's use cases because node's should work out of the box. Not like and abstract class where we need to extend to get it to actually do something. And right now that's a lot of Godot's nodes.

iiMidknightii commented 2 months ago

Would it also make sense to let SpinBox have a horizontal configuration as well? The feature proposed would ease selecting between string options, but having horizontal SpinBox configurations might make numeric input easier for gamepads as well.

I know there's the HSlider node already, but sliders tend to imply a continuum, whereas SpinBox seems to imply more discrete values. I personally would use the a horizontal SpinBox for editing things like larger integers like a random seed (which might imply that holding down ui_right and ui_left could do some sort of fast scrolling as well).

EiTaNBaRiBoA commented 1 month ago

Is it possible also to add a swipe or touch motion to the carousel button? Like for example a timer/clock apps where the numbers of hours,minutes can be scrolled infinitely looping

Calinou commented 1 month ago

Is it possible also to add a swipe or touch motion to the carousel button? Like for example a timer/clock apps where the numbers of hours,minutes can be scrolled infinitely looping

I'd say this is out of scope for a carousel button. Instead, this should be handled in a custom control as it's not often seen in mobile games.

Carousel buttons are generally handled on mobile the old-fashioned way, with a popup showing the list of valid options:

image

OptionButton is already well-suited to this use case in its current state.