PopupPanel.popup() can't be called twice?

Godot Version

4.3rc3

Question

Click a sprite to open a PopupPanel over it (let’s say “sell this tower”). Click a second time somewhere outside it to close it. Click a third time on a different sprite to open it over that sprite. All of that works.

What doesn’t work: Click sprite A to open, click sprite B to open. The second click fails. So i thought, okay, it can’t stay open so i’ll hide it and then re-open it. But that doesn’t work.

func _unhandled_input(event: InputEvent):
    if event.is_action_pressed("left_click"):
        show_tower_info(get_global_mouse_position())
func show_tower_info(new_position: Vector2):
	if tower_info_popup_panel.visible:
		print("it's already showing so we're hiding it.")
		tower_info_popup_panel.hide()
		#tower_info_popup_panel.visible = false
	tower_info_popup_panel.position = new_position
	tower_info_popup_panel.popup()

i have tried multiple variations on this including calling popup() multiple times in a row because i was angry and wanted it to feel my wrath. But nothing i’ve tried works. One mouse click opens it, one closes it.

How do i make it so that the second click also opens the popup?

There is this always on top property.

Maybe you need to fiddle with it for both popups

Are you opening the same PopupPanel?

Will PopupPanel block sprite B when clicking on it to open it
点击 sprite B 时,PopupPanel会不会遮挡 sprite B

The Info popup is a “this is a description of the object”. i have multiple objects you can click on. You can only see one Info popup at a time. So if you click on A (and get a popup) and then click on B, it basically moves - hide, move to B’s location, load B’s info, show.

So yes, i am opening the same PopupPanel (in this case %TowerInfoPopupPanel, defined at design time and sitting in the scene tree). i do not want two copies, just the one.

The actual game is at SimpleTD by baylorw but you have to beat the first level to get a second tower so that you can see the problem.

This is a scenario script built for you based on your description

[gd_scene load_steps=2 format=3 uid="uid://nb8p0e8l4fwr"]

[sub_resource type="GDScript" id="GDScript_830ic"]
script/source = "extends Node2D
@export var popup:PopupPanel

func _on_button_pressed() -> void:
	popup.popup()
	popup.position=$Button.position
func _on_button_2_pressed() -> void:
	popup.popup()
	popup.position=$Button2.position
"

[node name="Node2D" type="Node2D" node_paths=PackedStringArray("popup")]
script = SubResource("GDScript_830ic")
popup = NodePath("PopupPanel")

[node name="Button" type="Button" parent="."]
offset_left = 859.0
offset_top = 70.0
offset_right = 922.0
offset_bottom = 129.0
text = "A"

[node name="Button2" type="Button" parent="."]
offset_left = 978.0
offset_top = 62.0
offset_right = 1058.0
offset_bottom = 127.0
text = "B"

[node name="PopupPanel" type="PopupPanel" parent="."]

[node name="Label" type="Label" parent="PopupPanel"]
offset_right = 9.0
offset_bottom = 29.0
text = "55555"

[connection signal="pressed" from="Button" to="." method="_on_button_pressed"]
[connection signal="pressed" from="Button2" to="." method="_on_button_2_pressed"]

After testing, to achieve the effect you described, simply call popup() without hiding
Your mistake may be using _unhandled_input(), try replacing it with _input().

Interesting. Your example works for me. But if i modify it slightly… It only works if the second click is on a Button. Something in Button causes popup() to work that isn’t present in _input() (or _unhandled_input(); i tried both).

Godot doesn’t support _on_click() for Sprite2D (which is insanely stupid but that’s been debated at length in other threads so i won’t repeat why that’s such an awful design decision here) so i implemented my own (using an Area2D) and that doesn’t work. There’s something special about Button::click.

Next i tried Button::click but with right mouse (button_mask = MOUSE_BUTTON_MASK_LEFT | MOUSE_BUTTON_MASK_RIGHT). It doesn’t work with right buttons. If you right-click button A the popup opens but if you then right-click button B, nothing happens. Right click A followed by left click B does work. Multiple popup clicks only work with Buttons and left click. Weird.

i guess the next step is hoping a wizard knows why or i go read the C++ source code. Which i’ve never done before but i could maybe figure it out with enough time… This is kind of a big deal right now for my project (everything else works other than particles on moving objects) so i’ll have to decide how desperate i am.

i got it to work!

The trick: If the popup is visible, wait a little bit.

func show_tower_info(new_position: Vector2):
	if tower_info_popup_panel.visible:
		await get_tree().create_timer(0.001).timeout
	tower_info_popup_panel.position = new_position
	tower_info_popup_panel.popup()

Don’t even have to hide it. Just have to wait.

One (i think) major downside: This only works with left mouse clicks. The PopupPanel appears to block the rest of the app from seeing any inputs (including keystrokes) other than left mouse click. So you can close a popup by left clicking a button but not right clicking - the button never sees a right click event (nor does _input()).

So i guess a left mouse click (and only left mouse click) closes the popup and that same click is sent to the app (Button::clicked, "_inputand_unhandled_input) but the app cannot call popup()because thePopupPanelis still in the process of shutting down. If you wait a little bit the panel will be hidden and you can callpopup()` again.

Time: i tested with 1, 10 and 100ms and they all worked for my game. So it doesn’t look like you have to wait long