pkdawson / imgui-godot

Dear ImGui plugin for Godot 4
MIT License
318 stars 18 forks source link

SetMainViewport breaks Interaction with In-Editor GUI #58

Open Mori2003 opened 1 month ago

Mori2003 commented 1 month ago

Hey there, I am currently working with v5.1.0 and Godot 4.2.2-stable, and I am having a problem while creating In-Editor GUIs. It seems that setting the Main Viewport breaks Input/Interaction.

To illustrate my problem, here's a simple In-Editor Tool.

@tool
extends Node2D

var show_gui: bool = false

func _ready() -> void:
    if Engine.is_editor_hint():
        show_gui = ImGuiGD.ToolInit()

func _process(_delta: float) -> void:
    if show_gui:
        ImGui.Begin("Example Tool")
        ImGui.Text("Lorem Ipsum")
        ImGui.End()

This correctly displays the GUI, and it's visible and interactable across the entire Editor including the 2D, 3D, and Script Views (Which i think is expected?).

imgui_issue1

However, I want the GUI to appear exclusively in the 2D Viewport.

To achieve this, I tried to use SetMainViewport() as following:

# in _ready()
ImGuiGD.SetMainViewport(EditorInterface.get_editor_viewport_2d())

Now the GUI only appears in the 2D View as desired, but It's not interactable.

imgui_issue2

Here is a project that shows this problem: ToolProject.zip

pkdawson commented 1 month ago

Hey, thanks for including a project that reproduces the issue.

I should have documented this better, but using SetMainViewport with a SubViewport means that the user is responsible for pushing inputs to the SubViewport. Normally in 2D this would be handled automatically by a SubViewportContainer, but that's not working here. I'll try to figure it out when I have the time. Not sure if there's any good way to make it work, I don't want to mess with the editor internals.

This is a little kludgy because Godot doesn't seem to provide an easy way to check which main screen is active, but you could do something like this:

@tool
extends Node2D

var show_gui: bool = false
var button_2d: Button

func _ready() -> void:
    if Engine.is_editor_hint():
        show_gui = ImGuiGD.ToolInit()
        var title_bar := EditorInterface.get_base_control().find_child("@EditorTitleBar*", true, false)
        button_2d = title_bar.find_child("2D", true, false)

func _process(_delta: float) -> void:
    if show_gui and button_2d.button_pressed:
        ImGui.Begin("Tool")
        ImGui.Text("Lorem Ipsum")
        ImGui.End()

Your ImGui windows won't stay confined to the 2D viewport, but otherwise I think it solves the problem.

Mori2003 commented 1 month ago

Thank you for the response/solution! What you provided is working great, and I will use this.

Ideally, I would like to have it confined to the viewport, but it's not a big deal. As you mentioned, it seems that Editor-Viewports handle inputs differently than usual SubViewports. Pushing inputs via an EditorPlugin also does not work, apparently.