0 votes

(cross-posting from reddit)

I have a rich text label with clickable links, but want it to be hidden if i click somewhere else.

My Tree:

  • PauseMenu as PauseMenu.gd

    • CreditsButton as Button

      • Signal pressed: ._on_CreditsButton_pressed
    • CreditsLayer as Control

      • visible = false
      • Signal gui_input: .._on_CreditsLayer_gui_input
      • CreditsText as MyLabel.gd

        • mouse_filter = PASS

MyLabel.gd:

extends RichTextLabel

func _ready() -> void:
    connect('meta_clicked',self,'_on_meta_clicked')

func _on_meta_clicked(meta: String):
    OS.shell_open(meta)
    get_tree().set_input_as_handled()
    accept_event()

PauseMenu.gd:

extends Control

onready var credits_layer := $CreditsLayer

func _on_CreditsButton_pressed() -> void:
    credits_layer.show()

func _on_CreditsLayer_gui_input(event: InputEvent) -> void:
    if event is InputEventMouseButton or event is InputEventScreenTouch:
        credits_layer.hide()

I can not get the event to stop (even with it set as handled and accepted) from being passed onto the externally bound on_gui_input event.

And as far as I understand it, _input and _unhandled_input (afaik the latter would honor the as_handled flag?) are functions, not signals, so i can't bind to them from the outside either, and my PauseMenu contains other stuff (such as the menu with a button to show the credits to begin with), so i can't just implement it there.

asked Apr 24 in Engine by nonchip (92 points)

1 Answer

0 votes

I don't quite understand why you need mouse_filter to be PASS, since that's the reason input events being passed to CreditsText's parent Node's on_gui_input.
Did you try to set the mouse_filter to STOP for your CreditsText?

If you have a reason to use PASS mouse_filter, maybe this is what you want:
PauseMenu.gd (and just delete MyLabel.gd)

extends Control

onready var credits_layer := $CreditsLayer
onready var credits_text := $CreditsLayer/CreditsText

func _ready() -> void:
    credits_text.connect('meta_clicked',self,'_on_CreditsText_meta_clicked')

func _on_CreditsButton_pressed() -> void:
    credits_layer.show()

func _on_CreditsLayer_gui_input(event: InputEvent) -> void:
    if event is InputEventMouseButton or event is InputEventScreenTouch:
        credits_layer.hide()

func _on_CreditsText_meta_clicked(meta: String) -> void:
    OS.shell_open(meta)
answered Apr 25 by MintSoda (64 points)

as far as i understand it i need mouse_filter to pass so i can get events on both (click a link -> open a link. click anything else -> hide the layer). i think i forgot to mention: the label is actually full screen, so it has to pass the events on for the hiding part to work. i just want them to stop and not hide if they were clicking on a link.

also no, i can't just delete MyLabel.gd, because that does way more than just the meta_clicked.

and correct me if i'm wrong but your code looks equivalent to what i posted, just in one file instead of two? how would that fix anything? my issue is the event doesn't get handled/accepted when meta_clicked was fired (so click a link -> open a link AND hide the layer; which i want to prevent), and you got rid of those 2 calls? do i just not understand event handling or has that even less chance of working? :P

EDIT: just found the difference (except which files are used, which shouldnt really make a difference i think) between our codes: you bind gui_input on the label, i did on the layer. tried on the label, still hides it when i click a link, so afraid that didn't help either :/
I'm starting to get really confused, the source code seems to suggest the event is emitted in-place (not deferred or anything), so how can it possibly ignore my set_input_as_handled();accept_event()? even that very function calls accept_event() conditionally, how can that be stopped by something like emit_signal 0.o

EDIT again: seems like somehow it actually is deferred, and seems to be happening anywhere up to 3 frames later, even though that's not how emit_signal is supposed to behave, found a very ugly workaround:

var hide_credits_layer = -1
func _process(_delta: float) -> void:
    if hide_credits_layer>0:
        hide_credits_layer-=1
    elif hide_credits_layer==0:
        credits_layer.hide()
        hide_credits_layer = -1
func _on_CreditsLabel_meta_clicked(meta: String):
    hide_credits_layer = -1
    accept_event()
    get_tree().set_input_as_handled()
func _on_CreditsLayer_gui_input(event: InputEvent) -> void:
    if credits_layer.is_visible() and event is InputEventMouseButton:
        hide_credits_layer = 3

that technically works but it's horrifying...

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 How to use this Q&A? before posting your first questions.