godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
90.97k stars 21.16k forks source link

«layout_mode» can't be changed in GDExtension, impossible to use anchors in GDExtension created controls. #84031

Open KirillGrigoriev opened 1 year ago

KirillGrigoriev commented 1 year ago

Godot version

v4.1.2.stable.official [399c9dc39]

System information

Godot v4.1.2.stable - Windows 10.0.19045 - Vulkan (Compatibility) - NVIDIA GeForce GTX 650 (NVIDIA; 30.0.14.7430) - 13th Gen Intel(R) Core(TM) i5-13400 (16 Threads)

Issue description

Anchors only work in «Anchors» layout mode, but controls creating with layout mode «Position» by default, and method for changing layout_mode is not exported for GDExtension. In result, methods «set_anchors_preset», «set_offsets_preset», «set_anchors_and_offsets_preset», «set_anchor», «set_offset», «set_anchor_and_offset» don't work as supposed, they change size and position in moment of call, and don't handle any future control layout changes. In source file of Control (scene/gui/control.h) I found method «void _set_layout_mode(LayoutMode p_mode)», assume, one of previous methods should use this method internally or it should be exported, but this didn't happen. Also, seems like LayoutMode enumeration (values for changing layout_mode property) wasn't exported for GDScript, but it can be done by integer (like self.layout_mode = 1).

Steps to reproduce

  1. By official docs get and compile «godot-cpp» (https://docs.godotengine.org/en/stable/tutorials/scripting/gdextension/gdextension_cpp_example.html).
  2. Check «godot-cpp/gen/include/godot_cpp/classes/control.h» that miss «set_layout_mode» or any «layout_mode» related methods.

Minimal reproduction project

N/A

YuriSizov commented 1 year ago

Anchors only work in «Anchors» layout mode, but controls creating with layout mode «Position» by default

That only applies to the inspector. There is no such limitation in code. Layout mode is an artificial restriction for the editor GUI, not an actual mode for a control.

they change size and position in moment of call, and don't handle any future control layout changes

That is indeed how anchoring works. Depending on the nature of the external changes you may need to re-apply anchors.

KirillGrigoriev commented 1 year ago

Let me explain by example. Let's created simple scene inherited by Control and add 2 Controls and 2 Labels inside this controls. image Now setup «Layout Mode», «Anchor Preset», «Anchor Points», «Anchor Offsets» for given nodes (Control1, Label1, Control2, Label2): image image image image Controls act as expected when Windows (or parent node) is resized: image image Now, let's recreate this in C++ in GDExtension:

Control* control1 = memnew(Control);
control1->set_anchor(SIDE_BOTTOM, 1.0);
control1->set_anchor(SIDE_RIGHT,  0.5);
control1->set_offset(SIDE_BOTTOM, 0.0);
control1->set_offset(SIDE_LEFT,   0.0);
control1->set_offset(SIDE_RIGHT,  0.0);
control1->set_offset(SIDE_TOP,    0.0);
this->add_child(control1);

Label* label1 = memnew(Label);
label1->set_anchor_and_offset(SIDE_BOTTOM, 0.5, 0.0);
label1->set_anchor_and_offset(SIDE_LEFT,   0.5, 0.0);
label1->set_anchor_and_offset(SIDE_RIGHT,  0.5, 0.0);
label1->set_anchor_and_offset(SIDE_TOP,    0.5, 0.0);
label1->set_text("Hello, World!");
control1->add_child(label1);

Control* control2 = memnew(Control);
control2->set_anchor(SIDE_BOTTOM, 1.0);
control2->set_anchor(SIDE_LEFT,   0.5);
control2->set_anchor(SIDE_RIGHT,  1.0);
control1->set_offset(SIDE_BOTTOM, 0.0);
control1->set_offset(SIDE_LEFT,   0.0);
control1->set_offset(SIDE_RIGHT,  0.0);
control1->set_offset(SIDE_TOP,    0.0);
this->add_child(control2);

Label* label2 = memnew(Label);
label2->set_anchors_preset(Control::PRESET_CENTER);
label2->set_offset(SIDE_BOTTOM, 0.0);
label2->set_offset(SIDE_LEFT,   0.0);
label2->set_offset(SIDE_RIGHT,  0.0);
label2->set_offset(SIDE_TOP,    0.0);
label2->set_text("Hello, World!");
control2->add_child(label2);

Let's create another scene that extends our GDExtension Control class and now we see this: image image Now we see elements positioned incorrectly and handle resizing more unexpectedly.