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

Control.set_anchors_preset not work as expect #66651

Open
CsloudX opened this issue Sep 30, 2022 · 12 comments
Open

Control.set_anchors_preset not work as expect #66651

CsloudX opened this issue Sep 30, 2022 · 12 comments

Comments

@CsloudX
Copy link

CsloudX commented Sep 30, 2022

Godot version

v4.0.beta2.official [f8745f2]

System information

Windows 10 64bit

Issue description

In the docs, it say:
image

In the 2D editor, I can set the anchors preset as expect:
GIF

And I want set preset with code:
image

But there wasn't any effect:
GIF

Steps to reproduce

Please run the reproduction project

Minimal reproduction project

AnchorTest.zip

@dominiks
Copy link
Contributor

dominiks commented Sep 30, 2022

I think using the default true for the second parameter causes Godot to adjust the offsets so that no change is visible. If you call

box.set_anchors_preset(Control.PRESET_FULL_RECT)
box.offset_left = 0
box.offset_right = 0
box.offset_bottom = 0
box.offset_top = 0

You get the expected outcome. The anchors are automatically set to 0 when using the preset via the editor.

Calling box.set_anchors_preset(Control.PRESET_FULL_RECT, false) will show you an expanded rectangle but with the old offsets you provided.

Edited to add:
grafik

@CsloudX
Copy link
Author

CsloudX commented Sep 30, 2022

@dominiks Thanks

@dominiks
Copy link
Contributor

dominiks commented Sep 30, 2022

But I have to agree that this does not work as expected and I would have ran into the same issue, even though it's documented. I'm not sure if there is a technical reason for this behaviour or if set_anchors_and_offsets_preset is supposed to mirror the behaviour of the editor button.

@markcagatandavis
Copy link

This seems to still be an issue, I get some weird formatting when I try to use the set_anchors_and_offsets_preset.

Setting by above advised steps resolves this, but annoying:

image

image

image

image

@pc9098
Copy link

pc9098 commented May 29, 2024

This seems to still be an issue, I get some weird formatting when I try to use the set_anchors_and_offsets_preset.

Setting by above advised steps resolves this, but annoying:

I've tested a bit. Your issue seems to be the same as mine. The problem you show in your images is that the node UI/VBoxContainer is in the editor as "Layout Mode: Position" or "Layout Mode: Top Left". If you cahnge it to "Layout Mode: Center" you will see it will work. This is not an intended feature but a bug

@pc9098
Copy link

pc9098 commented May 29, 2024

Changing the propierty anchors_preset solves everything. But this propierty is not meant to be used scripting, it's supposed to be internal but it was exposed by mistake.

From :

Both anchors_preset and layout_mode are not supposed to be used in scripting. They are marked as PROPERTY_USAGE_INTERNAL, and are only relevant for the editor. They exist as properties because that's the only way to have them in the inspector and in a specific order.

@pc9098
Copy link

pc9098 commented May 30, 2024

Found where the mistake was. This is the function set_anchor in Control.cpp,
image

The problem is in

if (!p_keep_offset) { data.offset[p_side] = previous_pos - data.anchor[p_side] * parent_range; if (p_push_opposite_anchor) { data.offset[(p_side + 2) % 4] = previous_opposite_pos - data.anchor[(p_side + 2) % 4] * parent_range; } }

I feel like it is indeed changing the anchor_preset but also changing the offset just as much so it looks like nothing really happended.
I'll try to code a solution for this

EDIT:
pretty sure
data.offset[p_side] = 0
I'll test tomorrow

EDIT2:
tested it and set_anchor() works perfectly with PRESET_LEFT and PRESET_TOP. Will rewrite a few things so it works with RIGHT and BOTTOM.

EDIT3:
Since all this code looks good (to me) this would mean the offset of RIGHT and/or BOT is changed somewhere else, or it is badly redrawn. I cannot think of any else. I give up to some legend to show up

@pc9098
Copy link

pc9098 commented Jun 1, 2024

DONE! I finally got a way to set_anchor() to work! This is the code of the function set_anchor (which is in godot/scene/gui/Control.cpp):

image

