Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add EditorInterface get_main_screen_editor() method #2081

Open
me2beats opened this issue Jan 6, 2021 · 11 comments
Open

Add EditorInterface get_main_screen_editor() method #2081

me2beats opened this issue Jan 6, 2021 · 11 comments

Comments

@me2beats
Copy link

me2beats commented Jan 6, 2021

Describe the project you are working on

Godot editor plugins (gdscript)

Describe the problem or limitation you are having in your project

I'm creating plugins which do something depending on the active screen (2D, 3D, Script etc).
I need to get current main screen editor name from plugin, but there is no such method.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

Adding method to get main screen editor name would completely solve the problem

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

String get_editor_interface().get_main_screen_editor()

If this enhancement will not be used often, can it be worked around with a few lines of script?

func get_main_screen()->String:
	var screen:String
	var base:Panel = get_editor_interface().get_base_control()
	var editor_head:BoxContainer = base.get_child(0).get_child(0)
	if editor_head.get_child_count()<3:
		# may happen when calling from plugin _init()
		return screen
	var main_screen_buttons:Array = editor_head.get_child(2).get_children()
	for button in main_screen_buttons:
		if button.pressed:
			screen = button.text
			break
	return screen

This should work better but still not well tested:

static func get_main_screen(plugin:EditorPlugin)->int:
	var idx = -1
	var base:Panel = plugin.get_editor_interface().get_base_control()
	var button:ToolButton = find_node_by_class_path(
		base, ['VBoxContainer', 'HBoxContainer', 'HBoxContainer', 'ToolButton'], false
	)

	if not button: 
		return idx
	for b in button.get_parent().get_children():
		b = b as ToolButton
		if not b: continue
		if b.pressed:
			return b.get_index()
	return idx
	

static func find_node_by_class_path(node:Node, class_path:Array, inverted:= true)->Node:
	var res:Node

	var stack = []
	var depths = []

	var first = class_path[0]
	
	var children = node.get_children()
	if not inverted:
		children.invert()

	for c in children:
		if c.get_class() == first:
			stack.push_back(c)
			depths.push_back(0)

	if not stack: return res
	
	var max_ = class_path.size()-1

	while stack:
		var d = depths.pop_back()
		var n = stack.pop_back()

		if d>max_:
			continue
		if n.get_class() == class_path[d]:
			if d == max_:
				res = n
				return res

			var children_ = n.get_children()
			if not inverted:
				children_.invert()
			for c in children_:
				stack.push_back(c)
				depths.push_back(d+1)

	return res

As you can see this is a hacky workaround, I don't like it because it depends on UI tree and UI states (like Button.pressed).

UPD:
solution by pycbouh
https://github.com/pycbouh/godot-time-tracker/blob/master/addons/time-tracker/plugin.gd#L76-L118

Is there a reason why this should be core and not an add-on in the asset library?

Because this method is necessary for creating this kind of plugins.

@YuriSizov
Copy link
Contributor

For whatever reason main_screen_changed signal is on the EditorPlugin, not EditorInterface, so the method should probably also be there? Or the signal needs to be moved.

@yikescloud
Copy link

yikescloud commented Nov 17, 2021

Duplicate of #23955. I found this because I make a 2d editor level plugin and I only want the panel show when it's on the 2D edit mode. Hope it be can add in 3.x

@granitrocky
Copy link

I think this can be closed at least according to this.

@Calinou

This comment has been minimized.

@Calinou Calinou closed this as completed Dec 2, 2024
@Calinou Calinou added this to the 4.0 milestone Dec 2, 2024
@YuriSizov
Copy link
Contributor

YuriSizov commented Dec 2, 2024

I think this can be closed at least according to this.

That method has been around since Godot 4.0's early development at least: godotengine/godot#44524, godotengine/godot#65449

It was likely already implemented in master before this proposal was opened, so maybe OP didn't notice it 🙂

The proposal is about adding a method that would return the name of the current main screen plugin/editor. I.e. "2D", "3D", "Script", "AssetLib", or one of the names added by editor plugins. You can get this name by listening to the main_screen_changed signal, but you cannot ask for it directly. (So you can't get it during the initial load without a lengthy hack.)

The linked method returns a VBox in the editor layout that hosts main screen plugins, which is a completely different matter. While the proposed name for the new method is similar (and perhaps should be changed with the implementation), the purpose is different.

@granitrocky
Copy link

granitrocky commented Dec 2, 2024

@Calinou I see in the editor_node.h file that get_editor_plugin_screen is defined, but not exposed to the ClassDB::bind_method(). Could just adding that method as a public option be enough?

EDIT:
I added a get_editor_plugin_screen to the editor interface, and I can confirm that it works. In C# I can now do GD.Print($"{EditorInterface.Singleton.GetEditorPluginScreen().Name}"); and it returns the plugin for the main tab:

Image

@YuriSizov
Copy link
Contributor

@granitrocky That's the node name, not the name of the tab. The name of the tab is significant, because it is used with methods like EditorInterface::set_main_screen_editor. (Which is why the proposal suggests the name get_main_screen_editor, which is problematic...)

@granitrocky
Copy link

granitrocky commented Dec 2, 2024

Hm, yeah. turns out they don't come out as main screen plugins. _HasMainScreen() comes back false for all tabs.

EDIT:
The main editor plugins we all know and love don't actually use _get_plugin_name. They return their name as just a string. I think we should either change that so that they use _get_plugin_name so scripts can read that or let get_name be public

@Calinou Calinou reopened this Dec 2, 2024
@granitrocky
Copy link

granitrocky commented Dec 3, 2024

@Calinou I will admit that cpp is not my strong suit. Is there a way to override the GDVIRTUAL methods within the class.h files?

I'd like to implement _get_plugin_name for the 4 main screen editor plugins

@Calinou
Copy link
Member

Calinou commented Dec 3, 2024

Is there a way to override the GDVIRTUAL methods within the class.h files?

If you mean implementing support for virtual methods that scripts can contain, it should be feasible. Check BaseButton's _pressed() for an example:

https://github.com/godotengine/godot/blob/0f20e67d8de83c30b5dd79cb68d12d4cf613065d/scene/gui/base_button.cpp#L135-L139

I suggest joining the Godot Contributors Chat and asking on the #editor channel as well.

@granitrocky
Copy link

I actually mean overriding the GDVIRTUAL entirely within the cpp code. For example, EditorPlugin has the virtual _get_plugin_name, but the CanvasItemEditorPlugin can't override that since it exists only in the cpp code. Unless I am missing something, which is entirely possible. I'll ask in the chat

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants