(Tool) Detecting when a node is selected in the editor?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Takanu Kyriako

Hey, i’m currently developing some level building tools and I want to replicate some of the functionality seen in nodes like OmniLight, where the wireframe that represents it’s sphere of influence dims when unselected and brightens when selected, as it helps distinguish between what is and isn’t selected when editing.

I currently can’t find any default notifications or signals I can catch to detect when a node is selected or unselected to make this happen inside a tool script however. If anyone knows how, that would be great to know w

:bust_in_silhouette: Reply From: Xrayez

EditorInterface retrieved from EditorPlugin or EditorScript allows to fetch selected nodes via special EditorSelection object.

EditorSelection has selection_changed signal that you can use to check whether any nodes are selected in the scene tree dock. In order to connect to selection_changed signal:

var eds = get_editor_interface().get_selection()

func _enter_tree():
    # Plugin initialization, etc
    eds.connect("selection_changed", self, "_on_selection_changed")

Now you can handle it in a callback, for instance:

func _on_selection_changed():
    # Returns an array of selected nodes
    var selected = eds.get_selected_nodes() 

    if not selected.empty():
        # Always pick first node in selection
        var selected_node = selected[0]

This works in Godot 3.1.

Xrayez, thanks for pointing this way.
I would like to give a warning thou, because I actually had some problems building the game with this approach.
EditorPlugin is meant to be used inside plugins only: so don’t do like I did :smiley:

THIS IS NOT THE CORRECT WAY OF DOING IT
IT WONT GIVE YOU A VALID RELEASE BUILD

var eds
func _ready():
	if Engine.editor_hint:
		eds = EditorPlugin.new().get_editor_interface().get_selection()
		eds.connect("selection_changed", self, "_on_selection_changed")

func _on_selection_changed():
	var sel = eds.get_selected_nodes()
	if not sel.empty():
		if self == sel[0]:
			#draw stuff in editor

Even if excluded from the script with an if statement it will ruin the build for release because this class won’t be in the export template: here is a link to the highlighted issue on github #4082

iRad | 2021-10-24 23:52

I understand, but this is expected if you write a tool script/plugin, which this question explicitly asked for. In general, don’t assume that classes which are named after Editor will work after export, because export templates are compiled without tools enabled.

Xrayez | 2021-10-25 10:10

Xrayez, are you saying that a script using tool will break your project outside the editor? Because I think that’s wrong. Using Editor classes does, using tool scripts shouldn’t.

berarma | 2021-11-16 16:33

Using Editor classes does, using tool scripts shouldn’t.

Correct, I didn’t mean to imply that tool scripts won’t work outside the editor in this context. tool simply allows to run code in the editor, regardless whether core or editor-only classes are used in a tool script.

It’s just that every EditorPlugin requires tool keyword, and in order to solve the problem asked by the author, this does require writing an EditorPlugin, which is editor-only.

Xrayez | 2021-11-16 16:51

:bust_in_silhouette: Reply From: jpate

If you want a cheap way to get this from any tool node:

WARNING: maybe not a good idea and may just break randomly in the future!!!

HERE BE DRAGONS!

if Engine.editor_hint:
    var editor_node = get_tree().root.get_node('EditorNode')
    var editor_interface = null
    for c in editor_node.get_children():
    	if c.get_class() == 'EditorInterface':
    		editor_interface = c