Some Info, if you get in GUI & Input coordinate mayhem, pivot, scale, rotation, input

wombatstampedewombatstampede Posts: 72Member

Hi all,
the GUI topic can get really complicated if you are working with i.e. scaled or rotated controls. Maybe you'll have to catch events via > _input(event) because of touch-screen/multitouch requirements. And then you'll notice that there IS documentation about this but some parts of the docs are still a bit "blurry". So I thought it might be a good idea to put up a post which sheds some light into the nasty sides of GUI and coordinates. Feel free to add/correct.

Control.rect_global_position

Ok you know that rect_position marks the local position of a control inside their parent controls. So you think that rect_global_position equals $OnlyParentCtrl.rect_position + $ChildCtrl.rect_position?
Well, not quite, not always. This is because rect_global_position takes scaling, pivot and rotation into account.

Example: (Parent Controls are at (0,0))

rect_position = (0,0)
rect_pivot_offset = (30,30)
rect_size = (50,50)
rect_scale = (0.5,0.5)
==> rect_global_position = (15,15)

This shows that rect_global_position marks the actual upper left position of the scaled rectangle. Also, if you rotate the control then it will mark the rotated upper left of the control.

Example: (Parent Controls are at (0,0))

rect_position = (0,0)
rect_pivot_offset = (30,30)
rect_size = (50,50)
rect_scale = (0.5,0.5)
rect_rotation = 90.0
==> rect_global_position = (45,15)

Control.get_global_rect

This method returns a Rect2 which contains the position = rect_global_position and size = rect_size. Ok, you might already notice that two worlds are mixed up: The position (as told above) takes scaling, rotation, pivot into account. And size? Well size is just size, unscaled, unrotated.

If you want to somehow transform screen coords to local control coords or vice versa for rotated controls then you might have a look into get_global_transform() from CanvasItem (Control is Inherited from CanvasItem).

Control._gui_input(event)

This is event is basically only triggered when something happens in the rectangle of the control (MouseMove, Touch, Drag, etc.).
The event coordinates are local. This means that the "upper left" of the Control is (0,0) and the "lower right" is (rect_size.x-1,rect_size.y-1).

Please note that these local coordinates move inside the unscaled an unrotated Control. So if this Control is rotated by 90° then the local coordinates (0,0) are actually on the upper right of the control.

Control._input(event)

This event is is also triggered if an input event occurs on a region outside the control. The event coordinates are "global" screen coordinates. So, maybe you want to know if they are inside your Controls region?

_input(event):
    evLocal = make_input_local(event)
    if Rect2(Vector2(0,0),rect_size).has_point(evLocal.position):
        do something...

make_input_local() does the magic for you. No fiddling with Transform2Ds.

Sign In or Register to comment.