pygame_gui icon indicating copy to clipboard operation
pygame_gui copied to clipboard

the anchor changing

Open LondonClass opened this issue 1 year ago • 6 comments

Borrowed from Unity's RectTransform and modified the anchor points.

The anchor now consists of a dictionary.

The anchor includes four key value pairs, 'left', 'right', 'top', and 'bottom'. Floating point number, between 0 and 1. 0 indicates anchoring on the left or upper boundary, 1 indicates anchoring on the right or lower boundary, and 0.5 indicates anchoring in the middle.

Add two new values 'pivotx',' pivoty', floating-point numbers between 0 and 1, determines the scaling center of the UI when the size changes. (0, 0) represents the scaling center in the upper left corner, (1, 1) represents the scaling center in the lower right corner (0.5, 0.5) represents the scaling center in the center of the object.

Supports using strings instead of numbers 'left', ' right', ' top', ' bottom', and 'center' represent 0,1, 0,1, and 0.5, respectively.

Principle:

Calculate the anchor rectangle based on the parent container rectangle. 'left', 'right', 'top', and 'bottom' correspond to the percentile of the four sides of the anchored rectangle on the parent container, respectively. When the parent container changes, the anchor rectangle changes accordingly. Keep the distance between the four sides of the element and the four sides of the anchored rectangle fixed and unchanged. So the elements will change with the change of the anchored rectangle. When the 'left' and 'right' values of the anchor point are equal, and the 'top' and 'bottom' values are equal, the left and right edges, top and bottom edges of the anchored rectangle coincide, and the anchored rectangle degenerates into an anchor point. At this point, the size of the element does not change with the size of the parent container. When the size of an element changes, the relative position of its scaling center remains unchanged.

Features:

  1. Now the element can anchor the percentile position of the form, for example, left: 0.4, which means anchoring the left side at 40% of the container width.

  2. Add a scaling center for the element, which can specify how to move it when the size of the element changes.

  3. There is a modification to the annotation. If this modification is made, there is no need to subtract the element width when anchoring the element to the right and bottom.

There may still be some problems in the code. The performance of the code may need attention.

Fixes #505

LondonClass avatar Feb 08 '24 10:02 LondonClass

Sometimes it is necessary to modify the position and size of elements simultaneously.

If set_dimensions and set-relative_position are called simultaneously, it will result in some duplicate calculations. Do we need to solve this?

LondonClass avatar Feb 10 '24 01:02 LondonClass

Do all the previous anchors work the same? As in, anyone who was already using this library will not have to change their current implementation, right? Other than that, it sounds like a good addition.

GimLala avatar Feb 10 '24 10:02 GimLala

Do all the previous anchors work the same? As in, anyone who was already using this library will not have to change their current implementation, right? Other than that, it sounds like a good addition.

Most of the time, this is the case, but certain behaviors may undergo slight changes. It should have an impact on the part you submitted. Because the anchor is a number instead of a string.

Another option is that I can add an offset of line132 in pygame_gui/core/ui_element.py, which will prevent the need to subtract the width of the rectangle when the anchor is anchored on the right and bottom sides. But the problem it brings is that there will be problems with past implementations.

LondonClass avatar Feb 10 '24 13:02 LondonClass

I think it is great to support numeric anchors as well as things like 'top', 'center' and 'bottom' - but I'd like to keep the former working (i.e. by translating 'center' to (0.5, 0.5)) as they were picked to be familiar to pygame users as these terms are used in the pygame.Rect class. It looks like that is what you have done here.

It is generally best if we can maintain backwards compatibility with previous versions as otherwise we break people's GUI layouts when they update to the new version. If we aren't going to do this for a good reason, then there should be a cycle of deprecation warnings before changing the behaviour over. Again it seems like that is what is happening.

Right now it looks like four of the unit tests are failing after this PR not sure why exactly at the minute.

MyreMylar avatar Feb 12 '24 12:02 MyreMylar

I think it is great to support numeric anchors as well as things like 'top', 'center' and 'bottom' - but I'd like to keep the former working (i.e. by translating 'center' to (0.5, 0.5)) as they were picked to be familiar to pygame users as these terms are used in the pygame.Rect class. It looks like that is what you have done here.

