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

the anchor changing #506

Closed
wants to merge 1 commit into from

Conversation

LondonClass
Copy link
Contributor

@LondonClass LondonClass commented Feb 8, 2024

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
Copy link
Contributor Author

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?

@GimLala
Copy link
Contributor

GimLala commented Feb 10, 2024

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.

@LondonClass
Copy link
Contributor Author

LondonClass commented Feb 10, 2024

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.

@MyreMylar MyreMylar closed this Feb 12, 2024
@MyreMylar MyreMylar reopened this Feb 12, 2024
@MyreMylar
Copy link
Owner

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.

@LondonClass
Copy link
Contributor Author

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
Copy link
Contributor Author

LondonClass commented Feb 13, 2024

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.

@MyreMylar
Copy link
Owner

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.

@GimLala
Copy link
Contributor

GimLala commented Apr 14, 2024

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.

@MyreMylar
Copy link
Owner

I will revisit the ideas here soon.

@MyreMylar MyreMylar closed this Jun 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

I would like to try modifying the anchors
3 participants