PeterPM _draw() is implemented in CanvasItem. You can use it only on nodes that inherit that class. Viewport is not a canvas item. If you meant to draw over the entire editor window including all gui elements, as a one big canvas, I don't think you can do that without an intervention into engine's source code.

@jonSS Your aprouch is somewhat convoluted, and includes several things not specified, can you please elaborate and make it as a minimal as possible? I just need to draw on the editor.

@xyz And, yes. This is what i am trying to achieve, the entire editor as a big canvas, and some other sub windows.
Indeed the Window or the Viewport class does not have a _draw.
But, one can maybe get the children that is derived from a CanvasItem from the tree.

print(EditorInterface.get_editor_viewport_2d().get_tree().root.get_child(0).get_children()) returns:

Click to reveal Click to hide

[@EditorPropertyNameProcessor@2:<EditorPropertyNameProcessor#24209523966>,
@EditorFileSystem@3:<EditorFileSystem#25283265838>,
@EditorExport@5:<EditorExport#25333597488>,
@EditorResourcePreview@6:<EditorResourcePreview#61438167523>,
@Panel@13:<Panel#61740157429>,
@Timer@49:<Timer#63753423469>,
@Timer@50:<Timer#63770200686>,
@AudioStreamPreviewGenerator@7669:<AudioStreamPreviewGenerator#588075006539>,
@DebuggerEditorPlugin@8282:<DebuggerEditorPlugin#588091783754>,
@AnimationPlayerEditorPlugin@9088:<AnimationPlayerEditorPlugin#619465179447>,
@AnimationTrackKeyEditEditorPlugin@9089:<AnimationTrackKeyEditEditorPlugin#657683679577>,
@CanvasItemEditorPlugin@9273:<CanvasItemEditorPlugin#657717234011>,
@Node3DEditorPlugin@9810:<Node3DEditorPlugin#670367255531>,
@ScriptEditorPlugin@10561:<ScriptEditorPlugin#717192467488>,
@AssetLibraryEditorPlugin@10915:<AssetLibraryEditorPlugin#761937305027>,
@VersionControlEditorPlugin@11351:<VersionControlEditorPlugin#771953303514>,
@AudioBusesEditorPlugin@11353:<AudioBusesEditorPlugin#792404730957>,
@AnimationTreeEditorPlugin@12209:<AnimationTreeEditorPlugin#792421508172>,
@AudioStreamEditorPlugin@12210:<AudioStreamEditorPlugin#829482380432>,
@AudioStreamRandomizerEditorPlugin@12211:<AudioStreamRandomizerEditorPlugin#829515934866>,
@BitMapEditorPlugin@12212:<BitMapEditorPlugin#829532712083>,
@BoneMapEditorPlugin@12213:<BoneMapEditorPlugin#829566266517>,
@Camera3DEditorPlugin@12214:<Camera3DEditorPlugin#829650152602>,
@ControlEditorPlugin@12277:<ControlEditorPlugin#829666929819>,
@CPUParticles3DEditorPlugin@12377:<CPUParticles3DEditorPlugin#832351284539>,
@CurveEditorPlugin@12378:<CurveEditorPlugin#836780469812>,
@DebugAdapterServer@12379:<DebugAdapterServer#836830801463>,
@FontEditorPlugin@12380:<FontEditorPlugin#836914687548>,
@GPUParticles3DEditorPlugin@12480:<GPUParticles3DEditorPlugin#836981796416>,
@GPUParticlesCollisionSDF3DEditorPlugin@12626:<GPUParticlesCollisionSDF3DEditorPlugin#841410981689>,
@GradientEditorPlugin@12627:<GradientEditorPlugin#847752769695>,
@GradientTexture2DEditorPlugin@12628:<GradientTexture2DEditorPlugin#847786324128>,
@InputEventEditorPlugin@12629:<InputEventEditorPlugin#847819878562>,
@LightmapGIEditorPlugin@12774:<LightmapGIEditorPlugin#847853432996>,
@MaterialEditorPlugin@12775:<MaterialEditorPlugin#854161666568>,
@MeshEditorPlugin@12776:<MeshEditorPlugin#854228775435>,
@MeshInstance3DEditorPlugin@12838:<MeshInstance3DEditorPlugin#854262329869>,
@MeshLibraryEditorPlugin@13009:<MeshLibraryEditorPlugin#857835877060>,
@MultiMeshEditorPlugin@13121:<MultiMeshEditorPlugin#867717657728>,
@NavigationObstacle3DEditorPlugin@13127:<NavigationObstacle3DEditorPlugin#872515941781>,
@OccluderInstance3DEditorPlugin@13272:<OccluderInstance3DEditorPlugin#872801154470>,
@PackedSceneEditorPlugin@13273:<PackedSceneEditorPlugin#879109388042>,
@Path3DEditorPlugin@13298:<Path3DEditorPlugin#879142942475>,
@PhysicalBone3DEditorPlugin@13302:<PhysicalBone3DEditorPlugin#880753555302>,
@Polygon3DEditorPlugin@13308:<Polygon3DEditorPlugin#880904550254>,
@ResourcePreloaderEditorPlugin@13483:<ResourcePreloaderEditorPlugin#881189762943>,
@ShaderEditorPlugin@13705:<ShaderEditorPlugin#888588515624>,
@ShaderFileEditorPlugin@13721:<ShaderFileEditorPlugin#899292380017>,
@Skeleton3DEditorPlugin@13722:<Skeleton3DEditorPlugin#899980245913>,
@SkeletonIK3DEditorPlugin@13725:<SkeletonIK3DEditorPlugin#900215126946>,
@SpriteFramesEditorPlugin@14171:<SpriteFramesEditorPlugin#900315790247>,
@StyleBoxEditorPlugin@14172:<StyleBoxEditorPlugin#919928356867>,
@SubViewportPreviewEditorPlugin@14173:<SubViewportPreviewEditorPlugin#919961911301>,
@Texture3DEditorPlugin@14174:<Texture3DEditorPlugin#919995465735>,
@TextureEditorPlugin@14175:<TextureEditorPlugin#920029020169>,
@TextureLayeredEditorPlugin@14176:<TextureLayeredEditorPlugin#920062574603>,
@TextureRegionEditorPlugin@14226:<TextureRegionEditorPlugin#920096129037>,
@ThemeEditorPlugin@15089:<ThemeEditorPlugin#922176503937>,
@VoxelGIEditorPlugin@15235:<VoxelGIEditorPlugin#962542487802>,
@CollisionPolygon2DEditorPlugin@15250:<CollisionPolygon2DEditorPlugin#969437923968>,
@CollisionShape2DEditorPlugin@15252:<CollisionShape2DEditorPlugin#969488255619>,
@CPUParticles2DEditorPlugin@15424:<CPUParticles2DEditorPlugin#969538587270>,
@GPUParticles2DEditorPlugin@15610:<GPUParticles2DEditorPlugin#981500742736>,
@LightOccluder2DEditorPlugin@15625:<LightOccluder2DEditorPlugin#994637303390>,
@Line2DEditorPlugin@15640:<Line2DEditorPlugin#995241283202>,
@NavigationLink2DEditorPlugin@15642:<NavigationLink2DEditorPlugin#995291614853>,
@NavigationObstacle2DEditorPlugin@15657:<NavigationObstacle2DEditorPlugin#995895594665>,
@NavigationPolygonEditorPlugin@15684:<NavigationPolygonEditorPlugin#996969336553>,
@ParallaxBackgroundEditorPlugin@15693:<ParallaxBackgroundEditorPlugin#997019668204>,
@Path2DEditorPlugin@15717:<Path2DEditorPlugin#997455875845>,
@Polygon2DEditorPlugin@15819:<Polygon2DEditorPlugin#1003361456212>,
@Cast2DEditorPlugin@15821:<Cast2DEditorPlugin#1003411787863>,
@Skeleton2DEditorPlugin@15837:<Skeleton2DEditorPlugin#1003462119514>,
@Sprite2DEditorPlugin@15889:<Sprite2DEditorPlugin#1004317757575>,
@TileSetEditorPlugin@16278:<TileSetEditorPlugin#1006733676811>,
@TileMapEditorPlugin@16410:<TileMapEditorPlugin#1024936957184>,
@EditorPluginCSG@16411:<EditorPluginCSG#1031295522407>,
@SceneExporterGLTFPlugin@16558:<SceneExporterGLTFPlugin#1031966611078>,
@GridMapEditorPlugin@16596:<GridMapEditorPlugin#1039432472582>,
@AudioStreamInteractiveEditorPlugin@16662:<AudioStreamInteractiveEditorPlugin#1043039574190>,
@MultiplayerEditorPlugin@16790:<MultiplayerEditorPlugin#1046462126443>,
@NavigationMeshEditorPlugin@16804:<NavigationMeshEditorPlugin#1051730172576>,
@NoiseEditorPlugin@16805:<NoiseEditorPlugin#1052267043520>,
@GDScriptLanguageServer@16876:<GDScriptLanguageServer#1056041917336>,
@EditorImportBlendRunner@16878:<EditorImportBlendRunner#1056243243940>,
@Timer@16879:<Timer#1056461347761>,
@Timer@16880:<Timer#1056494902194>,
JointGizmoUpdateTimer:<Timer#1096626003317>,
@EditorPlugin@17234:<EditorPlugin#1659820371926>]
!<

One of this nodes should contain the engine GUI, and it must be certanly a Control node.

By getting that control node reference, then we can starting talking about calling _draw() inside it, ergo, on the full canvas of the editor itself.

I will analise the output that represent the tree and try to find that node, but please, continue pondering about solution and post any here.


By doing a reverse aprouch:

EditorInterface.get_editor_viewport_2d().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent()

gets me to the @Panel@13:<Panel#61740157429>, as doing one more get_parent() gets me to the same node as:
print(EditorInterface.get_editor_viewport_2d().get_tree().root.get_child(0))
So, it may be the panel that contains the full editor.


Indeed it may be.

var pane = EditorInterface.get_editor_viewport_2d().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent()
pane.modulate = Color.RED

tints the full engine editor red:

But, as speculated, doing a
pane.draw_circle(Vector2(100,100),100,Color.RED) return a:

Drawing is only allowed inside this node's _draw(), functions connected to its draw signal, or when it receives NOTIFICATION_DRAW.

Now, what?

  • xyz replied to this.

    PeterPM One of this nodes should contain the engine GUI

    Nope, I don't think so. Besides, 3D views are not canvas items either. You'll need to go much lower level and the editor itself won't let you go there. You can't go beyond the rendering server, and rendering server has no way of facilitating access to the whole window to draw on, especially not via canvas item class interface or canvas_item_*() calls on the rendering server. You'll need to mess with the source code.

    What's your actual goal with this? Why would you want to do something like this? Some kind of horror thing again, like the one where the engine pretends to delete your files. This is level 2 when the gui gets attacked as well? 😃

    If you want the complete overlay (e.g. Steam overlay) you'll need to do it the way they do it. Hook onto the running application from the outside and do some runtime library injecting. At least that's how it's done with OpenGL. I don't know it's there's a more elegant way with Vulkan but even if there is, it's unlikely you'll be able to pull it off simply by typing some GDScript code.

      xyz Actualy i found the Panel that contains the engine, now i need to register the _draw() funcs on that, because calling directly it is not possible.

      How to do that? Its already proved that its indeed the whole canvas, as the .modulate tinted the whole screen.
      Its something internal, not external, gdscript can be used.
      I think the hard part passed, i now need to know more about how to register the _draw() without pluging a whole script inside the Panel that hosts the editor interface. Or this will be the only way?

      And i need to do that beacuse i am extending the editor, and found what i think is a bug, and i need this to make a test case, that if reproduced, will be posted on github. luckly i am doing something wrong, because i really need the use case, and cant wait for fixages. but lest focus on enabling the _draw() on that suposed Panel that contains the editor. How to, given the context?

      • xyz replied to this.

        PeterPM You can't just take over drawing of built in canvas item classes. The engine is not made to allow that. You can only introduce a new canvas item class and implement custom drawing there by overriding the virtual function _draw(). As I already said, it should either be runtime injection or source code intervention.

          xyz No bro, i did it. 😃

          Click to reveal Click to hide

          @tool
          extends EditorPlugin

          var pane = EditorInterface.get_editor_viewport_2d().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent()
          func enter_tree():
          print(pane.connect("draw", Callable(self, "
          on_draw")))
          func _exit_tree():
          pass
          func _on_draw():
          pane.draw_circle(Vector2(100,100),100,Color.RED)
          func _process(delta):
          pane.modulate = Color.WHITE
          pane.queue_redraw()

          This made this:

          But, because its drawing on the parent node, the child are ocluding it. How to make draw be on top of the childs?

          • xyz replied to this.

            PeterPM But, because its drawing on the parent node, the child are ocluding it. How to make draw be on top of the childs?

            Seems you're the main hacker here. You tell us. 😃

              xyz Hahaha, just a scriptkiddie with acess to gpt. Maybe something with the z-index, but that may cause problens on the other subnodes.

              I tried to add a ColorRect to it, but it does not showd up.
              One thing that would be really cool to have on the engine, would be the "remote" tab when one have a project running, but instead, its the tree of the editor, now that would be very slashy to thinker.

              • xyz replied to this.

                PeterPM One thing that would be really cool to have on the engine, would be the "remote" tab when one have a project running, but instead, its the tree of the editor, now that would be very slashy to thinker.

                Make a plugin for that. It's actually quite easy to do.

                  xyz Why not. Will try investigate that latter, it would even help in this case right now.

                  But, its already kinda working, i need to understand if i can use the _draw() to be on top of other nodes, but it seens not.

                  But, thanks anyway, i solved it.

                  This works:

                  Click to reveal Click to hide

                  `@tool
                  extends EditorPlugin

                  var pane = EditorInterface.get_editor_viewport_2d().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent().get_parent()
                  var cc = Control.new()
                  func enter_tree():
                  var rot = pane.get_parent().get_parent()
                  rot.add_child(cc)
                  print(cc.connect("draw", Callable(self, "
                  on_draw")))

                  func _exit_tree():
                  cc.queue_free()
                  pass

                  func _on_draw():
                  var thesize = EditorInterface.get_editor_viewport_2d().get_parent().get_global_rect()
                  cc.draw_rect(thesize,Color.RED,false)

                  func _process(delta):
                  cc.modulate = Color.WHITE

                  cc.queue_redraw()`

                  Its the test case, i need sinc external objets to the the viewport, and it was missbehaving and not aligning, but is seens to be working now, i will go on and run my tests. Thanks. Solved, for now.

                  • xyz replied to this.

                    PeterPM Ok, you got me there. This is perfectly doable.

                    @tool
                    extends Node2D
                    
                    func _ready():
                    	var overlay = Control.new()
                    	get_tree().get_root().add_child(overlay)
                    	overlay.mouse_filter = Control.MOUSE_FILTER_IGNORE
                    	overlay.draw.connect(
                    		func():
                    			overlay.size = get_tree().get_root().size
                    			for i in 20:
                    				overlay.draw_circle(Vector2(randf()*overlay.size.x, randf()*overlay.size.y), 100, Color.RED)
                    	)

                    I'll leave the above "skin" a permanent fixture in my editor.