+1 vote

Hello There,

I am developing a game for a german company in which they use many option buttons.

Sadly they also have a fixed resolution for the game. In one of the optionButtons, the options should show all the letters of the alphabet, meaning that it has more options then space in the screen.

Since the game should run on Android devices, im wondering how can I make the options scroll with a touch input, because I'm able to scroll using the mouse wheel but no dragging function..

I tried making a scrollcontainer for the whole scene, but the client didn't like it.

Is there any way I can scroll or make them grow horizontaly or is there any other options I may use ?

in Engine by (16 points)

3 Answers

–3 votes

When you press an OptionButton it actually shows a PopupMenu, which you can access with get_popup() and then do whatever you want with.

Here's a simple example; it lets you drag the popup with right click.

extends OptionButton

onready var popup = get_popup()

func _ready():
    popup.connect("gui_input", self, "_on_popup_gui_input")

func _on_popup_gui_input(event):
    if event is InputEventMouseMotion\
    && Input.is_mouse_button_pressed(2):
        popup.rect_position.y += event.relative.y
by (9 points)
+2 votes

@Royerson's answer got me halfway there (Thanks!), but I ran into issues with the popup erroneously selecting items when I mean to be dragging. I use Godot C# Mono, but here is my code that is working OK for me by tracking the drag state.


using Godot;
using System;

public class DraggableOptionButton : OptionButton{
    private PopupMenu popup;
    private Boolean wasJustDragging = false;
    public Boolean PopupIsVisible { get { 
        return this.popup.Visible;}}

    public override void _Ready(){
        this.popup = this.GetPopup();
        this.popup.HideOnItemSelection = false;
        this.popup.HideOnCheckableItemSelection = false;
        this.popup.Connect("gui_input", this, nameof(this.OnPopupGuiInput));
    }

    public void  OnPopupGuiInput(InputEvent @event){
        this.popup.HideOnItemSelection = false;
        this.popup.HideOnCheckableItemSelection = false;
        if(@event is InputEventScreenDrag){
            var dragEvent = (InputEventScreenDrag)@event;
            this.popup.RectPosition += new Vector2(0, dragEvent.Relative.y);
            //If we're dragging, set this flag to not release popup until we're done
            this.wasJustDragging = true;}
        if(@event is InputEventMouseButton){
            if(!this.wasJustDragging){
                //If we weren't just dragging, release the popup for normal input
                this.popup.HideOnItemSelection = true;
                this.popup.HideOnCheckableItemSelection = true;}
            this.wasJustDragging = false;}
    }
}
by (30 points)

Thanks for this, works great!

This is the GDScript version just to save somebody else some typing :P

extends OptionButton

onready var popup = get_popup()

var was_just_dragging = false

func _ready():
    popup.hide_on_item_selection = false
    popup.hide_on_checkable_item_selection = false
    popup.connect("gui_input", self, "_on_popup_gui_input")

func _on_popup_gui_input(event):
    popup.hide_on_item_selection = false
    popup.hide_on_checkable_item_selection = false

    if event is InputEventScreenDrag:
        self.popup.rect_position += Vector2(0, event.relative.y)
        was_just_dragging = true

    if event is InputEventMouseButton:
        if not was_just_dragging:
            popup.hide_on_item_selection = true
            popup.hide_on_checkable_item_selection = true
        was_just_dragging = false
0 votes

I use this and it works great

extends OptionButton

onready var popup = get_popup()

var scrSz 

func _ready():
    scrSz = screenSize()

    popup.connect("gui_input", self, "_on_popup_gui_input")

func _on_popup_gui_input(event):
    if popup.rect_size.y>scrSz.y:
        if event is InputEventScreenTouch and !event.pressed:
            _disable_items(false)
        elif event is InputEventScreenDrag:
            _disable_items(true)
            popup.rect_position += Vector2(0, event.relative.y)
            popup.rect_position.y = clamp(popup.rect_position.y,scrSz.y-popup.rect_size.y,0)

func _disable_items(disable):
    if !disable: yield(get_tree().create_timer(0.1),"timeout")
    for i in popup.get_item_count():
        popup.set_item_disabled(i,disable)

func screenSize() -> Vector2:
    var sz := (get_viewport().get_size_override() if get_viewport().get_size_override() > Vector2(0, 0)
        else get_viewport().size)
    return sz
by (14 points)
edited by
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.