diff --git a/doc/classes/NinePatchRect.xml b/doc/classes/NinePatchRect.xml
index c30662b1224c..d0c697b45eed 100644
--- a/doc/classes/NinePatchRect.xml
+++ b/doc/classes/NinePatchRect.xml
@@ -72,5 +72,8 @@
Repeats the center texture across the NinePatchRect, but will also stretch the texture to make sure each tile is visible in full. This may cause the texture to be distorted, but less than [constant AXIS_STRETCH_MODE_STRETCH]. The texture must be seamless for this to work without displaying artifacts between edges.
+
+ Keep center slices centered. Useful for tooltips with arrow or controls with handles.
+
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index a3ec4d25f1ba..53289be24f3e 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -5137,6 +5137,9 @@
The nine patch gets filled with tiles where needed and stretches them a bit if needed.
+
+ The nine patch gets stretched where needed, keeping the middle centered at its original size.
+
Uses the default filter mode for this [Viewport].
diff --git a/doc/classes/StyleBoxTexture.xml b/doc/classes/StyleBoxTexture.xml
index 14bceb4d4cf7..5f3c83defc3b 100644
--- a/doc/classes/StyleBoxTexture.xml
+++ b/doc/classes/StyleBoxTexture.xml
@@ -118,5 +118,8 @@
Repeats the stylebox's texture to match the stylebox's size according to the nine-patch system. Unlike [constant AXIS_STRETCH_MODE_TILE], the texture may be slightly stretched to make the nine-patch texture tile seamlessly.
+
+ Keep center slices centered. Useful for tooltips with arrow or controls with handles.
+
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index ce8fe25625bf..f00c41e7fa51 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -502,6 +502,9 @@ float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, flo
ratio = mod(ratio * scale, 1.0);
// Scale to source texture.
return (margin_begin + ratio * dst_area) * tex_pixel_size;
+ } else if (np_repeat == 3) { // Center.
+ const float CMP_EPSILON = 1e-5;
+ return clamp(pixel - (draw_size - tex_size) / 2.0, margin_begin + CMP_EPSILON, tex_size - margin_end - CMP_EPSILON) * tex_pixel_size;
} else { // Shouldn't happen, but silences compiler warning.
return 0.0;
}
diff --git a/scene/gui/nine_patch_rect.cpp b/scene/gui/nine_patch_rect.cpp
index e2ae824e6072..7c9ad943ef3b 100644
--- a/scene/gui/nine_patch_rect.cpp
+++ b/scene/gui/nine_patch_rect.cpp
@@ -81,12 +81,13 @@ void NinePatchRect::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::INT, "patch_margin_right", PROPERTY_HINT_RANGE, "0,16384,1,suffix:px"), "set_patch_margin", "get_patch_margin", SIDE_RIGHT);
ADD_PROPERTYI(PropertyInfo(Variant::INT, "patch_margin_bottom", PROPERTY_HINT_RANGE, "0,16384,1,suffix:px"), "set_patch_margin", "get_patch_margin", SIDE_BOTTOM);
ADD_GROUP("Axis Stretch", "axis_stretch_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_horizontal", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_h_axis_stretch_mode", "get_h_axis_stretch_mode");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_vertical", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_v_axis_stretch_mode", "get_v_axis_stretch_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_horizontal", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit,Center"), "set_h_axis_stretch_mode", "get_h_axis_stretch_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_vertical", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit,Center"), "set_v_axis_stretch_mode", "get_v_axis_stretch_mode");
BIND_ENUM_CONSTANT(AXIS_STRETCH_MODE_STRETCH);
BIND_ENUM_CONSTANT(AXIS_STRETCH_MODE_TILE);
BIND_ENUM_CONSTANT(AXIS_STRETCH_MODE_TILE_FIT);
+ BIND_ENUM_CONSTANT(AXIS_STRETCH_MODE_CENTER);
}
void NinePatchRect::_texture_changed() {
diff --git a/scene/gui/nine_patch_rect.h b/scene/gui/nine_patch_rect.h
index ae9fab17739c..3f58f055d8fd 100644
--- a/scene/gui/nine_patch_rect.h
+++ b/scene/gui/nine_patch_rect.h
@@ -41,6 +41,7 @@ class NinePatchRect : public Control {
AXIS_STRETCH_MODE_STRETCH,
AXIS_STRETCH_MODE_TILE,
AXIS_STRETCH_MODE_TILE_FIT,
+ AXIS_STRETCH_MODE_CENTER,
};
bool draw_center = true;
diff --git a/scene/resources/style_box_texture.cpp b/scene/resources/style_box_texture.cpp
index 156525d21c46..3fef8eb1209d 100644
--- a/scene/resources/style_box_texture.cpp
+++ b/scene/resources/style_box_texture.cpp
@@ -223,8 +223,8 @@ void StyleBoxTexture::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_BOTTOM);
ADD_GROUP("Axis Stretch", "axis_stretch_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_horizontal", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_h_axis_stretch_mode", "get_h_axis_stretch_mode");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_vertical", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_v_axis_stretch_mode", "get_v_axis_stretch_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_horizontal", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit,Center"), "set_h_axis_stretch_mode", "get_h_axis_stretch_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_vertical", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit,Center"), "set_v_axis_stretch_mode", "get_v_axis_stretch_mode");
ADD_GROUP("Sub-Region", "region_");
ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect", PROPERTY_HINT_NONE, "suffix:px"), "set_region_rect", "get_region_rect");
@@ -236,6 +236,7 @@ void StyleBoxTexture::_bind_methods() {
BIND_ENUM_CONSTANT(AXIS_STRETCH_MODE_STRETCH);
BIND_ENUM_CONSTANT(AXIS_STRETCH_MODE_TILE);
BIND_ENUM_CONSTANT(AXIS_STRETCH_MODE_TILE_FIT);
+ BIND_ENUM_CONSTANT(AXIS_STRETCH_MODE_CENTER);
}
StyleBoxTexture::StyleBoxTexture() {}
diff --git a/scene/resources/style_box_texture.h b/scene/resources/style_box_texture.h
index b1b833f4706f..84cb7388d7fc 100644
--- a/scene/resources/style_box_texture.h
+++ b/scene/resources/style_box_texture.h
@@ -42,6 +42,7 @@ class StyleBoxTexture : public StyleBox {
AXIS_STRETCH_MODE_STRETCH,
AXIS_STRETCH_MODE_TILE,
AXIS_STRETCH_MODE_TILE_FIT,
+ AXIS_STRETCH_MODE_CENTER,
};
private:
diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl
index 7a13ac720796..285bffeffb9e 100644
--- a/servers/rendering/renderer_rd/shaders/canvas.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas.glsl
@@ -336,6 +336,9 @@ float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, flo
ratio = mod(ratio * scale, 1.0);
// Scale to source texture.
return (margin_begin + ratio * dst_area) * tex_pixel_size;
+ } else if (np_repeat == 3) { // Center.
+ const float CMP_EPSILON = 1e-5;
+ return clamp(pixel - (draw_size - tex_size) / 2.0, margin_begin + CMP_EPSILON, tex_size - margin_end - CMP_EPSILON) * tex_pixel_size;
} else { // Shouldn't happen, but silences compiler warning.
return 0.0;
}
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index 00015b74a1d2..77ff2950f0b9 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -3202,6 +3202,7 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(NINE_PATCH_STRETCH);
BIND_ENUM_CONSTANT(NINE_PATCH_TILE);
BIND_ENUM_CONSTANT(NINE_PATCH_TILE_FIT);
+ BIND_ENUM_CONSTANT(NINE_PATCH_CENTER);
BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_FILTER_DEFAULT);
BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 016801fa6e2d..5039b3a48db1 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -1374,6 +1374,7 @@ class RenderingServer : public Object {
NINE_PATCH_STRETCH,
NINE_PATCH_TILE,
NINE_PATCH_TILE_FIT,
+ NINE_PATCH_CENTER,
};
virtual void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = -1.0, bool p_antialiased = false) = 0;