Toxe It's not what I wanted but i might be enough. I will try it, thank you!

I'm vomiting ideas here:

  • draw() signal fires everytime a control node is redrawn, for example, when appearing, moving or resizing.
  • a rect's position should be located at its top left corner by default, so:
    anywhere between rect.position and rect.position + rect.size would be occupied by rect.

you could use that draw() signal with the vector2 math above to convince your control nodes to behave how I think you're wanting them to behave.
if you're clever.
i am a lot more familiar with gdscript than most of godot's builtin functions, so please someone speak up if what i'm suggesting is unnecessarily hacky.

    Toxe I tried it with containers and it kind of works but It's not really what I was looking for. This way I can't move them around and connect them as I had planned.

    If someone knows a better way, I would appreciate it!

    Oh, you wanted to connect them? I thought they were more like dialog boxes.

      packrat Those are great ideas too! I will test them and get back to you!

      Toxe Oh no this is more like my dialog manager so this is where I will be making the narrative in the back end. At the end I should be able to export the whole tree of conversation to a json file that I will use with my actual dialogue box. That's why I want to be able to move them around and connect them but without them overlapping/touching

      • xyz replied to this.

        Godoten It's not worth the effort if this is just for backend. Let them overlap. Almost every node editor in existence overlaps its nodes.

          I agree it isn't necessary or worth it, but why not do it anyway for fun? 😛

          @Godoten Do you already have figured out how you're doing click & drag? You should implement that first, then at the point in code where you release after dragging you can worry about making the boxes not overlap.

            xyz True but it's a good opportunity to challenge myself so I can learn more about the engine (and do more things in the actual game). So my goal is that they can't won't touch.

            • xyz replied to this.

              award Yeah, it's more like a challenge to improve. In fact I could use GraphNodes and GraphEdit to have them directly but I'm traying to make them myself so I can learn and play with the logic.

              I haven't figured out the connection yet, but I guess I will use curve2D and a simple drag and drop code that checks if can_drag and can_drop. The hard part would be making interactions between them when linked, I think.

              Godoten True but it's a good opportunity to challenge myself

              Well if you want to challenge yourself, then you should figure it out on your own. By asking "how to", you're challenging the people on the forum instead 😉

              This can be done in several ways. Start by precisely describing the behavior. Can you drag one or multiple boxes at a time? Should they rearrange as you drag or only when you drop? Should they be pushed in the direction of drag or only moved out of the way... etc.

                xyz I tried myself for a long time. If I'm asking is because I got stuck and you gotta know your limits. Now @packrat gave me a great idea that a can try to implement and learn more.

                I thought it would be possible to give them some kind of "collide" property just like bodies, but I guess I will need to code the whole interaction.

                  Godoten thanks for the validation. i use knowledge from vain/pointless projects all the time.
                  i do appreciate custom UI behaviour. altering how the player interacts with a menu can make your game subconsciously memorable. i didn't love Metroid Prime 2, but the main menu in that game still sticks in my head, simply because it was weird.
                  do be careful with that, it can also cause your game to suck..

                  Godoten A quick and dirty custom implementation of rectangular Separating Axis Theorem should do the trick. It's been a while since I implemented one of those, so challenge accepted 😃

                  main.gd:

                  extends Node2D
                  
                  func separate(window1, window2, bias = .5):
                  	var r1 = window1.get_rect()
                  	var r2 = window2.get_rect()
                  
                  	var ri = r1.intersection(r2)	
                  	if not ri.has_area():
                  		return
                  
                  	var displace = Vector2.ZERO
                  	var o1 = r1.end - r2.position
                  	var o2 = r2.end - r1.position
                  
                  	if(ri.size.x < ri.size.y):
                  		if abs(o1.x) < abs(o2.x):
                  			displace.x += o1.x
                  		else:
                  			displace.x -= o2.x	
                  	else:
                  		if abs(o1.y) < abs(o2.y):
                  			displace.y += o1.y
                  		else:
                  			displace.y -= o2.y	
                  	
                  	window2.position += displace * bias
                  	window1.position -= displace * (1-bias)
                  
                  func _process(delta):
                  	for w1 in get_children():
                  		for w2 in get_children():
                  			if w1 != w2:
                  				var bias = .5
                  				if w1.dragging: 
                  					bias = 1
                  				elif w2.dragging:
                  					bias = 0
                  				separate(w1, w2, bias)

                  window.gd:

                  extends ColorRect
                  
                  var dragging = false
                  
                  func _gui_input(event):
                  	if event is InputEventMouseButton:
                  		if event.is_pressed():
                  			dragging = true
                  			modulate = Color(1.0, 0.0, 0.0, 1.0)
                  
                  	if event is InputEventMouseMotion and dragging:
                  		position += event.relative
                  
                  func _input(event):
                  	if event is InputEventMouseButton and not event.is_pressed():
                  		dragging = false
                  		modulate = Color(1.0, 1.0, 1.0, 1.0)

                  Note that running it once cannot guarantee cascaded separation in very crowded situations. However we run it every frame and it eventually sorts itself out throughout several frames, which is mostly unnoticeable.

                  You homework is to adapt it for multiple dragging windows, and optimize for performance 😉

                    xyz Wow that actually looks amazing, great work! I understand part of what you did there, but another part of the code is a mystery to me. I will spend the day studying it, thank you so much!