summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/audio_stream_player_2d.cpp3
-rw-r--r--scene/3d/audio_stream_player_3d.cpp3
-rw-r--r--scene/3d/collision_polygon_3d.cpp16
-rw-r--r--scene/3d/collision_polygon_3d.h4
-rw-r--r--scene/3d/node_3d.cpp4
-rw-r--r--scene/3d/node_3d.h4
-rw-r--r--scene/animation/animation_blend_tree.cpp7
-rw-r--r--scene/animation/animation_blend_tree.h2
-rw-r--r--scene/animation/animation_node_state_machine.cpp12
-rw-r--r--scene/animation/animation_node_state_machine.h2
-rw-r--r--scene/audio/audio_stream_player.cpp3
-rw-r--r--scene/gui/item_list.cpp11
-rw-r--r--scene/gui/label.cpp16
-rw-r--r--scene/gui/line_edit.cpp24
-rw-r--r--scene/gui/link_button.cpp8
-rw-r--r--scene/gui/popup_menu.cpp82
-rw-r--r--scene/gui/popup_menu.h1
-rw-r--r--scene/gui/progress_bar.cpp8
-rw-r--r--scene/gui/rich_text_label.cpp61
-rw-r--r--scene/gui/rich_text_label.h12
-rw-r--r--scene/gui/tab_container.cpp5
-rw-r--r--scene/gui/tabs.cpp15
-rw-r--r--scene/gui/text_edit.cpp95
-rw-r--r--scene/gui/text_edit.h6
-rw-r--r--scene/gui/tree.cpp42
-rw-r--r--scene/gui/tree.h2
-rw-r--r--scene/main/node.cpp57
-rw-r--r--scene/main/node.h3
-rw-r--r--scene/main/viewport.cpp5
-rw-r--r--scene/resources/animation.cpp4
-rw-r--r--scene/resources/animation.h2
-rw-r--r--scene/resources/default_theme/default_theme.cpp56
-rw-r--r--scene/resources/font.cpp55
-rw-r--r--scene/resources/font.h21
-rw-r--r--scene/resources/material.h2
-rw-r--r--scene/resources/mesh.cpp9
-rw-r--r--scene/resources/mesh.h2
-rw-r--r--scene/resources/mesh_library.cpp3
-rw-r--r--scene/resources/mesh_library.h1
-rw-r--r--scene/resources/packed_scene.cpp3
-rw-r--r--scene/resources/packed_scene.h1
-rw-r--r--scene/resources/resource_format_text.cpp127
-rw-r--r--scene/resources/resource_format_text.h4
-rw-r--r--scene/resources/shader.cpp2
-rw-r--r--scene/resources/shader.h2
-rw-r--r--scene/resources/skin.cpp4
-rw-r--r--scene/resources/skin.h1
-rw-r--r--scene/resources/style_box.cpp13
-rw-r--r--scene/resources/text_line.cpp1
-rw-r--r--scene/resources/text_paragraph.cpp2
-rw-r--r--scene/resources/texture.cpp6
-rw-r--r--scene/resources/texture.h6
-rw-r--r--scene/resources/theme.cpp3
-rw-r--r--scene/resources/theme.h2
-rw-r--r--scene/resources/tile_set.cpp4
-rw-r--r--scene/resources/tile_set.h2
-rw-r--r--scene/resources/visual_shader.cpp9
-rw-r--r--scene/resources/visual_shader.h2
58 files changed, 699 insertions, 163 deletions
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index 4e7eec906c..d6f35cc99d 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -342,6 +342,9 @@ bool AudioStreamPlayer2D::is_playing() const {
float AudioStreamPlayer2D::get_playback_position() {
if (stream_playback.is_valid()) {
+ if (setseek >= 0.0) {
+ return setseek;
+ }
return stream_playback->get_playback_position();
}
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index d420bd6075..65d0703139 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -714,6 +714,9 @@ bool AudioStreamPlayer3D::is_playing() const {
float AudioStreamPlayer3D::get_playback_position() {
if (stream_playback.is_valid()) {
+ if (setseek >= 0.0) {
+ return setseek;
+ }
return stream_playback->get_playback_position();
}
diff --git a/scene/3d/collision_polygon_3d.cpp b/scene/3d/collision_polygon_3d.cpp
index 4d117f02d3..e3e2eb4669 100644
--- a/scene/3d/collision_polygon_3d.cpp
+++ b/scene/3d/collision_polygon_3d.cpp
@@ -70,6 +70,7 @@ void CollisionPolygon3D::_build_polygon() {
}
convex->set_points(cp);
+ convex->set_margin(margin);
parent->shape_owner_add_shape(owner_id, convex);
parent->shape_owner_set_disabled(owner_id, disabled);
}
@@ -155,6 +156,17 @@ bool CollisionPolygon3D::is_disabled() const {
return disabled;
}
+real_t CollisionPolygon3D::get_margin() const {
+ return margin;
+}
+
+void CollisionPolygon3D::set_margin(real_t p_margin) {
+ margin = p_margin;
+ if (parent) {
+ _build_polygon();
+ }
+}
+
String CollisionPolygon3D::get_configuration_warning() const {
String warning = Node3D::get_configuration_warning();
@@ -189,11 +201,15 @@ void CollisionPolygon3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &CollisionPolygon3D::set_disabled);
ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionPolygon3D::is_disabled);
+ ClassDB::bind_method(D_METHOD("set_margin", "margin"), &CollisionPolygon3D::set_margin);
+ ClassDB::bind_method(D_METHOD("get_margin"), &CollisionPolygon3D::get_margin);
+
ClassDB::bind_method(D_METHOD("_is_editable_3d_polygon"), &CollisionPolygon3D::_is_editable_3d_polygon);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth"), "set_depth", "get_depth");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0.001,10,0.001"), "set_margin", "get_margin");
}
CollisionPolygon3D::CollisionPolygon3D() {
diff --git a/scene/3d/collision_polygon_3d.h b/scene/3d/collision_polygon_3d.h
index cb0aba67b1..750751b509 100644
--- a/scene/3d/collision_polygon_3d.h
+++ b/scene/3d/collision_polygon_3d.h
@@ -37,6 +37,7 @@
class CollisionObject3D;
class CollisionPolygon3D : public Node3D {
GDCLASS(CollisionPolygon3D, Node3D);
+ real_t margin = 0.04;
protected:
real_t depth = 1.0;
@@ -70,6 +71,9 @@ public:
virtual AABB get_item_rect() const;
+ real_t get_margin() const;
+ void set_margin(real_t p_margin);
+
String get_configuration_warning() const override;
CollisionPolygon3D();
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
index 3b1fb830e3..4575716f7a 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -747,8 +747,8 @@ void Node3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("orthonormalize"), &Node3D::orthonormalize);
ClassDB::bind_method(D_METHOD("set_identity"), &Node3D::set_identity);
- ClassDB::bind_method(D_METHOD("look_at", "target", "up"), &Node3D::look_at);
- ClassDB::bind_method(D_METHOD("look_at_from_position", "position", "target", "up"), &Node3D::look_at_from_position);
+ ClassDB::bind_method(D_METHOD("look_at", "target", "up"), &Node3D::look_at, DEFVAL(Vector3(0, 1, 0)));
+ ClassDB::bind_method(D_METHOD("look_at_from_position", "position", "target", "up"), &Node3D::look_at_from_position, DEFVAL(Vector3(0, 1, 0)));
ClassDB::bind_method(D_METHOD("to_local", "global_point"), &Node3D::to_local);
ClassDB::bind_method(D_METHOD("to_global", "local_point"), &Node3D::to_global);
diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h
index 8610e2c0bd..a62c7b31a8 100644
--- a/scene/3d/node_3d.h
+++ b/scene/3d/node_3d.h
@@ -173,8 +173,8 @@ public:
void global_scale(const Vector3 &p_scale);
void global_translate(const Vector3 &p_offset);
- void look_at(const Vector3 &p_target, const Vector3 &p_up);
- void look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up);
+ void look_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0));
+ void look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0));
Vector3 to_local(Vector3 p_global) const;
Vector3 to_global(Vector3 p_local) const;
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index fb16f95379..79a1dc1ac0 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -1121,6 +1121,13 @@ void AnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) cons
p_list->push_back(PropertyInfo(Variant::ARRAY, "node_connections", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
}
+void AnimationNodeBlendTree::reset_state() {
+ graph_offset = Vector2();
+ nodes.clear();
+ emit_changed();
+ emit_signal("tree_changed");
+}
+
void AnimationNodeBlendTree::_tree_changed() {
emit_signal("tree_changed");
}
diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h
index 4732f43af2..d82658c8c2 100644
--- a/scene/animation/animation_blend_tree.h
+++ b/scene/animation/animation_blend_tree.h
@@ -351,6 +351,8 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ virtual void reset_state() override;
+
public:
enum ConnectionError {
CONNECTION_OK,
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index 4f69b05afe..71de3635f9 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -914,6 +914,18 @@ void AnimationNodeStateMachine::_get_property_list(List<PropertyInfo> *p_list) c
p_list->push_back(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
}
+void AnimationNodeStateMachine::reset_state() {
+ states.clear();
+ transitions.clear();
+ playback = "playback";
+ start_node = StringName();
+ end_node = StringName();
+ graph_offset = Vector2();
+
+ emit_changed();
+ emit_signal("tree_changed");
+}
+
void AnimationNodeStateMachine::set_node_position(const StringName &p_name, const Vector2 &p_position) {
ERR_FAIL_COND(!states.has(p_name));
states[p_name].position = p_position;
diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h
index 7abc6388a1..9c1bca63c3 100644
--- a/scene/animation/animation_node_state_machine.h
+++ b/scene/animation/animation_node_state_machine.h
@@ -171,6 +171,8 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ virtual void reset_state() override;
+
public:
virtual void get_parameter_list(List<PropertyInfo> *r_list) const override;
virtual Variant get_parameter_default_value(const StringName &p_parameter) const override;
diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp
index 4f77734b79..ec0a4b8696 100644
--- a/scene/audio/audio_stream_player.cpp
+++ b/scene/audio/audio_stream_player.cpp
@@ -267,6 +267,9 @@ bool AudioStreamPlayer::is_playing() const {
float AudioStreamPlayer::get_playback_position() {
if (stream_playback.is_valid()) {
+ if (setseek >= 0.0) {
+ return setseek;
+ }
return stream_playback->get_playback_position();
}
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index d76284e333..7afc04c51c 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -883,6 +883,8 @@ void ItemList::_notification(int p_what) {
int vseparation = get_theme_constant("vseparation");
int icon_margin = get_theme_constant("icon_margin");
int line_separation = get_theme_constant("line_separation");
+ Color font_outline_color = get_theme_color("font_outline_color");
+ int outline_size = get_theme_constant("outline_size");
Ref<StyleBox> sbsel = has_focus() ? get_theme_stylebox("selected_focus") : get_theme_stylebox("selected");
Ref<StyleBox> cursor = has_focus() ? get_theme_stylebox("cursor") : get_theme_stylebox("cursor_unfocused");
@@ -1204,6 +1206,10 @@ void ItemList::_notification(int p_what) {
items.write[i].text_buf->set_width(max_len);
items.write[i].text_buf->set_align(HALIGN_CENTER);
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ items[i].text_buf->draw_outline(get_canvas_item(), text_ofs, outline_size, font_outline_color);
+ }
+
items[i].text_buf->draw(get_canvas_item(), text_ofs, modulate);
} else {
if (fixed_column_width > 0) {
@@ -1230,6 +1236,11 @@ void ItemList::_notification(int p_what) {
} else {
items.write[i].text_buf->set_align(HALIGN_LEFT);
}
+
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ items[i].text_buf->draw_outline(get_canvas_item(), text_ofs, outline_size, font_outline_color);
+ }
+
items[i].text_buf->draw(get_canvas_item(), text_ofs, modulate);
}
}
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index 453ecc802c..2997a6ebe9 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -357,21 +357,25 @@ void Label::_notification(int p_what) {
}
Size2 Label::get_minimum_size() const {
- Size2 min_style = get_theme_stylebox("normal")->get_minimum_size();
-
// don't want to mutable everything
if (dirty || lines_dirty) {
const_cast<Label *>(this)->_shape();
}
+ Size2 min_size = minsize;
+
+ Ref<Font> font = get_theme_font("font");
+ min_size.height = MAX(min_size.height, font->get_height(get_theme_font_size("font_size")) + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM));
+
+ Size2 min_style = get_theme_stylebox("normal")->get_minimum_size();
if (autowrap) {
- return Size2(1, clip ? 1 : minsize.height) + min_style;
+ return Size2(1, clip ? 1 : min_size.height) + min_style;
} else {
- Size2 ms = minsize;
if (clip) {
- ms.width = 1;
+ min_size.width = 1;
}
- return ms + min_style;
+
+ return min_size + min_style;
}
}
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index bbe09af3aa..5bd9259a64 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -835,6 +835,24 @@ void LineEdit::_notification(int p_what) {
// Draw text.
ofs.y += TS->shaped_text_get_ascent(text_rid);
+ Color font_outline_color = get_theme_color("font_outline_color");
+ int outline_size = get_theme_constant("outline_size");
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ Vector2 oofs = ofs;
+ for (int i = 0; i < gl_size; i++) {
+ for (int j = 0; j < glyphs[i].repeat; j++) {
+ if (ceil(oofs.x) >= x_ofs && (oofs.x + glyphs[i].advance) <= ofs_max) {
+ if (glyphs[i].font_rid != RID()) {
+ TS->font_draw_glyph_outline(glyphs[i].font_rid, ci, glyphs[i].font_size, outline_size, oofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, font_outline_color);
+ }
+ }
+ oofs.x += glyphs[i].advance;
+ }
+ if (oofs.x >= ofs_max) {
+ break;
+ }
+ }
+ }
for (int i = 0; i < gl_size; i++) {
bool selected = selection.enabled && glyphs[i].start >= selection.begin && glyphs[i].end <= selection.end;
for (int j = 0; j < glyphs[i].repeat; j++) {
@@ -1568,12 +1586,12 @@ Size2 LineEdit::get_minimum_size() const {
Size2 min_size;
// Minimum size of text.
- int space_size = font->get_char_size('m', 0, font_size).x;
- min_size.width = get_theme_constant("minimum_spaces") * space_size;
+ int em_space_size = font->get_char_size('M', 0, font_size).x;
+ min_size.width = get_theme_constant("minimum_character_width") * em_space_size;
if (expand_to_text_length) {
// Add a space because some fonts are too exact, and because cursor needs a bit more when at the end.
- min_size.width = MAX(min_size.width, full_width + space_size);
+ min_size.width = MAX(min_size.width, full_width + em_space_size);
}
min_size.height = MAX(TS->shaped_text_get_size(text_rid).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM), font->get_height(font_size));
diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp
index c6706aba68..1f7b61e3d1 100644
--- a/scene/gui/link_button.cpp
+++ b/scene/gui/link_button.cpp
@@ -191,9 +191,17 @@ void LinkButton::_notification(int p_what) {
int width = text_buf->get_line_width();
+ Color font_outline_color = get_theme_color("font_outline_color");
+ int outline_size = get_theme_constant("outline_size");
if (is_layout_rtl()) {
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ text_buf->draw_outline(get_canvas_item(), Vector2(size.width - width, 0), outline_size, font_outline_color);
+ }
text_buf->draw(get_canvas_item(), Vector2(size.width - width, 0), color);
} else {
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ text_buf->draw_outline(get_canvas_item(), Vector2(0, 0), outline_size, font_outline_color);
+ }
text_buf->draw(get_canvas_item(), Vector2(0, 0), color);
}
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 835f4c432f..f237f79be1 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -62,7 +62,7 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
Size2 size;
Size2 icon_size = items[i].get_icon_size();
- size.height = MAX(icon_size.height, items[i].text_buf->get_size().y);
+ size.height = _get_item_height(i);
icon_w = MAX(icon_size.width, icon_w);
size.width += items[i].h_ofs;
@@ -89,7 +89,9 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
minsize.height += size.height;
}
- minsize.width += max_w + icon_w + accel_max_w;
+ int item_side_padding = get_theme_constant("item_start_padding") + get_theme_constant("item_end_padding");
+ minsize.width += max_w + icon_w + accel_max_w + item_side_padding;
+
if (has_check) {
minsize.width += check_w;
}
@@ -104,13 +106,35 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
return minsize;
}
+int PopupMenu::_get_item_height(int p_item) const {
+ ERR_FAIL_INDEX_V(p_item, items.size(), 0);
+ ERR_FAIL_COND_V(p_item < 0, 0);
+
+ int icon_height = items[p_item].get_icon_size().height;
+ if (items[p_item].checkable_type) {
+ icon_height = MAX(icon_height, MAX(get_theme_icon("checked")->get_height(), get_theme_icon("radio_checked")->get_height()));
+ }
+
+ int text_height = items[p_item].text_buf->get_size().height;
+ if (text_height == 0 && !items[p_item].separator) {
+ text_height = get_theme_font("font")->get_height(get_theme_font_size("font_size"));
+ }
+
+ int separator_height = 0;
+ if (items[p_item].separator) {
+ separator_height = MAX(get_theme_stylebox("separator")->get_minimum_size().height, MAX(get_theme_stylebox("labeled_separator_left")->get_minimum_size().height, get_theme_stylebox("labeled_separator_right")->get_minimum_size().height));
+ }
+
+ return MAX(separator_height, MAX(text_height, icon_height));
+}
+
int PopupMenu::_get_items_total_height() const {
int vsep = get_theme_constant("vseparation");
// Get total height of all items by taking max of icon height and font height
int items_total_height = 0;
for (int i = 0; i < items.size(); i++) {
- items_total_height += MAX(items[i].get_icon_size().height, items[i].text_buf->get_size().y) + vsep;
+ items_total_height += _get_item_height(i) + vsep;
}
// Subtract a separator which is not needed for the last item.
@@ -152,7 +176,7 @@ int PopupMenu::_get_mouse_over(const Point2 &p_over) const {
for (int i = 0; i < items.size(); i++) {
ofs.y += i > 0 ? vseparation : (float)vseparation / 2;
- ofs.y += MAX(items[i].get_icon_size().height, items[i].text_buf->get_size().y);
+ ofs.y += _get_item_height(i);
if (p_over.y - control->get_position().y < ofs.y) {
return i;
@@ -451,6 +475,10 @@ void PopupMenu::_draw_items() {
margin_size.width = margin_container->get_theme_constant("margin_right") + margin_container->get_theme_constant("margin_left");
margin_size.height = margin_container->get_theme_constant("margin_top") + margin_container->get_theme_constant("margin_bottom");
+ // Space between the item content and the sides of popup menu.
+ int item_start_padding = get_theme_constant("item_start_padding");
+ int item_end_padding = get_theme_constant("item_end_padding");
+
bool rtl = control->is_layout_rtl();
Ref<StyleBox> style = get_theme_stylebox("panel");
Ref<StyleBox> hover = get_theme_stylebox("hover");
@@ -509,7 +537,7 @@ void PopupMenu::_draw_items() {
Point2 item_ofs = ofs;
Size2 icon_size = items[i].get_icon_size();
- float h = MAX(icon_size.height, items[i].text_buf->get_size().y);
+ float h = _get_item_height(i);
if (i == mouse_over) {
if (rtl) {
@@ -525,24 +553,28 @@ void PopupMenu::_draw_items() {
item_ofs.x += items[i].h_ofs;
if (items[i].separator) {
int sep_h = separator->get_center_size().height + separator->get_minimum_size().height;
+ int sep_ofs = Math::floor((h - sep_h) / 2.0);
if (text != String()) {
int text_size = items[i].text_buf->get_size().width;
int text_center = display_width / 2;
int text_left = text_center - text_size / 2;
int text_right = text_center + text_size / 2;
if (text_left > item_ofs.x) {
- labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, text_left - item_ofs.x), sep_h)));
+ labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, sep_ofs), Size2(MAX(0, text_left - item_ofs.x), sep_h)));
}
if (text_right < display_width) {
- labeled_separator_right->draw(ci, Rect2(Point2(text_right, item_ofs.y + Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, display_width - text_right), sep_h)));
+ labeled_separator_right->draw(ci, Rect2(Point2(text_right, item_ofs.y + sep_ofs), Size2(MAX(0, display_width - text_right), sep_h)));
}
} else {
- separator->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(display_width, sep_h)));
+ separator->draw(ci, Rect2(item_ofs + Point2(0, sep_ofs), Size2(display_width, sep_h)));
}
}
Color icon_color(1, 1, 1, items[i].disabled ? 0.5 : 1);
+ // For non-separator items, add some padding for the content.
+ item_ofs.x += item_start_padding;
+
// Checkboxes
if (items[i].checkable_type) {
Texture2D *icon = (items[i].checked ? check[items[i].checkable_type - 1] : uncheck[items[i].checkable_type - 1]).ptr();
@@ -565,35 +597,53 @@ void PopupMenu::_draw_items() {
// Submenu arrow on right hand side
if (items[i].submenu != "") {
if (rtl) {
- submenu->draw(ci, Point2(scroll_width + style->get_margin(SIDE_LEFT), item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
+ submenu->draw(ci, Point2(scroll_width + style->get_margin(SIDE_LEFT) + item_end_padding, item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
} else {
- submenu->draw(ci, Point2(display_width - style->get_margin(SIDE_RIGHT) - submenu->get_width(), item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
+ submenu->draw(ci, Point2(display_width - style->get_margin(SIDE_RIGHT) - submenu->get_width() - item_end_padding, item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
}
}
// Text
+ Color font_outline_color = get_theme_color("font_outline_color");
+ int outline_size = get_theme_constant("outline_size");
if (items[i].separator) {
if (text != String()) {
int center = (display_width - items[i].text_buf->get_size().width) / 2;
- items[i].text_buf->draw(ci, Point2(center, item_ofs.y + Math::floor((h - items[i].text_buf->get_size().y) / 2.0)), font_separator_color);
+ Vector2 text_pos = Point2(center, item_ofs.y + Math::floor((h - items[i].text_buf->get_size().y) / 2.0));
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ items[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color);
+ }
+ items[i].text_buf->draw(ci, text_pos, font_separator_color);
}
} else {
item_ofs.x += icon_ofs + check_ofs;
if (rtl) {
- items[i].text_buf->draw(ci, Size2(control->get_size().width - items[i].text_buf->get_size().width - item_ofs.x, item_ofs.y) + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0)), items[i].disabled ? font_disabled_color : (i == mouse_over ? font_hover_color : font_color));
+ Vector2 text_pos = Size2(control->get_size().width - items[i].text_buf->get_size().width - item_ofs.x, item_ofs.y) + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0));
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ items[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color);
+ }
+ items[i].text_buf->draw(ci, text_pos, items[i].disabled ? font_disabled_color : (i == mouse_over ? font_hover_color : font_color));
} else {
- items[i].text_buf->draw(ci, item_ofs + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0)), items[i].disabled ? font_disabled_color : (i == mouse_over ? font_hover_color : font_color));
+ Vector2 text_pos = item_ofs + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0));
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ items[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color);
+ }
+ items[i].text_buf->draw(ci, text_pos, items[i].disabled ? font_disabled_color : (i == mouse_over ? font_hover_color : font_color));
}
}
// Accelerator / Shortcut
if (items[i].accel || (items[i].shortcut.is_valid() && items[i].shortcut->is_valid())) {
if (rtl) {
- item_ofs.x = scroll_width + style->get_margin(SIDE_LEFT);
+ item_ofs.x = scroll_width + style->get_margin(SIDE_LEFT) + item_end_padding;
} else {
- item_ofs.x = display_width - style->get_margin(SIDE_RIGHT) - items[i].accel_text_buf->get_size().x;
+ item_ofs.x = display_width - style->get_margin(SIDE_RIGHT) - items[i].accel_text_buf->get_size().x - item_end_padding;
+ }
+ Vector2 text_pos = item_ofs + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0));
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ items[i].accel_text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color);
}
- items[i].accel_text_buf->draw(ci, item_ofs + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0)), i == mouse_over ? font_hover_color : font_accelerator_color);
+ items[i].accel_text_buf->draw(ci, text_pos, i == mouse_over ? font_hover_color : font_accelerator_color);
}
// Cache the item vertical offset from the first item and the height
diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h
index 184be42e95..e4cbe984c9 100644
--- a/scene/gui/popup_menu.h
+++ b/scene/gui/popup_menu.h
@@ -101,6 +101,7 @@ class PopupMenu : public Popup {
int _get_mouse_over(const Point2 &p_over) const;
virtual Size2 _get_contents_minimum_size() const override;
+ int _get_item_height(int p_item) const;
int _get_items_total_height() const;
void _scroll_to_item(int p_item);
diff --git a/scene/gui/progress_bar.cpp b/scene/gui/progress_bar.cpp
index 63174b2d7f..6e8dfd5994 100644
--- a/scene/gui/progress_bar.cpp
+++ b/scene/gui/progress_bar.cpp
@@ -74,7 +74,13 @@ void ProgressBar::_notification(int p_what) {
if (percent_visible) {
String txt = TS->format_number(itos(int(get_as_ratio() * 100))) + TS->percent_sign();
TextLine tl = TextLine(txt, font, font_size);
- tl.draw(get_canvas_item(), (Point2(get_size().width - tl.get_size().x, get_size().height - tl.get_size().y) / 2).round(), font_color);
+ Vector2 text_pos = (Point2(get_size().width - tl.get_size().x, get_size().height - tl.get_size().y) / 2).round();
+ Color font_outline_color = get_theme_color("font_outline_color");
+ int outline_size = get_theme_constant("outline_size");
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ tl.draw_outline(get_canvas_item(), text_pos, outline_size, font_outline_color);
+ }
+ tl.draw(get_canvas_item(), text_pos, font_color);
}
}
}
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index f9f8f4f78a..6a1cc291a6 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -45,7 +45,7 @@
#include "editor/editor_scale.h"
#endif
-RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) {
+RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) const {
if (p_free) {
if (p_item->subitems.size()) {
return p_item->subitems.front()->get();
@@ -90,7 +90,7 @@ RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) {
return nullptr;
}
-RichTextLabel::Item *RichTextLabel::_get_prev_item(Item *p_item, bool p_free) {
+RichTextLabel::Item *RichTextLabel::_get_prev_item(Item *p_item, bool p_free) const {
if (p_free) {
if (p_item->subitems.size()) {
return p_item->subitems.back()->get();
@@ -147,7 +147,7 @@ RichTextLabel::Item *RichTextLabel::_get_item_at_pos(RichTextLabel::Item *p_item
case ITEM_TEXT: {
ItemText *t = (ItemText *)it;
offset += t->text.length();
- if (offset > p_position) {
+ if (offset >= p_position) {
return it;
}
} break;
@@ -220,7 +220,7 @@ void RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font>
if (tab_size > 0) { // Align inline tabs.
Vector<float> tabs;
- tabs.push_back(tab_size * p_base_font->get_char_size('m', 0, p_base_font_size).width);
+ tabs.push_back(tab_size * p_base_font->get_char_size(' ', 0, p_base_font_size).width);
l.text_buf->tab_align(tabs);
}
@@ -392,7 +392,7 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
if (tab_size > 0) { // Align inline tabs.
Vector<float> tabs;
- tabs.push_back(tab_size * p_base_font->get_char_size('m', 0, p_base_font_size).width);
+ tabs.push_back(tab_size * p_base_font->get_char_size(' ', 0, p_base_font_size).width);
l.text_buf->tab_align(tabs);
}
@@ -454,6 +454,7 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
ItemImage *img = (ItemImage *)it;
l.text_buf->add_object((uint64_t)it, img->image->get_size(), img->inline_align, 1);
text += String::chr(0xfffc);
+ l.char_count += 1;
} break;
case ITEM_TABLE: {
ItemTable *table = static_cast<ItemTable *>(it);
@@ -776,6 +777,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
Color odd_row_bg = get_theme_color("table_odd_row_bg");
Color even_row_bg = get_theme_color("table_even_row_bg");
Color border = get_theme_color("table_border");
+ int hseparation = get_theme_constant("table_hseparation");
int col_count = table->columns.size();
int row_count = table->rows.size();
@@ -792,11 +794,11 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
coff.x = rect.size.width - table->columns[col].width - coff.x;
}
if (row % 2 == 0) {
- draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width, table->rows[row])), (frame->odd_row_bg != Color(0, 0, 0, 0) ? frame->odd_row_bg : odd_row_bg), true);
+ draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width + hseparation + frame->padding.position.x + frame->padding.size.x, table->rows[row])), (frame->odd_row_bg != Color(0, 0, 0, 0) ? frame->odd_row_bg : odd_row_bg), true);
} else {
- draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width, table->rows[row])), (frame->even_row_bg != Color(0, 0, 0, 0) ? frame->even_row_bg : even_row_bg), true);
+ draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width + hseparation + frame->padding.position.x + frame->padding.size.x, table->rows[row])), (frame->even_row_bg != Color(0, 0, 0, 0) ? frame->even_row_bg : even_row_bg), true);
}
- draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width, table->rows[row])), (frame->border != Color(0, 0, 0, 0) ? frame->border : border), false);
+ draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width + hseparation + frame->padding.position.x + frame->padding.size.x, table->rows[row])), (frame->border != Color(0, 0, 0, 0) ? frame->border : border), false);
}
for (int j = 0; j < frame->lines.size(); j++) {
@@ -819,8 +821,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
// Draw oulines and shadow.
for (int i = 0; i < gl_size; i++) {
Item *it = _get_item_at_pos(it_from, it_to, glyphs[i].start);
- int size = _find_outline_size(it);
- Color font_color = _find_outline_color(it, Color(0, 0, 0, 0));
+ int size = _find_outline_size(it, p_outline_size);
+ Color font_color = _find_outline_color(it, p_outline_color);
if (size <= 0) {
gloff.x += glyphs[i].advance;
continue;
@@ -1398,7 +1400,7 @@ void RichTextLabel::_notification(int p_what) {
}
Ref<Font> base_font = get_theme_font("normal_font");
Color base_color = get_theme_color("default_color");
- Color outline_color = get_theme_color("outline_color");
+ Color outline_color = get_theme_color("font_outline_color");
int outline_size = get_theme_constant("outline_size");
Color font_shadow_color = get_theme_color("font_shadow_color");
bool use_outline = get_theme_constant("shadow_as_outline");
@@ -1753,7 +1755,7 @@ int RichTextLabel::_find_font_size(Item *p_item) {
return -1;
}
-int RichTextLabel::_find_outline_size(Item *p_item) {
+int RichTextLabel::_find_outline_size(Item *p_item, int p_default) {
Item *sizeitem = p_item;
while (sizeitem) {
@@ -1765,7 +1767,7 @@ int RichTextLabel::_find_outline_size(Item *p_item) {
sizeitem = sizeitem->parent;
}
- return 0;
+ return p_default;
}
Dictionary RichTextLabel::_find_font_features(Item *p_item) {
@@ -1859,7 +1861,7 @@ int RichTextLabel::_find_margin(Item *p_item, const Ref<Font> &p_base_font, int
if (font_size == -1) {
font_size = p_base_font_size;
}
- margin += tab_size * font->get_char_size('m', 0, font_size).width;
+ margin += tab_size * font->get_char_size(' ', 0, font_size).width;
} else if (item->type == ITEM_LIST) {
Ref<Font> font = _find_font(item);
@@ -1870,7 +1872,7 @@ int RichTextLabel::_find_margin(Item *p_item, const Ref<Font> &p_base_font, int
if (font_size == -1) {
font_size = p_base_font_size;
}
- margin += tab_size * font->get_char_size('m', 0, font_size).width;
+ margin += tab_size * font->get_char_size(' ', 0, font_size).width;
}
item = item->parent;
@@ -2252,6 +2254,8 @@ void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width,
}
ERR_FAIL_COND(p_image.is_null());
+ ERR_FAIL_COND(p_image->get_width() == 0);
+ ERR_FAIL_COND(p_image->get_height() == 0);
ItemImage *item = memnew(ItemImage);
item->image = p_image;
@@ -3520,7 +3524,7 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p
return false;
}
-String RichTextLabel::_get_line_text(ItemFrame *p_frame, int p_line, Selection p_selection) {
+String RichTextLabel::_get_line_text(ItemFrame *p_frame, int p_line, Selection p_selection) const {
String text;
ERR_FAIL_COND_V(p_frame == nullptr, text);
ERR_FAIL_COND_V(p_line < 0 || p_line >= p_frame->lines.size(), text);
@@ -3587,7 +3591,7 @@ String RichTextLabel::_get_line_text(ItemFrame *p_frame, int p_line, Selection p
return text;
}
-String RichTextLabel::get_selected_text() {
+String RichTextLabel::get_selected_text() const {
if (!selection.active || !selection.enabled) {
return "";
}
@@ -3611,6 +3615,22 @@ bool RichTextLabel::is_selection_enabled() const {
return selection.enabled;
}
+int RichTextLabel::get_selection_from() const {
+ if (!selection.active || !selection.enabled) {
+ return -1;
+ }
+
+ return selection.from_frame->lines[selection.from_line].char_offset + selection.from_char;
+}
+
+int RichTextLabel::get_selection_to() const {
+ if (!selection.active || !selection.enabled) {
+ return -1;
+ }
+
+ return selection.to_frame->lines[selection.to_line].char_offset + selection.to_char - 1;
+}
+
void RichTextLabel::set_bbcode(const String &p_bbcode) {
bbcode = p_bbcode;
if (is_inside_tree() && use_bbcode) {
@@ -3646,6 +3666,8 @@ String RichTextLabel::get_text() {
text += t->text;
} else if (it->type == ITEM_NEWLINE) {
text += "\n";
+ } else if (it->type == ITEM_IMAGE) {
+ text += " ";
} else if (it->type == ITEM_INDENT || it->type == ITEM_LIST) {
text += "\t";
}
@@ -3838,6 +3860,11 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_selection_enabled", "enabled"), &RichTextLabel::set_selection_enabled);
ClassDB::bind_method(D_METHOD("is_selection_enabled"), &RichTextLabel::is_selection_enabled);
+ ClassDB::bind_method(D_METHOD("get_selection_from"), &RichTextLabel::get_selection_from);
+ ClassDB::bind_method(D_METHOD("get_selection_to"), &RichTextLabel::get_selection_to);
+
+ ClassDB::bind_method(D_METHOD("get_selected_text"), &RichTextLabel::get_selected_text);
+
ClassDB::bind_method(D_METHOD("parse_bbcode", "bbcode"), &RichTextLabel::parse_bbcode);
ClassDB::bind_method(D_METHOD("append_bbcode", "bbcode"), &RichTextLabel::append_bbcode);
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index 84936221d5..2351aff0a4 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -389,7 +389,7 @@ private:
void _find_click(ItemFrame *p_frame, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool *r_outside = nullptr);
- String _get_line_text(ItemFrame *p_frame, int p_line, Selection p_sel);
+ String _get_line_text(ItemFrame *p_frame, int p_line, Selection p_sel) const;
bool _search_line(ItemFrame *p_frame, int p_line, const String &p_string, Item *p_from, Item *p_to);
void _shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width, int *r_char_offset);
@@ -405,7 +405,7 @@ private:
Ref<Font> _find_font(Item *p_item);
int _find_font_size(Item *p_item);
Dictionary _find_font_features(Item *p_item);
- int _find_outline_size(Item *p_item);
+ int _find_outline_size(Item *p_item, int p_default);
ItemList *_find_list_item(Item *p_item);
ItemDropcap *_find_dc_item(Item *p_item);
int _find_list(Item *p_item, Vector<int> &r_index, Vector<ItemList *> &r_list);
@@ -427,8 +427,8 @@ private:
void _scroll_changed(double);
void _gui_input(Ref<InputEvent> p_event);
- Item *_get_next_item(Item *p_item, bool p_free = false);
- Item *_get_prev_item(Item *p_item, bool p_free = false);
+ Item *_get_next_item(Item *p_item, bool p_free = false) const;
+ Item *_get_prev_item(Item *p_item, bool p_free = false) const;
Rect2 _get_text_rect();
Ref<RichTextEffect> _get_custom_effect_by_code(String p_bbcode_identifier);
@@ -524,7 +524,9 @@ public:
void set_selection_enabled(bool p_enabled);
bool is_selection_enabled() const;
- String get_selected_text();
+ int get_selection_from() const;
+ int get_selection_to() const;
+ String get_selected_text() const;
void selection_copy();
Error parse_bbcode(const String &p_bbcode);
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 861f66628d..e3e3f549de 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -535,6 +535,8 @@ void TabContainer::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, in
Vector<Control *> tabs = _get_tabs();
RID canvas = get_canvas_item();
Ref<Font> font = get_theme_font("font");
+ Color font_outline_color = get_theme_color("font_outline_color");
+ int outline_size = get_theme_constant("outline_size");
int icon_text_distance = get_theme_constant("icon_separation");
int tab_width = _get_tab_width(p_index);
int header_height = _get_top_margin();
@@ -565,6 +567,9 @@ void TabContainer::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, in
// Draw the tab text.
Point2i text_pos(x_content, y_center - text_buf[p_index]->get_size().y / 2);
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ text_buf[p_index]->draw_outline(canvas, text_pos, outline_size, font_outline_color);
+ }
text_buf[p_index]->draw(canvas, text_pos, p_font_color);
}
diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp
index 66f04e5569..da1a9698d0 100644
--- a/scene/gui/tabs.cpp
+++ b/scene/gui/tabs.cpp
@@ -275,6 +275,9 @@ void Tabs::_notification(int p_what) {
Color font_unselected_color = get_theme_color("font_unselected_color");
Color font_disabled_color = get_theme_color("font_disabled_color");
Ref<Texture2D> close = get_theme_icon("close");
+ Color font_outline_color = get_theme_color("font_outline_color");
+ int outline_size = get_theme_constant("outline_size");
+
Vector2 size = get_size();
bool rtl = is_layout_rtl();
@@ -357,9 +360,17 @@ void Tabs::_notification(int p_what) {
}
if (rtl) {
- tabs[i].text_buf->draw(ci, Point2i(size.width - w - tabs[i].text_buf->get_size().x, sb->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - tabs[i].text_buf->get_size().y) / 2), col);
+ Vector2 text_pos = Point2i(size.width - w - tabs[i].text_buf->get_size().x, sb->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - tabs[i].text_buf->get_size().y) / 2);
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ tabs[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color);
+ }
+ tabs[i].text_buf->draw(ci, text_pos, col);
} else {
- tabs[i].text_buf->draw(ci, Point2i(w, sb->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - tabs[i].text_buf->get_size().y) / 2), col);
+ Vector2 text_pos = Point2i(w, sb->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - tabs[i].text_buf->get_size().y) / 2);
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ tabs[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color);
+ }
+ tabs[i].text_buf->draw(ci, text_pos, col);
}
w += tabs[i].size_text;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index d31d00675e..880e66eb6a 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -202,7 +202,7 @@ void TextEdit::Text::invalidate_cache(int p_line, int p_column, const String &p_
// Apply tab align.
if (indent_size > 0) {
Vector<float> tabs;
- tabs.push_back(font->get_char_size('m', 0, font_size).width * indent_size);
+ tabs.push_back(font->get_char_size(' ', 0, font_size).width * indent_size);
text.write[p_line].data_buf->tab_align(tabs);
}
}
@@ -212,7 +212,7 @@ void TextEdit::Text::invalidate_all_lines() {
text.write[i].data_buf->set_width(width);
if (indent_size > 0) {
Vector<float> tabs;
- tabs.push_back(font->get_char_size('m', 0, font_size).width * indent_size);
+ tabs.push_back(font->get_char_size(' ', 0, font_size).width * indent_size);
text.write[i].data_buf->tab_align(tabs);
}
}
@@ -500,7 +500,7 @@ void TextEdit::_update_minimap_click() {
int row;
_get_minimap_mouse_row(Point2i(mp.x, mp.y), row);
- if (row >= get_first_visible_line() && (row < get_last_visible_line() || row >= (text.size() - 1))) {
+ if (row >= get_first_visible_line() && (row < get_last_full_visible_line() || row >= (text.size() - 1))) {
minimap_scroll_ratio = v_scroll->get_as_ratio();
minimap_scroll_click_pos = mp.y;
can_drag_minimap = true;
@@ -977,6 +977,16 @@ void TextEdit::_notification(int p_what) {
}
}
+ int top_limit_y = 0;
+ int bottom_limit_y = get_size().height;
+ if (readonly) {
+ top_limit_y += cache.style_readonly->get_margin(SIDE_TOP);
+ bottom_limit_y -= cache.style_readonly->get_margin(SIDE_BOTTOM);
+ } else {
+ top_limit_y += cache.style_normal->get_margin(SIDE_TOP);
+ bottom_limit_y -= cache.style_normal->get_margin(SIDE_BOTTOM);
+ }
+
// draw main text
int row_height = get_row_height();
int line = first_visible_line;
@@ -1019,17 +1029,33 @@ void TextEdit::_notification(int p_what) {
const String &str = wrap_rows[line_wrap_index];
int char_margin = xmargin_beg - cursor.x_ofs;
- int ofs_readonly = 0;
int ofs_x = 0;
+ int ofs_y = 0;
if (readonly) {
- ofs_readonly = cache.style_readonly->get_offset().y / 2;
ofs_x = cache.style_readonly->get_offset().x / 2;
+ ofs_x -= cache.style_normal->get_offset().x / 2;
+ ofs_y = cache.style_readonly->get_offset().y / 2;
+ } else {
+ ofs_y = cache.style_normal->get_offset().y / 2;
}
- int ofs_y = (i * row_height + cache.line_spacing / 2) + ofs_readonly;
+ ofs_y += i * row_height + cache.line_spacing / 2;
ofs_y -= cursor.wrap_ofs * row_height;
ofs_y -= get_v_scroll_offset() * row_height;
+ bool clipped = false;
+ if (ofs_y + row_height < top_limit_y) {
+ // Line is outside the top margin, clip current line.
+ // Still need to go through the process to prepare color changes for next lines.
+ clipped = true;
+ }
+
+ if (ofs_y > bottom_limit_y) {
+ // Line is outside the bottom margin, clip any remaining text.
+ i = draw_amount;
+ break;
+ }
+
if (text.is_marked(line)) {
if (rtl) {
RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - ofs_x - xmargin_end, ofs_y, xmargin_end - xmargin_beg, row_height), cache.mark_color);
@@ -1050,7 +1076,7 @@ void TextEdit::_notification(int p_what) {
// Give visual indication of empty selected line.
if (selection.active && line >= selection.from_line && line <= selection.to_line && char_margin >= xmargin_beg) {
- int char_w = cache.font->get_char_size('m', 0, cache.font_size).width;
+ int char_w = cache.font->get_char_size(' ', 0, cache.font_size).width;
if (rtl) {
RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - xmargin_beg - ofs_x - char_w, ofs_y, char_w, row_height), cache.selection_color);
} else {
@@ -1091,6 +1117,9 @@ void TextEdit::_notification(int p_what) {
tl->add_string(text, cache.font, cache.font_size);
int yofs = ofs_y + (row_height - tl->get_size().y) / 2;
+ if (cache.outline_size > 0 && cache.outline_color.a > 0) {
+ tl->draw_outline(ci, Point2(gutter_offset + ofs_x, yofs), cache.outline_size, cache.outline_color);
+ }
tl->draw(ci, Point2(gutter_offset + ofs_x, yofs), get_line_gutter_item_color(line, g));
} break;
case GUTTER_TPYE_ICON: {
@@ -1147,7 +1176,7 @@ void TextEdit::_notification(int p_what) {
char_margin = size.width - char_margin - TS->shaped_text_get_size(rid).x;
}
- if (selection.active && line >= selection.from_line && line <= selection.to_line) { // Selection
+ if (!clipped && selection.active && line >= selection.from_line && line <= selection.to_line) { // Selection
int sel_from = (line > selection.from_line) ? TS->shaped_text_get_range(rid).x : selection.from_column;
int sel_to = (line < selection.to_line) ? TS->shaped_text_get_range(rid).y : selection.to_column;
Vector<Vector2> sel = TS->shaped_text_get_selection(rid, sel_from, sel_to);
@@ -1167,7 +1196,7 @@ void TextEdit::_notification(int p_what) {
}
int start = TS->shaped_text_get_range(rid).x;
- if (!search_text.is_empty()) { // Search highhlight
+ if (!clipped && !search_text.is_empty()) { // Search highhlight
int search_text_col = _get_column_pos_of_word(search_text, str, search_flags, 0);
while (search_text_col != -1) {
Vector<Vector2> sel = TS->shaped_text_get_selection(rid, search_text_col + start, search_text_col + search_text.length() + start);
@@ -1190,7 +1219,7 @@ void TextEdit::_notification(int p_what) {
}
}
- if (highlight_all_occurrences && !only_whitespaces_highlighted && !highlighted_text.is_empty()) { // Highlight
+ if (!clipped && highlight_all_occurrences && !only_whitespaces_highlighted && !highlighted_text.is_empty()) { // Highlight
int highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, 0);
while (highlighted_text_col != -1) {
Vector<Vector2> sel = TS->shaped_text_get_selection(rid, highlighted_text_col + start, highlighted_text_col + highlighted_text.length() + start);
@@ -1212,7 +1241,7 @@ void TextEdit::_notification(int p_what) {
}
}
- if (select_identifiers_enabled && highlighted_word.length() != 0) { // Highlight word
+ if (!clipped && select_identifiers_enabled && highlighted_word.length() != 0) { // Highlight word
if (_is_char(highlighted_word[0]) || highlighted_word[0] == '.') {
int highlighted_word_col = _get_column_pos_of_word(highlighted_word, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, 0);
while (highlighted_word_col != -1) {
@@ -1247,6 +1276,22 @@ void TextEdit::_notification(int p_what) {
ofs_y += ldata->get_line_ascent(line_wrap_index);
int char_ofs = 0;
+ if (cache.outline_size > 0 && cache.outline_color.a > 0) {
+ for (int j = 0; j < gl_size; j++) {
+ for (int k = 0; k < glyphs[j].repeat; k++) {
+ if ((char_ofs + char_margin) >= xmargin_beg && (char_ofs + glyphs[j].advance + char_margin) <= xmargin_end) {
+ if (glyphs[j].font_rid != RID()) {
+ TS->font_draw_glyph_outline(glyphs[j].font_rid, ci, glyphs[j].font_size, cache.outline_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, cache.outline_color);
+ }
+ }
+ char_ofs += glyphs[j].advance;
+ }
+ if ((char_ofs + char_margin) >= xmargin_end) {
+ break;
+ }
+ }
+ char_ofs = 0;
+ }
for (int j = 0; j < gl_size; j++) {
if (color_map.has(glyphs[j].start)) {
current_color = color_map[glyphs[j].start].get("color");
@@ -1297,7 +1342,7 @@ void TextEdit::_notification(int p_what) {
}
for (int k = 0; k < glyphs[j].repeat; k++) {
- if ((char_ofs + char_margin) >= xmargin_beg && (char_ofs + glyphs[j].advance + char_margin) <= xmargin_end) {
+ if (!clipped && (char_ofs + char_margin) >= xmargin_beg && (char_ofs + glyphs[j].advance + char_margin) <= xmargin_end) {
if (glyphs[j].font_rid != RID()) {
TS->font_draw_glyph(glyphs[j].font_rid, ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, current_color);
} else if ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
@@ -1327,7 +1372,7 @@ void TextEdit::_notification(int p_what) {
#else
int caret_width = 1;
#endif
- if (cursor.line == line && ((line_wrap_index == line_wrap_amount) || (cursor.column != TS->shaped_text_get_range(rid).y))) {
+ if (!clipped && cursor.line == line && ((line_wrap_index == line_wrap_amount) || (cursor.column != TS->shaped_text_get_range(rid).y))) {
is_cursor_line_visible = true;
cursor_pos.y = line_top_offset_y;
@@ -1380,7 +1425,7 @@ void TextEdit::_notification(int p_what) {
l_caret.size.y = h;
}
l_caret.position += Vector2(char_margin + ofs_x, ofs_y);
- l_caret.size.x = cache.font->get_char_size('m', 0, cache.font_size).x;
+ l_caret.size.x = cache.font->get_char_size('M', 0, cache.font_size).x;
draw_rect(l_caret, cache.caret_color, false);
}
@@ -1444,7 +1489,6 @@ void TextEdit::_notification(int p_what) {
}
}
}
- ofs_y += ldata->get_line_descent(line_wrap_index);
}
}
@@ -1576,6 +1620,9 @@ void TextEdit::_notification(int p_what) {
}
tl->set_align(HALIGN_LEFT);
}
+ if (cache.outline_size > 0 && cache.outline_color.a > 0) {
+ tl->draw_outline(ci, title_pos, cache.outline_size, cache.outline_color);
+ }
tl->draw(ci, title_pos, completion_options[l].font_color);
}
@@ -3775,8 +3822,8 @@ void TextEdit::_scroll_lines_up() {
if (!selection.active) {
int cur_line = cursor.line;
int cur_wrap = get_cursor_wrap_index();
- int last_vis_line = get_last_visible_line();
- int last_vis_wrap = get_last_visible_line_wrap_index();
+ int last_vis_line = get_last_full_visible_line();
+ int last_vis_wrap = get_last_full_visible_line_wrap_index();
if (cur_line > last_vis_line || (cur_line == last_vis_line && cur_wrap > last_vis_wrap)) {
cursor_set_line(last_vis_line, false, false, last_vis_wrap);
@@ -4149,8 +4196,8 @@ void TextEdit::adjust_viewport_to_cursor() {
int first_vis_line = get_first_visible_line();
int first_vis_wrap = cursor.wrap_ofs;
- int last_vis_line = get_last_visible_line();
- int last_vis_wrap = get_last_visible_line_wrap_index();
+ int last_vis_line = get_last_full_visible_line();
+ int last_vis_wrap = get_last_full_visible_line_wrap_index();
if (cur_line < first_vis_line || (cur_line == first_vis_line && cur_wrap < first_vis_wrap)) {
// Cursor is above screen.
@@ -4919,6 +4966,8 @@ void TextEdit::_update_caches() {
cache.completion_font_color = get_theme_color("completion_font_color");
cache.font = get_theme_font("font");
cache.font_size = get_theme_font_size("font_size");
+ cache.outline_color = get_theme_color("font_outline_color");
+ cache.outline_size = get_theme_constant("outline_size");
cache.caret_color = get_theme_color("caret_color");
cache.caret_background_color = get_theme_color("caret_background_color");
cache.font_color = get_theme_color("font_color");
@@ -6163,19 +6212,19 @@ int TextEdit::get_first_visible_line() const {
return CLAMP(cursor.line_ofs, 0, text.size() - 1);
}
-int TextEdit::get_last_visible_line() const {
+int TextEdit::get_last_full_visible_line() const {
int first_vis_line = get_first_visible_line();
int last_vis_line = 0;
int wi;
- last_vis_line = first_vis_line + num_lines_from_rows(first_vis_line, cursor.wrap_ofs, get_visible_rows() + 1, wi) - 1;
+ last_vis_line = first_vis_line + num_lines_from_rows(first_vis_line, cursor.wrap_ofs, get_visible_rows(), wi) - 1;
last_vis_line = CLAMP(last_vis_line, 0, text.size() - 1);
return last_vis_line;
}
-int TextEdit::get_last_visible_line_wrap_index() const {
+int TextEdit::get_last_full_visible_line_wrap_index() const {
int first_vis_line = get_first_visible_line();
int wi;
- num_lines_from_rows(first_vis_line, cursor.wrap_ofs, get_visible_rows() + 1, wi);
+ num_lines_from_rows(first_vis_line, cursor.wrap_ofs, get_visible_rows(), wi);
return wi;
}
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 37299ec063..f50585d9e9 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -373,8 +373,8 @@ private:
void set_line_as_center_visible(int p_line, int p_wrap_index = 0);
void set_line_as_last_visible(int p_line, int p_wrap_index = 0);
int get_first_visible_line() const;
- int get_last_visible_line() const;
- int get_last_visible_line_wrap_index() const;
+ int get_last_full_visible_line() const;
+ int get_last_full_visible_line_wrap_index() const;
double get_visible_rows_offset() const;
double get_v_scroll_offset() const;
@@ -451,6 +451,8 @@ protected:
Ref<StyleBox> style_readonly;
Ref<Font> font;
int font_size = 16;
+ int outline_size = 0;
+ Color outline_color;
Color completion_background_color;
Color completion_selected_color;
Color completion_existing_color;
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index e8e3aeea68..ad06739da9 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -1118,7 +1118,7 @@ int Tree::get_item_height(TreeItem *p_item) const {
return height;
}
-void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color, const Color &p_icon_color) {
+void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color, const Color &p_icon_color, int p_ol_size, const Color &p_ol_color) {
ERR_FAIL_COND(cache.font.is_null());
Rect2i rect = p_rect;
@@ -1160,6 +1160,9 @@ void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Co
Point2 draw_pos = rect.position;
draw_pos.y += Math::floor((rect.size.y - p_cell.text_buf->get_size().y) / 2.0);
p_cell.text_buf->set_width(MAX(0, rect.size.width));
+ if (p_ol_size > 0 && p_ol_color.a > 0) {
+ p_cell.text_buf->draw_outline(ci, draw_pos, p_ol_size, p_ol_color);
+ }
p_cell.text_buf->draw(ci, draw_pos, p_color);
rect.position.x += ts.width + cache.hseparation;
rect.size.x -= ts.width + cache.hseparation;
@@ -1182,6 +1185,9 @@ void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Co
Point2 draw_pos = rect.position;
draw_pos.y += Math::floor((rect.size.y - p_cell.text_buf->get_size().y) / 2.0);
p_cell.text_buf->set_width(MAX(0, rect.size.width));
+ if (p_ol_size > 0 && p_ol_color.a > 0) {
+ p_cell.text_buf->draw_outline(ci, draw_pos, p_ol_size, p_ol_color);
+ }
p_cell.text_buf->draw(ci, draw_pos, p_color);
}
}
@@ -1434,6 +1440,8 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
}
Color col = p_item->cells[i].custom_color ? p_item->cells[i].color : get_theme_color(p_item->cells[i].selected ? "font_selected_color" : "font_color");
+ Color font_outline_color = get_theme_color("font_outline_color");
+ int outline_size = get_theme_constant("outline_size");
Color icon_col = p_item->cells[i].icon_color;
if (p_item->cells[i].dirty) {
@@ -1450,7 +1458,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
switch (p_item->cells[i].mode) {
case TreeItem::CELL_MODE_STRING: {
- draw_item_rect(p_item->cells.write[i], item_rect, col, icon_col);
+ draw_item_rect(p_item->cells.write[i], item_rect, col, icon_col, outline_size, font_outline_color);
} break;
case TreeItem::CELL_MODE_CHECK: {
Ref<Texture2D> checked = cache.checked;
@@ -1471,7 +1479,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
item_rect.size.x -= check_w;
item_rect.position.x += check_w;
- draw_item_rect(p_item->cells.write[i], item_rect, col, icon_col);
+ draw_item_rect(p_item->cells.write[i], item_rect, col, icon_col, outline_size, font_outline_color);
} break;
case TreeItem::CELL_MODE_RANGE: {
@@ -1485,8 +1493,14 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
p_item->cells.write[i].text_buf->set_width(cell_width);
if (rtl) {
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ p_item->cells[i].text_buf->draw_outline(ci, text_pos + Vector2(cell_width - text_width, 0), outline_size, font_outline_color);
+ }
p_item->cells[i].text_buf->draw(ci, text_pos + Vector2(cell_width - text_width, 0), col);
} else {
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ p_item->cells[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color);
+ }
p_item->cells[i].text_buf->draw(ci, text_pos, col);
}
@@ -1501,8 +1515,14 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
int cell_width = item_rect.size.x - updown->get_width();
if (rtl) {
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ p_item->cells[i].text_buf->draw_outline(ci, text_pos + Vector2(cell_width - text_width, 0), outline_size, font_outline_color);
+ }
p_item->cells[i].text_buf->draw(ci, text_pos + Vector2(cell_width - text_width, 0), col);
} else {
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ p_item->cells[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color);
+ }
p_item->cells[i].text_buf->draw(ci, text_pos, col);
}
@@ -1543,7 +1563,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
}
if (!p_item->cells[i].editable) {
- draw_item_rect(p_item->cells.write[i], item_rect, col, icon_col);
+ draw_item_rect(p_item->cells.write[i], item_rect, col, icon_col, outline_size, font_outline_color);
break;
}
@@ -1571,7 +1591,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
ir.position += cache.custom_button->get_offset();
}
- draw_item_rect(p_item->cells.write[i], ir, col, icon_col);
+ draw_item_rect(p_item->cells.write[i], ir, col, icon_col, outline_size, font_outline_color);
downarrow->draw(ci, arrow_pos);
@@ -3143,6 +3163,8 @@ void Tree::_notification(int p_what) {
Ref<StyleBox> bg = cache.bg;
Ref<StyleBox> bg_focus = get_theme_stylebox("bg_focus");
+ Color font_outline_color = get_theme_color("font_outline_color");
+ int outline_size = get_theme_constant("outline_size");
Point2 draw_ofs;
draw_ofs += bg->get_offset();
@@ -3179,7 +3201,12 @@ void Tree::_notification(int p_what) {
//text
int clip_w = tbrect.size.width - sb->get_minimum_size().width;
columns.write[i].text_buf->set_width(clip_w);
- columns[i].text_buf->draw(ci, tbrect.position + Point2i(sb->get_offset().x + (tbrect.size.width - columns[i].text_buf->get_size().x) / 2, (tbrect.size.height - columns[i].text_buf->get_size().y) / 2), cache.title_button_color);
+
+ Vector2 text_pos = tbrect.position + Point2i(sb->get_offset().x + (tbrect.size.width - columns[i].text_buf->get_size().x) / 2, (tbrect.size.height - columns[i].text_buf->get_size().y) / 2);
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ columns[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color);
+ }
+ columns[i].text_buf->draw(ci, text_pos, cache.title_button_color);
}
}
}
@@ -3315,6 +3342,9 @@ void Tree::item_selected(int p_column, TreeItem *p_item) {
//emit_signal("multi_selected",p_item,p_column,true); - NO this is for TreeItem::select
selected_col = p_column;
+ if (!selected_item) {
+ selected_item = p_item;
+ }
} else {
select_single_item(p_item, root, p_column);
}
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index c3c8052b67..1be21cb4a4 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -385,7 +385,7 @@ private:
void update_item_cell(TreeItem *p_item, int p_col);
void update_item_cache(TreeItem *p_item);
//void draw_item_text(String p_text,const Ref<Texture2D>& p_icon,int p_icon_max_w,bool p_tool,Rect2i p_rect,const Color& p_color);
- void draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color, const Color &p_icon_color);
+ void draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color, const Color &p_icon_color, int p_ol_size, const Color &p_ol_color);
int draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 &p_draw_size, TreeItem *p_item);
void select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_col, TreeItem *p_prev = nullptr, bool *r_in_range = nullptr, bool p_force_deselect = false);
int propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool p_doubleclick, TreeItem *p_item, int p_button, const Ref<InputEventWithModifiers> &p_mod);
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 9ac3b4a691..e109240f59 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -2138,8 +2138,17 @@ Node *Node::duplicate(int p_flags) const {
#ifdef TOOLS_ENABLED
Node *Node::duplicate_from_editor(Map<const Node *, Node *> &r_duplimap) const {
+ return duplicate_from_editor(r_duplimap, Map<RES, RES>());
+}
+
+Node *Node::duplicate_from_editor(Map<const Node *, Node *> &r_duplimap, const Map<RES, RES> &p_resource_remap) const {
Node *dupe = _duplicate(DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS | DUPLICATE_USE_INSTANCING | DUPLICATE_FROM_EDITOR, &r_duplimap);
+ // This is used by SceneTreeDock's paste functionality. When pasting to foreign scene, resources are duplicated.
+ if (!p_resource_remap.is_empty()) {
+ remap_node_resources(dupe, p_resource_remap);
+ }
+
// Duplication of signals must happen after all the node descendants have been copied,
// because re-targeting of connections from some descendant to another is not possible
// if the emitter node comes later in tree order than the receiver
@@ -2147,6 +2156,54 @@ Node *Node::duplicate_from_editor(Map<const Node *, Node *> &r_duplimap) const {
return dupe;
}
+
+void Node::remap_node_resources(Node *p_node, const Map<RES, RES> &p_resource_remap) const {
+ List<PropertyInfo> props;
+ p_node->get_property_list(&props);
+
+ for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
+ if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) {
+ continue;
+ }
+
+ Variant v = p_node->get(E->get().name);
+ if (v.is_ref()) {
+ RES res = v;
+ if (res.is_valid()) {
+ if (p_resource_remap.has(res)) {
+ p_node->set(E->get().name, p_resource_remap[res]);
+ remap_nested_resources(res, p_resource_remap);
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ remap_node_resources(p_node->get_child(i), p_resource_remap);
+ }
+}
+
+void Node::remap_nested_resources(RES p_resource, const Map<RES, RES> &p_resource_remap) const {
+ List<PropertyInfo> props;
+ p_resource->get_property_list(&props);
+
+ for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
+ if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) {
+ continue;
+ }
+
+ Variant v = p_resource->get(E->get().name);
+ if (v.is_ref()) {
+ RES res = v;
+ if (res.is_valid()) {
+ if (p_resource_remap.has(res)) {
+ p_resource->set(E->get().name, p_resource_remap[res]);
+ remap_nested_resources(res, p_resource_remap);
+ }
+ }
+ }
+ }
+}
#endif
void Node::_duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p_reown_map) const {
diff --git a/scene/main/node.h b/scene/main/node.h
index 5253ed2e45..66104b5cf5 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -362,6 +362,9 @@ public:
Node *duplicate_and_reown(const Map<Node *, Node *> &p_reown_map) const;
#ifdef TOOLS_ENABLED
Node *duplicate_from_editor(Map<const Node *, Node *> &r_duplimap) const;
+ Node *duplicate_from_editor(Map<const Node *, Node *> &r_duplimap, const Map<RES, RES> &p_resource_remap) const;
+ void remap_node_resources(Node *p_node, const Map<RES, RES> &p_resource_remap) const;
+ void remap_nested_resources(RES p_resource, const Map<RES, RES> &p_resource_remap) const;
#endif
// used by editors, to save what has changed only
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index a0750b2590..54b670df6c 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -278,6 +278,11 @@ void Viewport::_sub_window_update(Window *p_window) {
int x = (r.size.width - title_text.get_size().x) / 2;
int y = (-title_height - title_text.get_size().y) / 2;
+ Color font_outline_color = p_window->get_theme_color("title_outline_modulate");
+ int outline_size = p_window->get_theme_constant("title_outline_size");
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ title_text.draw_outline(sw.canvas_item, r.position + Point2(x, y), outline_size, font_outline_color);
+ }
title_text.draw(sw.canvas_item, r.position + Point2(x, y), title_color);
bool hl = gui.subwindow_focused == sw.window && gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE && gui.subwindow_drag_close_inside;
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 62a796b492..cc1dafd0db 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -580,6 +580,10 @@ void Animation::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
+void Animation::reset_state() {
+ clear();
+}
+
int Animation::add_track(TrackType p_type, int p_at_pos) {
if (p_at_pos < 0 || p_at_pos >= tracks.size()) {
p_at_pos = tracks.size();
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index ab3bbfacba..fd22cc445c 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -252,6 +252,8 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ virtual void reset_state() override;
+
static void _bind_methods();
public:
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 31bc00e528..943176537b 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -210,7 +210,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_color", "LinkButton", control_font_color);
theme->set_color("font_pressed_color", "LinkButton", control_font_pressed_color);
theme->set_color("font_hover_color", "LinkButton", control_font_hover_color);
+ theme->set_color("font_outline_color", "LinkButton", Color(1, 1, 1));
+ theme->set_constant("outline_size", "LinkButton", 0);
theme->set_constant("underline_spacing", "LinkButton", 2 * scale);
// ColorPickerButton
@@ -228,8 +230,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_pressed_color", "ColorPickerButton", Color(0.8, 0.8, 0.8, 1));
theme->set_color("font_hover_color", "ColorPickerButton", Color(1, 1, 1, 1));
theme->set_color("font_disabled_color", "ColorPickerButton", Color(0.9, 0.9, 0.9, 0.3));
+ theme->set_color("font_outline_color", "ColorPickerButton", Color(1, 1, 1));
theme->set_constant("hseparation", "ColorPickerButton", 2 * scale);
+ theme->set_constant("outline_size", "ColorPickerButton", 0);
// OptionButton
@@ -265,9 +269,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_pressed_color", "OptionButton", control_font_pressed_color);
theme->set_color("font_hover_color", "OptionButton", control_font_hover_color);
theme->set_color("font_disabled_color", "OptionButton", control_font_disabled_color);
+ theme->set_color("font_outline_color", "OptionButton", Color(1, 1, 1));
theme->set_constant("hseparation", "OptionButton", 2 * scale);
theme->set_constant("arrow_margin", "OptionButton", 2 * scale);
+ theme->set_constant("outline_size", "OptionButton", 0);
// MenuButton
@@ -284,8 +290,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_pressed_color", "MenuButton", control_font_pressed_color);
theme->set_color("font_hover_color", "MenuButton", control_font_hover_color);
theme->set_color("font_disabled_color", "MenuButton", Color(1, 1, 1, 0.3));
+ theme->set_color("font_outline_color", "MenuButton", Color(1, 1, 1));
theme->set_constant("hseparation", "MenuButton", 3 * scale);
+ theme->set_constant("outline_size", "MenuButton", 0);
// CheckBox
@@ -320,9 +328,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_hover_color", "CheckBox", control_font_hover_color);
theme->set_color("font_hover_pressed_color", "CheckBox", control_font_pressed_color);
theme->set_color("font_disabled_color", "CheckBox", control_font_disabled_color);
+ theme->set_color("font_outline_color", "CheckBox", Color(1, 1, 1));
theme->set_constant("hseparation", "CheckBox", 4 * scale);
theme->set_constant("check_vadjust", "CheckBox", 0 * scale);
+ theme->set_constant("outline_size", "CheckBox", 0);
// CheckButton
@@ -357,9 +367,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_hover_color", "CheckButton", control_font_hover_color);
theme->set_color("font_hover_pressed_color", "CheckButton", control_font_pressed_color);
theme->set_color("font_disabled_color", "CheckButton", control_font_disabled_color);
+ theme->set_color("font_outline_color", "CheckButton", Color(1, 1, 1));
theme->set_constant("hseparation", "CheckButton", 4 * scale);
theme->set_constant("check_vadjust", "CheckButton", 0 * scale);
+ theme->set_constant("outline_size", "CheckButton", 0);
// Label
@@ -373,7 +385,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("shadow_offset_x", "Label", 1 * scale);
theme->set_constant("shadow_offset_y", "Label", 1 * scale);
- theme->set_constant("outline_size", "Label", 0 * scale);
+ theme->set_constant("outline_size", "Label", 0);
theme->set_constant("shadow_outline_size", "Label", 1 * scale);
theme->set_constant("line_spacing", "Label", 3 * scale);
@@ -389,12 +401,14 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_color", "LineEdit", control_font_color);
theme->set_color("font_selected_color", "LineEdit", Color(0, 0, 0));
theme->set_color("font_uneditable_color", "LineEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f));
+ theme->set_color("font_outline_color", "LineEdit", Color(1, 1, 1));
theme->set_color("cursor_color", "LineEdit", control_font_hover_color);
theme->set_color("selection_color", "LineEdit", control_selection_color);
theme->set_color("clear_button_color", "LineEdit", control_font_color);
theme->set_color("clear_button_color_pressed", "LineEdit", control_font_pressed_color);
- theme->set_constant("minimum_spaces", "LineEdit", 12 * scale);
+ theme->set_constant("minimum_character_width", "LineEdit", 4);
+ theme->set_constant("outline_size", "LineEdit", 0);
theme->set_icon("clear", "LineEdit", make_icon(line_edit_clear_png));
@@ -408,6 +422,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_color", "ProgressBar", control_font_hover_color);
theme->set_color("font_shadow_color", "ProgressBar", Color(0, 0, 0));
+ theme->set_color("font_outline_color", "ProgressBar", Color(1, 1, 1));
+
+ theme->set_constant("outline_size", "ProgressBar", 0);
// TextEdit
@@ -431,6 +448,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_color", "TextEdit", control_font_color);
theme->set_color("font_selected_color", "TextEdit", Color(0, 0, 0));
theme->set_color("font_readonly_color", "TextEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f));
+ theme->set_color("font_outline_color", "TextEdit", Color(1, 1, 1));
theme->set_color("selection_color", "TextEdit", control_selection_color);
theme->set_color("mark_color", "TextEdit", Color(1.0, 0.4, 0.4, 0.4));
theme->set_color("code_folding_color", "TextEdit", Color(0.8, 0.8, 0.8, 0.8));
@@ -444,8 +462,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("completion_max_width", "TextEdit", 50);
theme->set_constant("completion_scroll_width", "TextEdit", 3);
theme->set_constant("line_spacing", "TextEdit", 4 * scale);
+ theme->set_constant("outline_size", "TextEdit", 0);
// CodeEdit
+
theme->set_stylebox("normal", "CodeEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3, 0, 0, 0, 0));
theme->set_stylebox("focus", "CodeEdit", focus);
theme->set_stylebox("read_only", "CodeEdit", make_stylebox(tree_bg_disabled_png, 4, 4, 4, 4, 0, 0, 0, 0));
@@ -471,6 +491,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_color", "CodeEdit", control_font_color);
theme->set_color("font_selected_color", "CodeEdit", Color(0, 0, 0));
theme->set_color("font_readonly_color", "CodeEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f));
+ theme->set_color("font_outline_color", "CodeEdit", Color(1, 1, 1));
theme->set_color("selection_color", "CodeEdit", control_selection_color);
theme->set_color("mark_color", "CodeEdit", Color(1.0, 0.4, 0.4, 0.4));
theme->set_color("bookmark_color", "CodeEdit", Color(0.5, 0.64, 1, 0.8));
@@ -489,6 +510,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("completion_max_width", "CodeEdit", 50);
theme->set_constant("completion_scroll_width", "CodeEdit", 3);
theme->set_constant("line_spacing", "CodeEdit", 4 * scale);
+ theme->set_constant("outline_size", "CodeEdit", 0);
Ref<Texture2D> empty_icon = memnew(ImageTexture);
@@ -544,7 +566,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("updown", "SpinBox", make_icon(spinbox_updown_png));
- //scroll container
+ // ScrollContainer
+
Ref<StyleBoxEmpty> empty;
empty.instance();
theme->set_stylebox("bg", "ScrollContainer", empty);
@@ -556,7 +579,12 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("scaleborder_size", "Window", 4 * scale);
theme->set_font("title_font", "Window", large_font);
+ theme->set_font_size("title_font_size", "Window", -1);
+
theme->set_color("title_color", "Window", Color(0, 0, 0));
+ theme->set_color("title_outline_modulate", "Window", Color(1, 1, 1));
+
+ theme->set_constant("title_outline_size", "Window", 0);
theme->set_constant("title_height", "Window", 20 * scale);
theme->set_constant("resize_margin", "Window", 4 * scale);
@@ -611,9 +639,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_disabled_color", "PopupMenu", Color(0.4, 0.4, 0.4, 0.8));
theme->set_color("font_hover_color", "PopupMenu", control_font_color);
theme->set_color("font_separator_color", "PopupMenu", control_font_color);
+ theme->set_color("font_outline_color", "PopupMenu", Color(1, 1, 1));
theme->set_constant("hseparation", "PopupMenu", 4 * scale);
theme->set_constant("vseparation", "PopupMenu", 4 * scale);
+ theme->set_constant("outline_size", "PopupMenu", 0);
+ theme->set_constant("item_start_padding", "PopupMenu", 2 * scale);
+ theme->set_constant("item_end_padding", "PopupMenu", 2 * scale);
// GraphNode
@@ -682,6 +714,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("title_button_color", "Tree", control_font_color);
theme->set_color("font_color", "Tree", control_font_low_color);
theme->set_color("font_selected_color", "Tree", control_font_pressed_color);
+ theme->set_color("font_outline_color", "Tree", Color(1, 1, 1));
theme->set_color("guide_color", "Tree", Color(0, 0, 0, 0.1));
theme->set_color("drop_position_color", "Tree", Color(1, 0.3, 0.2));
theme->set_color("relationship_line_color", "Tree", Color(0.27, 0.27, 0.27));
@@ -695,8 +728,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("draw_guides", "Tree", 1);
theme->set_constant("scroll_border", "Tree", 4);
theme->set_constant("scroll_speed", "Tree", 12);
+ theme->set_constant("outline_size", "Tree", 0);
// ItemList
+
Ref<StyleBoxTexture> item_selected = make_stylebox(selection_png, 4, 4, 4, 4, 8, 2, 8, 2);
Ref<StyleBoxTexture> item_selected_oof = make_stylebox(selection_oof_png, 4, 4, 4, 4, 8, 2, 8, 2);
@@ -712,12 +747,15 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_color", "ItemList", control_font_lower_color);
theme->set_color("font_selected_color", "ItemList", control_font_pressed_color);
+ theme->set_color("font_outline_color", "ItemList", Color(1, 1, 1));
theme->set_color("guide_color", "ItemList", Color(0, 0, 0, 0.1));
theme->set_stylebox("selected", "ItemList", item_selected_oof);
theme->set_stylebox("selected_focus", "ItemList", item_selected);
theme->set_stylebox("cursor", "ItemList", focus);
theme->set_stylebox("cursor_unfocused", "ItemList", focus);
+ theme->set_constant("outline_size", "ItemList", 0);
+
// TabContainer
Ref<StyleBoxTexture> tc_sb = sb_expand(make_stylebox(tab_container_bg_png, 4, 4, 4, 4, 4, 4, 4, 4), 3, 3, 3, 3);
@@ -743,9 +781,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_selected_color", "TabContainer", control_font_hover_color);
theme->set_color("font_unselected_color", "TabContainer", control_font_low_color);
theme->set_color("font_disabled_color", "TabContainer", control_font_disabled_color);
+ theme->set_color("font_outline_color", "TabContainer", Color(1, 1, 1));
theme->set_constant("side_margin", "TabContainer", 8 * scale);
theme->set_constant("icon_separation", "TabContainer", 4 * scale);
+ theme->set_constant("outline_size", "TabContainer", 0);
// Tabs
@@ -768,8 +808,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_selected_color", "Tabs", control_font_hover_color);
theme->set_color("font_unselected_color", "Tabs", control_font_low_color);
theme->set_color("font_disabled_color", "Tabs", control_font_disabled_color);
+ theme->set_color("font_outline_color", "Tabs", Color(1, 1, 1));
theme->set_constant("hseparation", "Tabs", 4 * scale);
+ theme->set_constant("outline_size", "Tabs", 0);
// Separators
@@ -827,9 +869,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_color", "TooltipLabel", Color(0, 0, 0));
theme->set_color("font_shadow_color", "TooltipLabel", Color(0, 0, 0, 0.1));
+ theme->set_color("font_outline_color", "TooltipLabel", Color(1, 1, 1));
theme->set_constant("shadow_offset_x", "TooltipLabel", 1);
theme->set_constant("shadow_offset_y", "TooltipLabel", 1);
+ theme->set_constant("outline_size", "TooltipLabel", 0);
// RichTextLabel
@@ -854,6 +898,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_shadow_color", "RichTextLabel", Color(0, 0, 0, 0));
+ theme->set_color("font_outline_color", "RichTextLabel", Color(1, 1, 1));
+
theme->set_constant("shadow_offset_x", "RichTextLabel", 1 * scale);
theme->set_constant("shadow_offset_y", "RichTextLabel", 1 * scale);
theme->set_constant("shadow_as_outline", "RichTextLabel", 0 * scale);
@@ -862,9 +908,12 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("table_hseparation", "RichTextLabel", 3 * scale);
theme->set_constant("table_vseparation", "RichTextLabel", 3 * scale);
+ theme->set_constant("outline_size", "RichTextLabel", 0);
+
theme->set_color("table_odd_row_bg", "RichTextLabel", Color(0, 0, 0, 0));
theme->set_color("table_even_row_bg", "RichTextLabel", Color(0, 0, 0, 0));
theme->set_color("table_border", "RichTextLabel", Color(0, 0, 0, 0));
+
// Containers
theme->set_stylebox("bg", "VSplitContainer", make_stylebox(vsplit_bg_png, 1, 1, 1, 1));
@@ -904,6 +953,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("bezier_len_neg", "GraphEdit", 160 * scale);
// Visual Node Ports
+
theme->set_constant("port_grab_distance_horizontal", "GraphEdit", 48 * scale);
theme->set_constant("port_grab_distance_vertical", "GraphEdit", 6 * scale);
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 3d610fd708..702f2ed1c8 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -50,6 +50,9 @@ void FontData::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_underline_position", "size"), &FontData::get_underline_position);
ClassDB::bind_method(D_METHOD("get_underline_thickness", "size"), &FontData::get_underline_thickness);
+ ClassDB::bind_method(D_METHOD("get_spacing", "type"), &FontData::get_spacing);
+ ClassDB::bind_method(D_METHOD("set_spacing", "type", "value"), &FontData::set_spacing);
+
ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &FontData::set_antialiased);
ClassDB::bind_method(D_METHOD("get_antialiased"), &FontData::get_antialiased);
@@ -100,6 +103,13 @@ void FontData::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "distance_field_hint"), "set_distance_field_hint", "get_distance_field_hint");
ADD_PROPERTY(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), "set_hinting", "get_hinting");
+
+ ADD_GROUP("Extra Spacing", "extra_spacing");
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "extra_spacing_glyph"), "set_spacing", "get_spacing", SPACING_GLYPH);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "extra_spacing_space"), "set_spacing", "get_spacing", SPACING_SPACE);
+
+ BIND_ENUM_CONSTANT(SPACING_GLYPH);
+ BIND_ENUM_CONSTANT(SPACING_SPACE);
}
bool FontData::_set(const StringName &p_name, const Variant &p_value) {
@@ -177,6 +187,14 @@ void FontData::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
+void FontData::reset_state() {
+ if (rid != RID()) {
+ TS->free(rid);
+ }
+ base_size = 16;
+ path = String();
+}
+
RID FontData::get_rid() const {
return rid;
}
@@ -281,6 +299,27 @@ double FontData::get_variation(const String &p_name) const {
return TS->font_get_variation(rid, p_name);
}
+int FontData::get_spacing(int p_type) const {
+ if (rid == RID()) {
+ return 0;
+ }
+ if (p_type == SPACING_GLYPH) {
+ return TS->font_get_spacing_glyph(rid);
+ } else {
+ return TS->font_get_spacing_space(rid);
+ }
+}
+
+void FontData::set_spacing(int p_type, int p_value) {
+ ERR_FAIL_COND(rid == RID());
+ if (p_type == SPACING_GLYPH) {
+ TS->font_set_spacing_glyph(rid, p_value);
+ } else {
+ TS->font_set_spacing_space(rid, p_value);
+ }
+ emit_changed();
+}
+
void FontData::set_antialiased(bool p_antialiased) {
ERR_FAIL_COND(rid == RID());
TS->font_set_antialiased(rid, p_antialiased);
@@ -588,6 +627,14 @@ void Font::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::OBJECT, "data/" + itos(data.size()), PROPERTY_HINT_RESOURCE_TYPE, "FontData"));
}
+void Font::reset_state() {
+ spacing_top = 0;
+ spacing_bottom = 0;
+ cache.clear();
+ cache_wrap.clear();
+ data.clear();
+}
+
void Font::add_data(const Ref<FontData> &p_data) {
ERR_FAIL_COND(p_data.is_null());
data.push_back(p_data);
@@ -781,6 +828,8 @@ Size2 Font::get_multiline_string_size(const String &p_text, float p_width, int p
}
void Font::draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HAlign p_align, float p_width, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const {
+ ERR_FAIL_COND(data.is_empty());
+
uint64_t hash = p_text.hash64();
hash = hash_djb2_one_64(p_size, hash);
@@ -811,6 +860,8 @@ void Font::draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_t
}
void Font::draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HAlign p_align, float p_width, int p_max_lines, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const {
+ ERR_FAIL_COND(data.is_empty());
+
uint64_t hash = p_text.hash64();
hash = hash_djb2_one_64(p_size, hash);
@@ -951,7 +1002,7 @@ Font::~Font() {
/*************************************************************************/
-RES ResourceFormatLoaderFont::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderFont::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_FILE_CANT_OPEN;
}
@@ -1006,7 +1057,7 @@ String ResourceFormatLoaderFont::get_resource_type(const String &p_path) const {
#ifndef DISABLE_DEPRECATED
-RES ResourceFormatLoaderCompatFont::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderCompatFont::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_FILE_CANT_OPEN;
}
diff --git a/scene/resources/font.h b/scene/resources/font.h
index 086226c082..56b5acde1a 100644
--- a/scene/resources/font.h
+++ b/scene/resources/font.h
@@ -42,6 +42,13 @@
class FontData : public Resource {
GDCLASS(FontData, Resource);
+public:
+ enum SpacingType {
+ SPACING_GLYPH,
+ SPACING_SPACE,
+ };
+
+private:
RID rid;
int base_size = 16;
String path;
@@ -53,6 +60,8 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ virtual void reset_state() override;
+
public:
virtual RID get_rid() const override;
@@ -76,6 +85,9 @@ public:
float get_underline_position(int p_size) const;
float get_underline_thickness(int p_size) const;
+ int get_spacing(int p_type) const;
+ void set_spacing(int p_type, int p_value);
+
void set_antialiased(bool p_antialiased);
bool get_antialiased() const;
@@ -132,7 +144,7 @@ class Font : public Resource {
public:
enum SpacingType {
SPACING_TOP,
- SPACING_BOTTOM
+ SPACING_BOTTOM,
};
private:
@@ -151,6 +163,8 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ virtual void reset_state() override;
+
void _data_changed();
public:
@@ -195,13 +209,14 @@ public:
~Font();
};
+VARIANT_ENUM_CAST(FontData::SpacingType);
VARIANT_ENUM_CAST(Font::SpacingType);
/*************************************************************************/
class ResourceFormatLoaderFont : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
@@ -212,7 +227,7 @@ public:
class ResourceFormatLoaderCompatFont : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
diff --git a/scene/resources/material.h b/scene/resources/material.h
index 595db36a57..70452a5f74 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -519,7 +519,7 @@ private:
AlphaAntiAliasing alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
- bool features[FEATURE_MAX];
+ bool features[FEATURE_MAX] = {};
Ref<Texture2D> textures[TEXTURE_MAX];
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 81dbb36288..1a2b21299a 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -1095,6 +1095,15 @@ bool ArrayMesh::_get(const StringName &p_name, Variant &r_ret) const {
return true;
}
+void ArrayMesh::reset_state() {
+ clear_surfaces();
+ clear_blend_shapes();
+
+ aabb = AABB();
+ blend_shape_mode = BLEND_SHAPE_MODE_RELATIVE;
+ custom_aabb = AABB();
+}
+
void ArrayMesh::_get_property_list(List<PropertyInfo> *p_list) const {
if (_is_generated()) {
return;
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index 8883fb9c2b..2ce519e644 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -207,6 +207,8 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ virtual void reset_state() override;
+
static void _bind_methods();
public:
diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp
index 84da0feab0..ad90481fbd 100644
--- a/scene/resources/mesh_library.cpp
+++ b/scene/resources/mesh_library.cpp
@@ -264,6 +264,9 @@ Array MeshLibrary::_get_item_shapes(int p_item) const {
return ret;
}
+void MeshLibrary::reset_state() {
+ clear();
+}
void MeshLibrary::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_item", "id"), &MeshLibrary::create_item);
ClassDB::bind_method(D_METHOD("set_item_name", "id", "name"), &MeshLibrary::set_item_name);
diff --git a/scene/resources/mesh_library.h b/scene/resources/mesh_library.h
index 5c302fcf08..1da624c275 100644
--- a/scene/resources/mesh_library.h
+++ b/scene/resources/mesh_library.h
@@ -65,6 +65,7 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ virtual void reset_state() override;
static void _bind_methods();
public:
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index ef0c3c830b..beb365d44e 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -1661,6 +1661,9 @@ void PackedScene::set_path(const String &p_path, bool p_take_over) {
Resource::set_path(p_path, p_take_over);
}
+void PackedScene::reset_state() {
+ clear();
+}
void PackedScene::_bind_methods() {
ClassDB::bind_method(D_METHOD("pack", "path"), &PackedScene::pack);
ClassDB::bind_method(D_METHOD("instance", "edit_state"), &PackedScene::instance, DEFVAL(GEN_EDIT_STATE_DISABLED));
diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h
index e24b09e77f..78a0aeaa9a 100644
--- a/scene/resources/packed_scene.h
+++ b/scene/resources/packed_scene.h
@@ -200,6 +200,7 @@ class PackedScene : public Resource {
protected:
virtual bool editor_can_reload_from_file() override { return false; } // this is handled by editor better
static void _bind_methods();
+ virtual void reset_state() override;
public:
enum GenEditState {
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index f42f957f6e..7ca532e1d6 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -114,23 +114,8 @@ Error ResourceLoaderText::_parse_sub_resource(VariantParser::Stream *p_stream, R
}
int index = token.value;
-
- if (use_nocache) {
- r_res = int_resources[index];
- } else {
- String path = local_path + "::" + itos(index);
-
- if (!ignore_resource_parsing) {
- if (!ResourceCache::has(path)) {
- r_err_str = "Can't load cached sub-resource: " + path;
- return ERR_PARSE_ERROR;
- }
-
- r_res = RES(ResourceCache::get(path));
- } else {
- r_res = RES();
- }
- }
+ ERR_FAIL_COND_V(!int_resources.has(index), ERR_INVALID_PARAMETER);
+ r_res = int_resources[index];
VariantParser::get_token(p_stream, token, line, r_err_str);
if (token.type != VariantParser::TK_PARENTHESIS_CLOSE) {
@@ -440,7 +425,7 @@ Error ResourceLoaderText::load() {
er.type = type;
if (use_sub_threads) {
- Error err = ResourceLoader::load_threaded_request(path, type, use_sub_threads, local_path);
+ Error err = ResourceLoader::load_threaded_request(path, type, use_sub_threads, ResourceFormatLoader::CACHE_MODE_REUSE, local_path);
if (err != OK) {
if (ResourceLoader::get_abort_on_missing_resources()) {
@@ -517,29 +502,44 @@ Error ResourceLoaderText::load() {
//bool exists=ResourceCache::has(path);
Ref<Resource> res;
+ bool do_assign = false;
- if (use_nocache || !ResourceCache::has(path)) { //only if it doesn't exist
-
- Object *obj = ClassDB::instance(type);
- if (!obj) {
- error_text += "Can't create sub resource of type: " + type;
- _printerr();
- error = ERR_FILE_CORRUPT;
- return error;
+ if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(path)) {
+ //reuse existing
+ Resource *r = ResourceCache::get(path);
+ if (r && r->get_class() == type) {
+ res = Ref<Resource>(r);
+ res->reset_state();
+ do_assign = true;
}
+ }
- Resource *r = Object::cast_to<Resource>(obj);
- if (!r) {
- error_text += "Can't create sub resource of type, because not a resource: " + type;
- _printerr();
- error = ERR_FILE_CORRUPT;
- return error;
- }
+ if (res.is_null()) { //not reuse
+ if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && ResourceCache::has(path)) { //only if it doesn't exist
+ //cached, do not assign
+ Resource *r = ResourceCache::get(path);
+ res = Ref<Resource>(r);
+ } else {
+ //create
+
+ Object *obj = ClassDB::instance(type);
+ if (!obj) {
+ error_text += "Can't create sub resource of type: " + type;
+ _printerr();
+ error = ERR_FILE_CORRUPT;
+ return error;
+ }
+
+ Resource *r = Object::cast_to<Resource>(obj);
+ if (!r) {
+ error_text += "Can't create sub resource of type, because not a resource: " + type;
+ _printerr();
+ error = ERR_FILE_CORRUPT;
+ return error;
+ }
- res = Ref<Resource>(r);
- int_resources[id] = res;
- if (!use_nocache) {
- res->set_path(path);
+ res = Ref<Resource>(r);
+ do_assign = true;
}
}
@@ -557,7 +557,7 @@ Error ResourceLoaderText::load() {
}
if (assign != String()) {
- if (res.is_valid()) {
+ if (do_assign) {
res->set(assign, value);
}
//it's assignment
@@ -572,6 +572,11 @@ Error ResourceLoaderText::load() {
}
}
+ int_resources[id] = res; //always assign int resources
+ if (do_assign && cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
+ res->set_path(path, cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE);
+ }
+
if (progress && resources_total > 0) {
*progress = resource_current / float(resources_total);
}
@@ -589,23 +594,33 @@ Error ResourceLoaderText::load() {
return error;
}
- Object *obj = ClassDB::instance(res_type);
- if (!obj) {
- error_text += "Can't create sub resource of type: " + res_type;
- _printerr();
- error = ERR_FILE_CORRUPT;
- return error;
+ if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(local_path)) {
+ Resource *r = ResourceCache::get(local_path);
+ if (r->get_class() == res_type) {
+ r->reset_state();
+ resource = Ref<Resource>(r);
+ }
}
- Resource *r = Object::cast_to<Resource>(obj);
- if (!r) {
- error_text += "Can't create sub resource of type, because not a resource: " + res_type;
- _printerr();
- error = ERR_FILE_CORRUPT;
- return error;
- }
+ if (!resource.is_valid()) {
+ Object *obj = ClassDB::instance(res_type);
+ if (!obj) {
+ error_text += "Can't create sub resource of type: " + res_type;
+ _printerr();
+ error = ERR_FILE_CORRUPT;
+ return error;
+ }
- resource = Ref<Resource>(r);
+ Resource *r = Object::cast_to<Resource>(obj);
+ if (!r) {
+ error_text += "Can't create sub resource of type, because not a resource: " + res_type;
+ _printerr();
+ error = ERR_FILE_CORRUPT;
+ return error;
+ }
+
+ resource = Ref<Resource>(r);
+ }
resource_current++;
@@ -620,7 +635,7 @@ Error ResourceLoaderText::load() {
_printerr();
} else {
error = OK;
- if (!use_nocache) {
+ if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
if (!ResourceCache::has(res_path)) {
resource->set_path(res_path);
}
@@ -668,7 +683,7 @@ Error ResourceLoaderText::load() {
error = OK;
//get it here
resource = packed_scene;
- if (!use_nocache && !ResourceCache::has(res_path)) {
+ if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && !ResourceCache::has(res_path)) {
packed_scene->set_path(res_path);
}
@@ -1241,7 +1256,7 @@ String ResourceLoaderText::recognize(FileAccess *p_f) {
/////////////////////
-RES ResourceFormatLoaderText::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderText::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_CANT_OPEN;
}
@@ -1254,7 +1269,7 @@ RES ResourceFormatLoaderText::load(const String &p_path, const String &p_origina
ResourceLoaderText loader;
String path = p_original_path != "" ? p_original_path : p_path;
- loader.use_nocache = p_no_cache;
+ loader.cache_mode = p_cache_mode;
loader.use_sub_threads = p_use_sub_threads;
loader.local_path = ProjectSettings::get_singleton()->localize_path(path);
loader.progress = r_progress;
diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h
index 3fc7814fe5..2dc683415d 100644
--- a/scene/resources/resource_format_text.h
+++ b/scene/resources/resource_format_text.h
@@ -69,7 +69,7 @@ class ResourceLoaderText {
VariantParser::Tag next_tag;
- bool use_nocache = false;
+ ResourceFormatLoader::CacheMode cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE;
bool use_sub_threads = false;
float *progress = nullptr;
@@ -134,7 +134,7 @@ public:
class ResourceFormatLoaderText : public ResourceFormatLoader {
public:
static ResourceFormatLoaderText *singleton;
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index 49d5ac8340..77c6199794 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -161,7 +161,7 @@ Shader::~Shader() {
////////////
-RES ResourceFormatLoaderShader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderShader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_FILE_CANT_OPEN;
}
diff --git a/scene/resources/shader.h b/scene/resources/shader.h
index bb83d8a032..6563181ca2 100644
--- a/scene/resources/shader.h
+++ b/scene/resources/shader.h
@@ -102,7 +102,7 @@ VARIANT_ENUM_CAST(Shader::Mode);
class ResourceFormatLoaderShader : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/scene/resources/skin.cpp b/scene/resources/skin.cpp
index 56c1dab4be..fee8fdbde2 100644
--- a/scene/resources/skin.cpp
+++ b/scene/resources/skin.cpp
@@ -81,6 +81,10 @@ void Skin::clear_binds() {
emit_changed();
}
+void Skin::reset_state() {
+ clear_binds();
+}
+
bool Skin::_set(const StringName &p_name, const Variant &p_value) {
String name = p_name;
if (name == "bind_count") {
diff --git a/scene/resources/skin.h b/scene/resources/skin.h
index d5f5e2085b..f5d64f96aa 100644
--- a/scene/resources/skin.h
+++ b/scene/resources/skin.h
@@ -52,6 +52,7 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ virtual void reset_state() override;
static void _bind_methods();
public:
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index 8e47c1c15c..9b80224c3f 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -937,8 +937,17 @@ void StyleBoxLine::_bind_methods() {
}
float StyleBoxLine::get_style_margin(Side p_side) const {
- ERR_FAIL_INDEX_V((int)p_side, 4, thickness);
- return thickness;
+ ERR_FAIL_INDEX_V((int)p_side, 4, 0);
+
+ if (vertical) {
+ if (p_side == SIDE_LEFT || p_side == SIDE_RIGHT) {
+ return thickness / 2.0;
+ }
+ } else if (p_side == SIDE_TOP || p_side == SIDE_BOTTOM) {
+ return thickness / 2.0;
+ }
+
+ return 0;
}
Size2 StyleBoxLine::get_center_size() const {
diff --git a/scene/resources/text_line.cpp b/scene/resources/text_line.cpp
index ed69c093cf..925867a1f2 100644
--- a/scene/resources/text_line.cpp
+++ b/scene/resources/text_line.cpp
@@ -167,6 +167,7 @@ void TextLine::set_bidi_override(const Vector<Vector2i> &p_override) {
}
bool TextLine::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) {
+ ERR_FAIL_COND_V(p_fonts.is_null(), false);
bool res = TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language);
spacing_top = p_fonts->get_spacing(Font::SPACING_TOP);
spacing_bottom = p_fonts->get_spacing(Font::SPACING_BOTTOM);
diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp
index 94957df510..444a4bb22a 100644
--- a/scene/resources/text_paragraph.cpp
+++ b/scene/resources/text_paragraph.cpp
@@ -243,6 +243,7 @@ TextServer::Orientation TextParagraph::get_orientation() const {
}
bool TextParagraph::set_dropcap(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Rect2 &p_dropcap_margins, const Dictionary &p_opentype_features, const String &p_language) {
+ ERR_FAIL_COND_V(p_fonts.is_null(), false);
TS->shaped_text_clear(dropcap_rid);
dropcap_margins = p_dropcap_margins;
bool res = TS->shaped_text_add_string(dropcap_rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language);
@@ -257,6 +258,7 @@ void TextParagraph::clear_dropcap() {
}
bool TextParagraph::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) {
+ ERR_FAIL_COND_V(p_fonts.is_null(), false);
bool res = TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language);
spacing_top = p_fonts->get_spacing(Font::SPACING_TOP);
spacing_bottom = p_fonts->get_spacing(Font::SPACING_BOTTOM);
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 1ecc968176..8cccf81659 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -736,7 +736,7 @@ StreamTexture2D::~StreamTexture2D() {
}
}
-RES ResourceFormatLoaderStreamTexture2D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderStreamTexture2D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
Ref<StreamTexture2D> st;
st.instance();
Error err = st->load(p_path);
@@ -1034,7 +1034,7 @@ StreamTexture3D::~StreamTexture3D() {
/////////////////////////////
-RES ResourceFormatLoaderStreamTexture3D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderStreamTexture3D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
Ref<StreamTexture3D> st;
st.instance();
Error err = st->load(p_path);
@@ -2432,7 +2432,7 @@ StreamTextureLayered::~StreamTextureLayered() {
/////////////////////////////////////////////////
-RES ResourceFormatLoaderStreamTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderStreamTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
Ref<StreamTextureLayered> st;
if (p_path.get_extension().to_lower() == "stexarray") {
Ref<StreamTexture2DArray> s;
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index ce2cf44530..a0d917fd86 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -211,7 +211,7 @@ public:
class ResourceFormatLoaderStreamTexture2D : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
@@ -513,7 +513,7 @@ public:
class ResourceFormatLoaderStreamTextureLayered : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
@@ -631,7 +631,7 @@ public:
class ResourceFormatLoaderStreamTexture3D : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp
index a6e261000f..0405ea98bb 100644
--- a/scene/resources/theme.cpp
+++ b/scene/resources/theme.cpp
@@ -930,6 +930,9 @@ void Theme::get_type_list(List<StringName> *p_list) const {
}
}
+void Theme::reset_state() {
+ clear();
+}
void Theme::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_icon", "name", "node_type", "texture"), &Theme::set_icon);
ClassDB::bind_method(D_METHOD("get_icon", "name", "node_type"), &Theme::get_icon);
diff --git a/scene/resources/theme.h b/scene/resources/theme.h
index c802ba2536..35481126ea 100644
--- a/scene/resources/theme.h
+++ b/scene/resources/theme.h
@@ -80,6 +80,8 @@ protected:
static void _bind_methods();
+ virtual void reset_state() override;
+
public:
static Ref<Theme> get_default();
static void set_default(const Ref<Theme> &p_default);
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 406137b387..84be69d0d6 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -1076,6 +1076,10 @@ int TileSet::find_tile_by_name(const String &p_name) const {
return -1;
}
+void TileSet::reset_state() {
+ clear();
+}
+
void TileSet::clear() {
tile_map.clear();
notify_property_list_changed();
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index 210520350f..0a8721f35b 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -136,6 +136,8 @@ protected:
static void _bind_methods();
+ virtual void reset_state() override;
+
public:
void create_tile(int p_id);
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 73fd01fb00..a296156bf5 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -675,6 +675,8 @@ void VisualShader::get_node_connections(Type p_type, List<Connection> *r_connect
}
void VisualShader::set_mode(Mode p_mode) {
+ ERR_FAIL_INDEX_MSG(p_mode, Mode::MODE_MAX, vformat("Invalid shader mode: %d.", p_mode));
+
if (shader_mode == p_mode) {
return;
}
@@ -1095,6 +1097,12 @@ bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const {
return false;
}
+void VisualShader::reset_state() {
+#ifndef _MSC_VER
+#warning everything needs to be cleared here
+#endif
+ emit_changed();
+}
void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
//mode
p_list->push_back(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Node3D,CanvasItem,Particles,Sky"));
@@ -1591,6 +1599,7 @@ void VisualShader::_queue_update() {
}
void VisualShader::_input_type_changed(Type p_type, int p_id) {
+ ERR_FAIL_INDEX(p_type, TYPE_MAX);
//erase connections using this input, as type changed
Graph *g = &graph[p_type];
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index 57732cc7e3..f3f3caf15e 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -126,6 +126,8 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ virtual void reset_state() override;
+
public: // internal methods
void set_shader_type(Type p_type);
Type get_shader_type() const;