void Control::set_anchor(Side p_side, real_t p_anchor, bool p_keep_offset, bool p_push_opposite_anchor) {
	ERR_MAIN_THREAD_GUARD;
	ERR_FAIL_INDEX((int)p_side, 4);

	Rect2 parent_rect = get_parent_anchorable_rect();
	// real_t parent_range = (p_side == SIDE_LEFT || p_side == SIDE_RIGHT) ? parent_rect.size.x : parent_rect.size.y;
	// real_t previous_pos = data.offset[p_side] + data.anchor[p_side] * parent_range;
	// real_t previous_opposite_pos = data.offset[(p_side + 2) % 4] + data.anchor[(p_side + 2) % 4] * parent_range;

	data.anchor[p_side] = p_anchor;

	if (((p_side == SIDE_LEFT || p_side == SIDE_TOP) && data.anchor[p_side] > data.anchor[(p_side + 2) % 4]) || ((p_side == SIDE_RIGHT || p_side == SIDE_BOTTOM) && data.anchor[p_side] < data.anchor[(p_side + 2) % 4])) {
		if (p_push_opposite_anchor) {
			data.anchor[(p_side + 2) % 4] = data.anchor[p_side];
		} else {
			data.anchor[p_side] = data.anchor[(p_side + 2) % 4];
		}
	}

	if (!p_keep_offset) {
		if(p_side == SIDE_LEFT) {data.offset[0] = 0;};
		if(p_side == SIDE_TOP) {data.offset[1] = 0;};
		if(p_side == SIDE_RIGHT) {data.offset[2] = (data.anchor[2] - 1) * (parent_rect.size.x - parent_rect.position.x);};
		if(p_side == SIDE_BOTTOM) {data.offset[3] = (data.anchor[3] - 1) * (parent_rect.size.y - parent_rect.position.y);};
	}

	

	if (is_inside_tree()) {
		_size_changed();
	}

	queue_redraw();
}

I gotta say. It could be much better for some reasons:

  1. Making a bunch of "if" with all possibilities (left, top, right, bottom) is kind of sad

  2. Other functions (lets call them functions X's which I don't know all of them but I think queue_redraw or _size_changed are function X's) depend on the offsets.
    set_anchor changes the offset when 3º argument is false (by default is false). But when we are talking about RIGHT and BOTTOM and 3º argument is false, offset[3] (which is right) and offset[4] which is bottom) are not zero always, they are zero just when 2º argument is 0. This is because functions X's are done in such a way that they think it is apropiate that they shouldn't be zero when there is no margin when we are talking about SIDE_LEFT or SIDE_BOTTOM.
    I honestly disagree with how functions X's work, because if you are setting 3º argument to false then the offset should be zero always because margins are zero. The code I wrote works with those functions X's in mind but I gotta insist, it would be better if we just did offset = 0 and change those functions X's.

I haven't tried set anchor_preset or any other. They may work.

I got no time to test if it worked, so If nobody test it in a month I will be back to test it. I would like to do a pull request or call testes or something, but I don't know how github works. Anyone can tell me what the next thing to do? Is it to do a pull request?

@groud
Copy link
Member

groud commented Jun 3, 2024

So, sorry I'm just picking up with this right now. I am not sure the API is clear, and it seems that the current state of the API + editor is causing some confusion. There might be a few bugs but I need to investigate it a bit further.

To make it clearer:

  • the set_anchor_preset, like the set_anchor function, is supposed to only modify the anchors values. So that's not supposed to be what the editor calls when setting the preset in the top toolbar menu. Instead it should call set_anchors_and_offset_preset, as this function is supposed to both set the anchors and the offsets to good values. From a quick look to the code, it seems like the editor only changes the anchor_preset value, which is not super clear.
  • the p_keep_offset is a bit weirdly named, but the idea behind it is that, when you modify an anchor, the corresponding side of the control gets moved accordingly (like, the offset is an absolute value from the anchor position, which is relative to the parent's size). p_keep_offset is supposed to change the offset value accordingly, so that control's side's position stays the same, despite the anchor value being changed.

From a quick test, there are indeed a few bugs here and there, and I need to figure out what broke things. I think the set_anchor function is likely fine.

I'll have a deeper look to that when I get the time to.

@pc9098
Copy link

pc9098 commented Jun 4, 2024

Ok, so offset is different from margin. Let's suppose we have a very simple scene of controls. Is there an intuitive way to see how much the offset is? Here are some examples of what I feel is intuitive:
image
You can see that those properties can be easily drawn, but I am not so sure about offset.

I discovered offset[SIDE_RIGHT] (and offset[SIDE_BOTTOM]) follow this formula. But still, I can't figure a way to draw it:
image

I already did a pull request that solves set_anchor completely.

I rather have other property different from offset because it feels inintuitive (at this moment), so I may propose to change how distance with anchors are calculated, and erease completely offset from code (maybe substitute it to something more intuitive).

What do you think?

@groud
Copy link
Member

groud commented Jun 4, 2024

Ok, so offset is different from margin. Let's suppose we have a very simple scene of controls. Is there an intuitive way to see how much the offset is? Here are some examples of what I feel is intuitive:

Hmm, this drawing does not seem right to me. The anchors are usually within the boundaries of the parent, and they don't have anything to do with the parent positioning (they only impact the child control ones). Here is a better representation:
Copie d'écran_20240604_091529
(here the parent is the whole window but it works the same for having a parent control)

The position is not depicted on that picture, but it is basically the position of the child control relative to the parent's one. So here, and in general, position = Vector2(left_anchor * parent_size + left_offset, top_anchor * parent_size + top_offset)

@pc9098
Copy link

pc9098 commented Jun 4, 2024

Ok now I understand. Totally my bad! I was using wrongly offset. I will update my PR. I may also fix set_anchor_preset and the others.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants