How to handle input for custom node in editor?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Ugis Brekis
:warning: Old Version Published before Godot 3 was released.

Ok, so here’s the situation:

I’d like to create a custom node which is really similar to polygon2d node, but with some additional features. The thing is, I need to be able to do editing of this polygon in editor- adding, moving and removing points, but I can’t figure out from the source code of the actual polygon_2d_editor_plugin.cpp how to handle the input. How can I make other nodes ignore the input- stop them from being selected while adding points?

I checked out that the plugin shouldn’t be using simply func _input(event) but instead there should be func forward_input_event(event), however it doesn’t seem to be doing anything when added just like that. I mean I added print function with some text under forward_input, but it doesn’t appear. Obviously I’m doing something wrong and I need your help to figure out how to do it properly, so that it works.

I’d really appreciate just a simple example, just a few lines of code or a fairly good explanation how this thing could be achieved.

I think forward_input_event(event) is a virtual method of EditorPlugin.

neikeq | 2016-03-16 17:29

Yes, I saw that in the class reference, but I’m not familiar of the meaning of it. I will have to read and learn about this topic, but in the meantime- why did you point out that this is a virtual method- do you have an idea on how to solve the problem or is this just a small lead?

Ugis Brekis | 2016-03-16 17:38

Ok, I read about virtual methods- I kinda have a vague understanding of that now, but I still have no clue how that matters in solving this problem.

Ugis Brekis | 2016-03-16 17:56

You said forward_input_event(event) was not being called (or that’s what I understood :stuck_out_tongue: ). That’s because it’s a virtual method of EditorPlugin, so it will only be called if you add it to a class that extends EditorPlugin. Polygon2DEditorPlugin overrides this method and passes the event to Polygon2DEditor. You can return true from this method to capture the event, making the other nodes ignore it.

neikeq | 2016-03-16 18:18

Thanks for the info! However, may I ask you to create a small preview of how this is done properly?

Shouldn’t this code print line if mouse button is clicked while the according node is selected and block other nodes from being selected if the cursor is over?

tool

extends EditorPlugin

func _ready():
	pass

func forward_input_event(event):
	if event.type == InputEvent.MOUSE_BUTTON:
		if event.button_index == BUTTON_LEFT:
			if get_selection().get_selected_nodes().size() == 1:
				if get_selection().get_selected_nodes()[0].is_type("Sprite"):
					print("Sprite is selected")
					return true
				else:
					return false

Ugis Brekis | 2016-03-16 20:40

That’s not how it works. You must override method bool handles(object) for the editor to know if your plugin can edit the selected node:

func handles(object):
    return object.is_type("Sprite")

I’ll try to make a proper answer with an example tomorrow.

neikeq | 2016-03-17 01:47

Thanks, mate, looking forward to it!

Ugis Brekis | 2016-03-17 10:05

Hey @neikeq, maybe you had some time to spare on this?

Ugis Brekis | 2016-03-21 18:10

:bust_in_silhouette: Reply From: neikeq

First you need to create a plugin. In version 2.0.x the plugins directory is ~/.godot/plugins/ ($APPDATA/Godot/plugins/ on Windows) and the plugin must be activated from Editor Settings->Plugins. In greater versions (master branch) the directory is res://addons/ and the plugin must be activated from Project Settings->Plugins.

A plugin consists of a directory with a plugin.cfg file and a main script which must extend EditorPlugin and have tool enabled. This is an example plugin.cfg:

[plugin]
name="PluginName"
description="Best plugin ever"
author="neikeq"
version="1.0.0"
installs=false
script="path/to/main_script.gd"

EditorPlugin class has some useful methods you can override. One of them is handles(object) which is called by the editor when editing a object/node to determine if your plugin can edit it. Here are bad news though: Currently there is no way to set a plugin’s priority, so you can’t create a plugin to edit TileMap (for example) because it’s already edited by the built-in TileMapEditorPlugin.

EditorPlugin also has the methods forward_input_event(event) for input events in the canvas editor and forward_spatial_input_event(camera, event) for the spatial editor. This methods are called only if your plugin is the one editing the current object (must be the first to return true from handles(object)).

With all the above in mind, this is an example EditorPlugin script that handles KinematicBody2D objects and translates them when the canvas editor is clicked, capturing the event to avoid selecting other nodes:

tool
extends EditorPlugin

var current_object

func _enter_tree():
	pass

func edit(object):
	current_object = object

func handles(object):
	return object.is_type("KinematicBody2D")

func forward_input_event(event):
	var captured_event = false
	if event.type == InputEvent.MOUSE_BUTTON:
		if event.button_index == BUTTON_LEFT and event.is_pressed():
			# current_object = get_selection().get_selected_nodes()[0]
			current_object.translate(Vector2(10, 10))
			captured_event = true
	return captured_event

Sorry for the delay. The lack of plugin priority may be a problem for you if the node you want to edit extends Polygon2D or another node that already has a plugin to edit it. I’ll make a pull request to add priorities to plugins on 2.1 (already created). Let’s see if it’s accepted :slight_smile:

neikeq | 2016-03-21 20:44

Thanks! I actually wrote similar code that would’ve worked if I’d only used different node type- as in your example KinematicBody2D, but since it failed because of the issue you mentioned, I thought it’s my fault. Anyway, thanks for clearing things up!

Ugis Brekis | 2016-03-21 23:55