diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index 927ab9ae0e35..69b0650046fc 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -1019,6 +1019,24 @@ The node's position, relative to its containing node. It corresponds to the rectangle's top-left corner. The property is not affected by [member pivot_offset]. + + Position offset applied after layouting. If [member render_offset_relative_to_size] is [code]true[/code], the offset is relative to the node's [member size]. + + + If [code]true[/code], [member render_offset] is relative to the node's [member size], otherwise it is absolute pixel values. + + + Rotation applied after layouting. The rotation pivot is defined by [member render_transform_pivot]. + + + Scale applied after layouting. The scale pivot is defined by [member render_transform_pivot]. + + + Pivot used for [member render_rotation] and [member render_scale]. If [member render_transform_pivot_relative_to_size] is [code]true[/code], the pivot is relative to the node's size, otherwise it represents absolute pixel values. + + + If [code]true[/code], [member render_transform_pivot] is relative to the node's [member size], otherwise it is absolute pixel values. + The node's rotation around its pivot, in radians. See [member pivot_offset] to change the pivot's position. [b]Note:[/b] This property is edited in the inspector in degrees. If you want to use degrees in a script, use [member rotation_degrees]. diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 15ada0021a17..8d738fa52511 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -483,6 +483,18 @@ void Control::_validate_property(PropertyInfo &p_property) const { p_property.hint = PROPERTY_HINT_LINK; } + if (p_property.name == "render_offset") { + p_property.hint_string = data.render_offset_relative_to_size + ? "" + : "suffix:px"; + } + + if (p_property.name == "render_transform_pivot") { + p_property.hint_string = data.render_transform_pivot_relative_to_size + ? "" + : "suffix:px"; + } + // Validate which positioning properties should be displayed depending on the parent and the layout mode. Node *parent_node = get_parent_control(); if (!parent_node) { @@ -697,6 +709,24 @@ void Control::_update_canvas_item_transform() { xform[2] = (xform[2] + Vector2(0.5, 0.5)).floor(); } + Vector2 absolute_render_offset = data.render_offset; + Vector2 absolute_render_transform_pivot = data.render_transform_pivot; + + if (data.render_offset_relative_to_size) { + absolute_render_offset *= get_size(); + } + + if (data.render_transform_pivot_relative_to_size) { + absolute_render_transform_pivot *= get_size(); + } + + xform *= Transform2D() + .translated(-absolute_render_transform_pivot) + .rotated(data.render_rotation) + .scaled(data.render_scale) + .translated(absolute_render_transform_pivot) + .translated(absolute_render_offset); + RenderingServer::get_singleton()->canvas_item_set_transform(get_canvas_item(), xform); } @@ -1675,6 +1705,76 @@ Size2 Control::get_custom_minimum_size() const { return data.custom_minimum_size; } +void Control::set_render_offset(const Vector2 &p_offset) { + data.render_offset = p_offset; + queue_redraw(); + _notify_transform(); +} + +Vector2 Control::get_render_offset() const { + return data.render_offset; +} + +void Control::set_render_offset_relative_to_size(bool p_relative) { + if (data.render_offset_relative_to_size == p_relative) { + return; + } + + data.render_offset_relative_to_size = p_relative; + queue_redraw(); + _notify_transform(); + notify_property_list_changed(); +} + +bool Control::get_render_offset_relative_to_size() const { + return data.render_offset_relative_to_size; +} + +void Control::set_render_scale(const Vector2 &p_scale) { + data.render_scale = p_scale; + queue_redraw(); + _notify_transform(); +} + +Vector2 Control::get_render_scale() const { + return data.render_scale; +} + +void Control::set_render_rotation(real_t p_rotation) { + data.render_rotation = p_rotation; + queue_redraw(); + _notify_transform(); +} + +real_t Control::get_render_rotation() const { + return data.render_rotation; +} + +void Control::set_render_transform_pivot(const Vector2 &p_pivot) { + data.render_transform_pivot = p_pivot; + queue_redraw(); + _notify_transform(); +} + +Vector2 Control::get_render_transform_pivot() const { + return data.render_transform_pivot; +} + +void Control::set_render_transform_pivot_relative_to_size(bool p_relative) { + if (data.render_transform_pivot_relative_to_size == p_relative) { + return; + } + + data.render_transform_pivot_relative_to_size = p_relative; + queue_redraw(); + _notify_transform(); + notify_property_list_changed(); +} + +bool Control::get_render_transform_pivot_relative_to_size() const { + return data.render_transform_pivot_relative_to_size; +} + void Control::_update_minimum_size_cache() { Size2 minsize = get_minimum_size(); minsize = minsize.max(data.custom_minimum_size); @@ -3423,6 +3523,19 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("find_next_valid_focus"), &Control::find_next_valid_focus); ClassDB::bind_method(D_METHOD("find_valid_focus_neighbor", "side"), &Control::find_valid_focus_neighbor); + ClassDB::bind_method(D_METHOD("set_render_offset", "offset"), &Control::set_render_offset); + ClassDB::bind_method(D_METHOD("get_render_offset"), &Control::get_render_offset); + ClassDB::bind_method(D_METHOD("set_render_offset_relative_to_size", "relative"), &Control::set_render_offset_relative_to_size); + ClassDB::bind_method(D_METHOD("get_render_offset_relative_to_size"), &Control::get_render_offset_relative_to_size); + ClassDB::bind_method(D_METHOD("set_render_scale", "scale"), &Control::set_render_scale); + ClassDB::bind_method(D_METHOD("get_render_scale"), &Control::get_render_scale); + ClassDB::bind_method(D_METHOD("set_render_rotation", "rotation"), &Control::set_render_rotation); + ClassDB::bind_method(D_METHOD("get_render_rotation"), &Control::get_render_rotation); + ClassDB::bind_method(D_METHOD("set_render_transform_pivot", "pivot"), &Control::set_render_transform_pivot); + ClassDB::bind_method(D_METHOD("get_render_transform_pivot"), &Control::get_render_transform_pivot); + ClassDB::bind_method(D_METHOD("set_render_transform_pivot_relative_to_size", "relative"), &Control::set_render_transform_pivot_relative_to_size); + ClassDB::bind_method(D_METHOD("get_render_transform_pivot_relative_to_size"), &Control::get_render_transform_pivot_relative_to_size); + ClassDB::bind_method(D_METHOD("set_h_size_flags", "flags"), &Control::set_h_size_flags); ClassDB::bind_method(D_METHOD("get_h_size_flags"), &Control::get_h_size_flags); @@ -3586,6 +3699,14 @@ void Control::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "size_flags_vertical", PROPERTY_HINT_FLAGS, "Fill:1,Expand:2,Shrink Center:4,Shrink End:8"), "set_v_size_flags", "get_v_size_flags"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size_flags_stretch_ratio", PROPERTY_HINT_RANGE, "0,20,0.01,or_greater"), "set_stretch_ratio", "get_stretch_ratio"); + ADD_GROUP("Render Transform", "render_"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "render_offset", PROPERTY_HINT_NONE), "set_render_offset", "get_render_offset"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "render_offset_relative_to_size"), "set_render_offset_relative_to_size", "get_render_offset_relative_to_size"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "render_scale"), "set_render_scale", "get_render_scale"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "render_rotation", PROPERTY_HINT_NONE, "-360,360,0.1,or_less,or_greater,radians_as_degrees"), "set_render_rotation", "get_render_rotation"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "render_transform_pivot", PROPERTY_HINT_NONE), "set_render_transform_pivot", "get_render_transform_pivot"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "render_transform_pivot_relative_to_size"), "set_render_transform_pivot_relative_to_size", "get_render_transform_pivot_relative_to_size"); + ADD_GROUP("Localization", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "localize_numeral_system"), "set_localize_numeral_system", "is_localizing_numeral_system"); diff --git a/scene/gui/control.h b/scene/gui/control.h index c784d4330dac..8454f8dae34f 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -194,6 +194,13 @@ class Control : public CanvasItem { Vector2 scale = Vector2(1, 1); Vector2 pivot_offset; + Vector2 render_offset; + bool render_offset_relative_to_size = true; + Vector2 render_scale = Vector2(1, 1); + real_t render_rotation = 0.0; + Vector2 render_transform_pivot; + bool render_transform_pivot_relative_to_size = true; + Point2 pos_cache; Size2 size_cache; Size2 minimum_size_cache; @@ -493,6 +500,20 @@ class Control : public CanvasItem { void set_custom_minimum_size(const Size2 &p_custom); Size2 get_custom_minimum_size() const; + // Render transform. + void set_render_offset(const Vector2 &p_offset); + Vector2 get_render_offset() const; + void set_render_offset_relative_to_size(bool p_relative); + bool get_render_offset_relative_to_size() const; + void set_render_scale(const Vector2 &p_scale); + Vector2 get_render_scale() const; + void set_render_rotation(real_t p_rotation); + real_t get_render_rotation() const; + void set_render_transform_pivot(const Vector2 &p_pivot); + Vector2 get_render_transform_pivot() const; + void set_render_transform_pivot_relative_to_size(bool p_relative); + bool get_render_transform_pivot_relative_to_size() const; + // Container sizing. void set_h_size_flags(BitField p_flags);