It is generally best if we can maintain backwards compatibility with previous versions as otherwise we break people's GUI layouts when they update to the new version. If we aren't going to do this for a good reason, then there should be a cycle of deprecation warnings before changing the behaviour over. Again it seems like that is what is happening.

Right now it looks like four of the unit tests are failing after this PR not sure why exactly at the minute.

The previous anchor points had logical inconsistencies. When using "left" and "right" anchor points, the left-top of relative_rect is the relative position of the element's top-left corner. However, when using the "centerx" anchor point, the left-top of relative_rect is the relative position of the element's center. Unifying this logic here can make the anchor points behave more predictably.

It's impossible to simultaneously achieve the following three points:

Fix the logical inconsistency Maintain consistency with previous usage Provide backward compatibility Do you have any ideas on how to address this?

LondonClass avatar Feb 13 '24 04:02 LondonClass

I think it is great to support numeric anchors as well as things like 'top', 'center' and 'bottom' - but I'd like to keep the former working (i.e. by translating 'center' to (0.5, 0.5)) as they were picked to be familiar to pygame users as these terms are used in the pygame.Rect class. It looks like that is what you have done here.

It is generally best if we can maintain backwards compatibility with previous versions as otherwise we break people's GUI layouts when they update to the new version. If we aren't going to do this for a good reason, then there should be a cycle of deprecation warnings before changing the behaviour over. Again it seems like that is what is happening.

Right now it looks like four of the unit tests are failing after this PR not sure why exactly at the minute.

As for testing, there's no need to worry. Now, relative_margin will be initialized immediately after creation because, after modification, this is the more fundamental information since it maintains the relative positions of all four edges unchanged.

This is the expected behavior and will not have any impact. The way to address this is to modify the tests themselves.

LondonClass avatar Feb 13 '24 04:02 LondonClass

I think the thing to do here is going to be to split these ideas into two phases of implementation:

  1. Swap to numeric versions of the existing anchor RHS values internally, and use numbers between 0.0 and 1.0 as an alternative input. So centrex & centrey become 0.5, top and left become 0.0 and bottom and right become 1.0. syntax might look something like this:
anchors = {"left": 0.0,
           "top": 0.0,
           "right": 0.0,
           "bottom": 0.0}

# equivalent to current
anchors = {"left": "left",
           "top": "top",
           "right": "left",
           "bottom": "top"}

A good test of this working properly is everything currently working - plus a new ability to anchor an element to 2/3rds of the way along the width of a container with a left and right anchor of 0.666.

  1. Add an "anchor_source" parameter (mirroring anchor_targets) to UIElement (and all elements) this will have a default value of (0.0,0.0) and equate to the top left corner of an element. An element will only be able to have one anchor source to keep it in line with current functionality - where everything is offset from the top left.

The anchor source will again have x and y values between 0.0 and 1.0 and it's exact pixel location on the element will need recalculating whenever the element changes in size. These values are then used to modify the initial positioning values passed into element's 'relative_rect' parameter or set with 'set_position'.

I think relative_rect will need to become a property of UIElement rather than a public attribute because what it represents is going to get very confused. You will no longer be able to simply edit or read it's attributes in a sensible fashion without reference to at least the anchor source.

Probably a good idea to also have some word values for "anchor source" as well e.g. 'center', 'topleft', 'bottomright'.

The goal here would be to get to a place where you could do:

hello_button = UIButton((0, 0), 'Hello', 
                        anchors={"top": "centery", "left": "centerx", "bottom": "centery", "right": "centerx"},
                        anchor_source="center")

To make a button that is centered in the middle of it's container. Then you could probably build in the special case that if you set the "center" anchor in the anchors dictionary it automatically sets the anchor_source to "center" and invalidates the other four anchor's values to get back to the "center": "center" case for speed. Maybe we could even have a default position of (0,0) for elements making this valid:

hello_button = UIButton( 'Hello',  anchors={"center": "center"})

Anyway, those are my current thoughts on anchoring.

MyreMylar avatar Apr 13 '24 08:04 MyreMylar

And for programs which use relative rect in some way, we could rename the attribute to _relative_rect and create a property called relative rect which can do all the calculation for backwards compatibility? Then programs created before this change will need minimal refactoring if any.

GimLala avatar Apr 14 '24 12:04 GimLala