summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/animation/tween.cpp35
-rw-r--r--scene/animation/tween.h6
-rw-r--r--scene/gui/code_edit.cpp30
-rw-r--r--scene/gui/code_edit.h2
-rw-r--r--scene/gui/label.cpp77
-rw-r--r--scene/gui/scroll_bar.cpp26
-rw-r--r--scene/gui/scroll_bar.h3
-rw-r--r--scene/gui/text_edit.cpp15
-rw-r--r--scene/gui/text_edit.h3
-rw-r--r--scene/gui/tree.cpp11
-rw-r--r--scene/main/scene_tree.cpp4
-rw-r--r--scene/main/viewport.cpp11
-rw-r--r--scene/main/viewport.h2
-rw-r--r--scene/resources/default_theme/default_theme.cpp4
-rw-r--r--scene/resources/mesh_library.cpp19
-rw-r--r--scene/resources/mesh_library.h3
-rw-r--r--scene/resources/texture.cpp24
-rw-r--r--scene/resources/texture.h2
18 files changed, 208 insertions, 69 deletions
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index 542011618d..3018fd3ae6 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -36,6 +36,10 @@ void Tweener::set_tween(Ref<Tween> p_tween) {
tween = p_tween;
}
+void Tweener::clear_tween() {
+ tween.unref();
+}
+
void Tweener::_bind_methods() {
ADD_SIGNAL(MethodInfo("finished"));
}
@@ -53,7 +57,7 @@ void Tween::start_tweeners() {
Ref<PropertyTweener> Tween::tween_property(Object *p_target, NodePath p_property, Variant p_to, float p_duration) {
ERR_FAIL_NULL_V(p_target, nullptr);
- ERR_FAIL_COND_V_MSG(invalid, nullptr, "Tween was created outside the scene tree, can't use Tweeners.");
+ ERR_FAIL_COND_V_MSG(!valid, nullptr, "Tween invalid. Either finished or created outside scene tree.");
ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first.");
Ref<PropertyTweener> tweener = memnew(PropertyTweener(p_target, p_property, p_to, p_duration));
@@ -62,7 +66,7 @@ Ref<PropertyTweener> Tween::tween_property(Object *p_target, NodePath p_property
}
Ref<IntervalTweener> Tween::tween_interval(float p_time) {
- ERR_FAIL_COND_V_MSG(invalid, nullptr, "Tween was created outside the scene tree, can't use Tweeners.");
+ ERR_FAIL_COND_V_MSG(!valid, nullptr, "Tween invalid. Either finished or created outside scene tree.");
ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first.");
Ref<IntervalTweener> tweener = memnew(IntervalTweener(p_time));
@@ -71,7 +75,7 @@ Ref<IntervalTweener> Tween::tween_interval(float p_time) {
}
Ref<CallbackTweener> Tween::tween_callback(Callable p_callback) {
- ERR_FAIL_COND_V_MSG(invalid, nullptr, "Tween was created outside the scene tree, can't use Tweeners.");
+ ERR_FAIL_COND_V_MSG(!valid, nullptr, "Tween invalid. Either finished or created outside scene tree.");
ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first.");
Ref<CallbackTweener> tweener = memnew(CallbackTweener(p_callback));
@@ -80,7 +84,7 @@ Ref<CallbackTweener> Tween::tween_callback(Callable p_callback) {
}
Ref<MethodTweener> Tween::tween_method(Callable p_callback, float p_from, float p_to, float p_duration) {
- ERR_FAIL_COND_V_MSG(invalid, nullptr, "Tween was created outside the scene tree, can't use Tweeners.");
+ ERR_FAIL_COND_V_MSG(!valid, nullptr, "Tween invalid. Either finished or created outside scene tree.");
ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first.");
Ref<MethodTweener> tweener = memnew(MethodTweener(p_callback, p_from, p_to, p_duration));
@@ -88,9 +92,7 @@ Ref<MethodTweener> Tween::tween_method(Callable p_callback, float p_from, float
return tweener;
}
-Ref<Tween> Tween::append(Ref<Tweener> p_tweener) {
- ERR_FAIL_COND_V_MSG(invalid, nullptr, "Tween was created outside the scene tree, can't use Tweeners.");
- ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first.");
+void Tween::append(Ref<Tweener> p_tweener) {
p_tweener->set_tween(this);
if (parallel_enabled) {
@@ -102,8 +104,6 @@ Ref<Tween> Tween::append(Ref<Tweener> p_tweener) {
tweeners.resize(current_step + 1);
tweeners.write[current_step].push_back(p_tweener);
-
- return this;
}
void Tween::stop() {
@@ -117,7 +117,7 @@ void Tween::pause() {
}
void Tween::play() {
- ERR_FAIL_COND_MSG(invalid, "Tween invalid, can't play.");
+ ERR_FAIL_COND_MSG(!valid, "Tween invalid. Either finished or created outside scene tree.");
ERR_FAIL_COND_MSG(dead, "Can't play finished Tween, use stop() first to reset its state.");
running = true;
}
@@ -132,11 +132,22 @@ bool Tween::is_running() {
}
void Tween::set_valid(bool p_valid) {
- invalid = !p_valid;
+ valid = p_valid;
}
bool Tween::is_valid() {
- return invalid;
+ return valid;
+}
+
+void Tween::clear() {
+ valid = false;
+
+ for (List<Ref<Tweener>> &step : tweeners) {
+ for (Ref<Tweener> &tweener : step) {
+ tweener->clear_tween();
+ }
+ }
+ tweeners.clear();
}
Ref<Tween> Tween::bind_node(Node *p_node) {
diff --git a/scene/animation/tween.h b/scene/animation/tween.h
index 947cdb7c2d..953d573539 100644
--- a/scene/animation/tween.h
+++ b/scene/animation/tween.h
@@ -43,6 +43,7 @@ public:
virtual void set_tween(Ref<Tween> p_tween);
virtual void start() = 0;
virtual bool step(float &r_delta) = 0;
+ void clear_tween();
protected:
static void _bind_methods();
@@ -111,7 +112,7 @@ private:
bool started = false;
bool running = true;
bool dead = false;
- bool invalid = true;
+ bool valid = false;
bool default_parallel = false;
bool parallel_enabled = false;
@@ -128,7 +129,7 @@ public:
Ref<IntervalTweener> tween_interval(float p_time);
Ref<CallbackTweener> tween_callback(Callable p_callback);
Ref<MethodTweener> tween_method(Callable p_callback, float p_from, float p_to, float p_duration);
- Ref<Tween> append(Ref<Tweener> p_tweener);
+ void append(Ref<Tweener> p_tweener);
bool custom_step(float p_delta);
void stop();
@@ -139,6 +140,7 @@ public:
bool is_running();
void set_valid(bool p_valid);
bool is_valid();
+ void clear();
Ref<Tween> bind_node(Node *p_node);
Ref<Tween> set_process_mode(TweenProcessMode p_mode);
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index d05762b6c0..3beff57027 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -654,7 +654,7 @@ void CodeEdit::_backspace_internal() {
// For space indentation we need to do a simple unindent if there are no chars to the left, acting in the
// same way as tabs.
if (indent_using_spaces && cc != 0) {
- if (get_first_non_whitespace_column(cl) > cc) {
+ if (get_first_non_whitespace_column(cl) >= cc) {
prev_column = cc - _calculate_spaces_till_next_left_indent(cc);
prev_line = cl;
}
@@ -987,10 +987,10 @@ void CodeEdit::_new_line(bool p_split_current_line, bool p_above) {
/* No need to move the brace below if we are not taking the text with us. */
if (p_split_current_line) {
brace_indent = true;
- ins += "\n" + ins.substr(1, ins.length() - 2);
+ ins += "\n" + ins.substr(indent_text.size(), ins.length() - 2);
} else {
brace_indent = false;
- ins = "\n" + ins.substr(1, ins.length() - 2);
+ ins = "\n" + ins.substr(indent_text.size(), ins.length() - 2);
}
}
}
@@ -1407,9 +1407,14 @@ void CodeEdit::fold_line(int p_line) {
int in_string = (in_comment == -1) ? is_in_string(p_line) : -1;
if (in_string != -1 || in_comment != -1) {
end_line = get_delimiter_end_position(p_line, get_line(p_line).size() - 1).y;
- /* End line is the same therefore we have a block. */
+ /* End line is the same therefore we have a block of single line delimiters. */
if (end_line == p_line) {
for (int i = p_line + 1; i <= line_count; i++) {
+ if (i == line_count) {
+ end_line = line_count;
+ break;
+ }
+
if ((in_string != -1 && is_in_string(i) == -1) || (in_comment != -1 && is_in_comment(i) == -1)) {
end_line = i - 1;
break;
@@ -1617,7 +1622,8 @@ Point2 CodeEdit::get_delimiter_start_position(int p_line, int p_column) const {
}
/* Region was found on this line and is not a multiline continuation. */
- if (start_position.x != -1 && start_position.x != get_line(p_line).length() + 1) {
+ int line_length = get_line(p_line).length();
+ if (start_position.x != -1 && line_length > 0 && start_position.x != line_length + 1) {
start_position.y = p_line;
return start_position;
}
@@ -1636,7 +1642,8 @@ Point2 CodeEdit::get_delimiter_start_position(int p_line, int p_column) const {
start_position.x = delimiter_cache[i].back()->key();
/* Make sure it's not a multiline continuation. */
- if (start_position.x != get_line(i).length() + 1) {
+ line_length = get_line(i).length();
+ if (line_length > 0 && start_position.x != line_length + 1) {
break;
}
}
@@ -2562,7 +2569,10 @@ int CodeEdit::_is_in_delimiter(int p_line, int p_column, DelimiterType p_type) c
}
void CodeEdit::_add_delimiter(const String &p_start_key, const String &p_end_key, bool p_line_only, DelimiterType p_type) {
- if (p_start_key.length() > 0) {
+ // If we are the editor allow "null" as a valid start key, otherwise users cannot add delimiters via the inspector.
+ if (!(Engine::get_singleton()->is_editor_hint() && p_start_key == "null")) {
+ ERR_FAIL_COND_MSG(p_start_key.is_empty(), "delimiter start key cannot be empty");
+
for (int i = 0; i < p_start_key.length(); i++) {
ERR_FAIL_COND_MSG(!is_symbol(p_start_key[i]), "delimiter must start with a symbol");
}
@@ -2627,7 +2637,11 @@ void CodeEdit::_set_delimiters(const TypedArray<String> &p_delimiters, Delimiter
_clear_delimiters(p_type);
for (int i = 0; i < p_delimiters.size(); i++) {
- String key = p_delimiters[i].is_null() ? "" : p_delimiters[i];
+ String key = p_delimiters[i];
+
+ if (key.is_empty()) {
+ continue;
+ }
const String start_key = key.get_slice(" ", 0);
const String end_key = key.get_slice_count(" ") > 1 ? key.get_slice(" ", 1) : String();
diff --git a/scene/gui/code_edit.h b/scene/gui/code_edit.h
index 4fbb5194e6..740548d559 100644
--- a/scene/gui/code_edit.h
+++ b/scene/gui/code_edit.h
@@ -248,7 +248,6 @@ private:
void _text_changed();
protected:
- void gui_input(const Ref<InputEvent> &p_gui_input) override;
void _notification(int p_what);
static void _bind_methods();
@@ -265,6 +264,7 @@ protected:
public:
/* General overrides */
+ virtual void gui_input(const Ref<InputEvent> &p_gui_input) override;
virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override;
/* Indent management */
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index 3f87003423..5600816b2d 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -227,7 +227,15 @@ void Label::_update_visible() {
}
}
-inline void draw_glyph(const TextServer::Glyph &p_gl, const RID &p_canvas, const Color &p_font_color, const Color &p_font_shadow_color, const Color &p_font_outline_color, const int &p_shadow_outline_size, const int &p_outline_size, const Vector2 &p_ofs, const Vector2 &shadow_ofs) {
+inline void draw_glyph(const TextServer::Glyph &p_gl, const RID &p_canvas, const Color &p_font_color, const Vector2 &p_ofs) {
+ if (p_gl.font_rid != RID()) {
+ TS->font_draw_glyph(p_gl.font_rid, p_canvas, p_gl.font_size, p_ofs + Vector2(p_gl.x_off, p_gl.y_off), p_gl.index, p_font_color);
+ } else {
+ TS->draw_hex_code_box(p_canvas, p_gl.font_size, p_ofs + Vector2(p_gl.x_off, p_gl.y_off), p_gl.index, p_font_color);
+ }
+}
+
+inline void draw_glyph_outline(const TextServer::Glyph &p_gl, const RID &p_canvas, const Color &p_font_color, const Color &p_font_shadow_color, const Color &p_font_outline_color, const int &p_shadow_outline_size, const int &p_outline_size, const Vector2 &p_ofs, const Vector2 &shadow_ofs) {
if (p_gl.font_rid != RID()) {
if (p_font_shadow_color.a > 0) {
TS->font_draw_glyph(p_gl.font_rid, p_canvas, p_gl.font_size, p_ofs + Vector2(p_gl.x_off, p_gl.y_off) + shadow_ofs, p_gl.index, p_font_shadow_color);
@@ -240,9 +248,6 @@ inline void draw_glyph(const TextServer::Glyph &p_gl, const RID &p_canvas, const
if (p_font_outline_color.a != 0.0 && p_outline_size > 0) {
TS->font_draw_glyph_outline(p_gl.font_rid, p_canvas, p_gl.font_size, p_outline_size, p_ofs + Vector2(p_gl.x_off, p_gl.y_off), p_gl.index, p_font_outline_color);
}
- TS->font_draw_glyph(p_gl.font_rid, p_canvas, p_gl.font_size, p_ofs + Vector2(p_gl.x_off, p_gl.y_off), p_gl.index, p_font_color);
- } else {
- TS->draw_hex_code_box(p_canvas, p_gl.font_size, p_ofs + Vector2(p_gl.x_off, p_gl.y_off), p_gl.index, p_font_color);
}
}
@@ -385,12 +390,70 @@ void Label::_notification(int p_what) {
int gl_size = visual.size();
TextServer::TrimData trim_data = TS->shaped_text_get_trim_data(lines_rid[i]);
+ // Draw outline. Note: Do not merge this into the single loop with the main text, to prevent overlaps.
+ if (font_shadow_color.a > 0 || (font_outline_color.a != 0.0 && outline_size > 0)) {
+ Vector2 offset = ofs;
+ // Draw RTL ellipsis string when necessary.
+ if (rtl && trim_data.ellipsis_pos >= 0) {
+ for (int gl_idx = trim_data.ellipsis_glyph_buf.size() - 1; gl_idx >= 0; gl_idx--) {
+ for (int j = 0; j < trim_data.ellipsis_glyph_buf[gl_idx].repeat; j++) {
+ //Draw glyph outlines and shadow.
+ draw_glyph_outline(trim_data.ellipsis_glyph_buf[gl_idx], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, offset, shadow_ofs);
+ offset.x += trim_data.ellipsis_glyph_buf[gl_idx].advance;
+ }
+ }
+ }
+
+ // Draw main text.
+ for (int j = 0; j < gl_size; j++) {
+ for (int k = 0; k < glyphs[j].repeat; k++) {
+ if (visible_glyphs != -1) {
+ if ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
+ if (glyhps_drawn >= visible_glyphs) {
+ return;
+ }
+ }
+ }
+
+ // Trim when necessary.
+ if (trim_data.trim_pos >= 0) {
+ if (rtl) {
+ if (j < trim_data.trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
+ continue;
+ }
+ } else {
+ if (j >= trim_data.trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
+ break;
+ }
+ }
+ }
+
+ // Draw glyph outlines and shadow.
+ draw_glyph_outline(glyphs[j], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, offset, shadow_ofs);
+ offset.x += glyphs[j].advance;
+ glyhps_drawn++;
+ }
+ }
+ // Draw LTR ellipsis string when necessary.
+ if (!rtl && trim_data.ellipsis_pos >= 0) {
+ for (int gl_idx = 0; gl_idx < trim_data.ellipsis_glyph_buf.size(); gl_idx++) {
+ for (int j = 0; j < trim_data.ellipsis_glyph_buf[gl_idx].repeat; j++) {
+ //Draw glyph outlines and shadow.
+ draw_glyph_outline(trim_data.ellipsis_glyph_buf[gl_idx], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, offset, shadow_ofs);
+ offset.x += trim_data.ellipsis_glyph_buf[gl_idx].advance;
+ }
+ }
+ }
+ }
+
+ // Draw main text. Note: Do not merge this into the single loop with the outline, to prevent overlaps.
+
// Draw RTL ellipsis string when necessary.
if (rtl && trim_data.ellipsis_pos >= 0) {
for (int gl_idx = trim_data.ellipsis_glyph_buf.size() - 1; gl_idx >= 0; gl_idx--) {
for (int j = 0; j < trim_data.ellipsis_glyph_buf[gl_idx].repeat; j++) {
//Draw glyph outlines and shadow.
- draw_glyph(trim_data.ellipsis_glyph_buf[gl_idx], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, ofs, shadow_ofs);
+ draw_glyph(trim_data.ellipsis_glyph_buf[gl_idx], ci, font_color, ofs);
ofs.x += trim_data.ellipsis_glyph_buf[gl_idx].advance;
}
}
@@ -421,7 +484,7 @@ void Label::_notification(int p_what) {
}
// Draw glyph outlines and shadow.
- draw_glyph(glyphs[j], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, ofs, shadow_ofs);
+ draw_glyph(glyphs[j], ci, font_color, ofs);
ofs.x += glyphs[j].advance;
glyhps_drawn++;
}
@@ -431,7 +494,7 @@ void Label::_notification(int p_what) {
for (int gl_idx = 0; gl_idx < trim_data.ellipsis_glyph_buf.size(); gl_idx++) {
for (int j = 0; j < trim_data.ellipsis_glyph_buf[gl_idx].repeat; j++) {
//Draw glyph outlines and shadow.
- draw_glyph(trim_data.ellipsis_glyph_buf[gl_idx], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, ofs, shadow_ofs);
+ draw_glyph(trim_data.ellipsis_glyph_buf[gl_idx], ci, font_color, ofs);
ofs.x += trim_data.ellipsis_glyph_buf[gl_idx].advance;
}
}
diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp
index 08bcb0bdda..4edf373fbf 100644
--- a/scene/gui/scroll_bar.cpp
+++ b/scene/gui/scroll_bar.cpp
@@ -80,12 +80,16 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) {
double total = orientation == VERTICAL ? get_size().height : get_size().width;
if (ofs < decr_size) {
+ decr_active = true;
set_value(get_value() - (custom_step >= 0 ? custom_step : get_step()));
+ update();
return;
}
if (ofs > total - incr_size) {
+ incr_active = true;
set_value(get_value() + (custom_step >= 0 ? custom_step : get_step()));
+ update();
return;
}
@@ -130,6 +134,8 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) {
}
} else {
+ incr_active = false;
+ decr_active = false;
drag.active = false;
update();
}
@@ -215,8 +221,24 @@ void ScrollBar::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW) {
RID ci = get_canvas_item();
- Ref<Texture2D> decr = highlight == HIGHLIGHT_DECR ? get_theme_icon(SNAME("decrement_highlight")) : get_theme_icon(SNAME("decrement"));
- Ref<Texture2D> incr = highlight == HIGHLIGHT_INCR ? get_theme_icon(SNAME("increment_highlight")) : get_theme_icon(SNAME("increment"));
+ Ref<Texture2D> decr, incr;
+
+ if (decr_active) {
+ decr = get_theme_icon(SNAME("decrement_pressed"));
+ } else if (highlight == HIGHLIGHT_DECR) {
+ decr = get_theme_icon(SNAME("decrement_highlight"));
+ } else {
+ decr = get_theme_icon(SNAME("decrement"));
+ }
+
+ if (incr_active) {
+ incr = get_theme_icon(SNAME("increment_pressed"));
+ } else if (highlight == HIGHLIGHT_INCR) {
+ incr = get_theme_icon(SNAME("increment_highlight"));
+ } else {
+ incr = get_theme_icon(SNAME("increment"));
+ }
+
Ref<StyleBox> bg = has_focus() ? get_theme_stylebox(SNAME("scroll_focus")) : get_theme_stylebox(SNAME("scroll"));
Ref<StyleBox> grabber;
diff --git a/scene/gui/scroll_bar.h b/scene/gui/scroll_bar.h
index fbc035397f..574d17ee20 100644
--- a/scene/gui/scroll_bar.h
+++ b/scene/gui/scroll_bar.h
@@ -51,6 +51,9 @@ class ScrollBar : public Range {
HighlightStatus highlight = HIGHLIGHT_NONE;
+ bool incr_active = false;
+ bool decr_active = false;
+
struct Drag {
bool active = false;
float pos_at_click = 0.0;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index f64c07df76..06dfc31621 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -2610,10 +2610,10 @@ void TextEdit::set_text(const String &p_text) {
set_caret_column(0);
begin_complex_operation();
+ deselect();
_remove_text(0, 0, MAX(0, get_line_count() - 1), MAX(get_line(MAX(get_line_count() - 1, 0)).size() - 1, 0));
insert_text_at_caret(p_text);
end_complex_operation();
- selection.active = false;
}
set_caret_line(0);
@@ -2731,6 +2731,8 @@ void TextEdit::insert_line_at(int p_at, const String &p_text) {
}
void TextEdit::insert_text_at_caret(const String &p_text) {
+ begin_complex_operation();
+
delete_selection();
int new_column, new_line;
@@ -2740,6 +2742,8 @@ void TextEdit::insert_text_at_caret(const String &p_text) {
set_caret_line(new_line, false);
set_caret_column(new_column);
update();
+
+ end_complex_operation();
}
void TextEdit::remove_text(int p_from_line, int p_from_column, int p_to_line, int p_to_column) {
@@ -3024,13 +3028,20 @@ void TextEdit::menu_option(int p_option) {
/* Versioning */
void TextEdit::begin_complex_operation() {
_push_current_op();
- next_operation_is_complex = true;
+ if (complex_operation_count == 0) {
+ next_operation_is_complex = true;
+ }
+ complex_operation_count++;
}
void TextEdit::end_complex_operation() {
_push_current_op();
ERR_FAIL_COND(undo_stack.size() == 0);
+ complex_operation_count = MAX(complex_operation_count - 1, 0);
+ if (complex_operation_count > 0) {
+ return;
+ }
if (undo_stack.back()->get().chain_forward) {
undo_stack.back()->get().chain_forward = false;
return;
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index e996bba983..b1226f2aff 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -304,6 +304,7 @@ private:
bool undo_enabled = true;
int undo_stack_max_size = 50;
+ int complex_operation_count = 0;
bool next_operation_is_complex = false;
TextOperation current_op;
@@ -545,7 +546,6 @@ private:
protected:
void _notification(int p_what);
- virtual void gui_input(const Ref<InputEvent> &p_gui_input) override;
static void _bind_methods();
@@ -594,6 +594,7 @@ protected:
public:
/* General overrides. */
+ virtual void gui_input(const Ref<InputEvent> &p_gui_input) override;
virtual Size2 get_minimum_size() const override;
virtual bool is_text_field() const override;
virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override;
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index cb990892ed..c4dfbc0d4e 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -2339,13 +2339,22 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
cache.click_type = Cache::CLICK_NONE;
return -1;
}
+
+ // Make sure the click is correct.
+ Point2 click_pos = get_global_mouse_position() - get_global_position();
+ if (!get_item_at_position(click_pos)) {
+ pressed_button = -1;
+ cache.click_type = Cache::CLICK_NONE;
+ return -1;
+ }
+
pressed_button = j;
cache.click_type = Cache::CLICK_BUTTON;
cache.click_index = j;
cache.click_id = c.buttons[j].id;
cache.click_item = p_item;
cache.click_column = col;
- cache.click_pos = get_global_mouse_position() - get_global_position();
+ cache.click_pos = click_pos;
update();
//emit_signal(SNAME("button_pressed"));
return -1;
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index bef7ecb462..e1b1b356a9 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -544,7 +544,7 @@ void SceneTree::process_tweens(float p_delta, bool p_physics) {
}
if (!E->get()->step(p_delta)) {
- E->get()->set_valid(false);
+ E->get()->clear();
tweens.erase(E);
}
if (E == L) {
@@ -1337,7 +1337,7 @@ SceneTree::SceneTree() {
current_scene = nullptr;
const int msaa_mode = GLOBAL_DEF("rendering/anti_aliasing/quality/msaa", 0);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/msaa", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/msaa", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Fast),4× (Average),8× (Slow),16× (Slower)")));
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/msaa", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/msaa", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)")));
root->set_msaa(Viewport::MSAA(msaa_mode));
const int ssaa_mode = GLOBAL_DEF("rendering/anti_aliasing/quality/screen_space_aa", 0);
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index eea5ca9895..fb86d37280 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -823,7 +823,9 @@ Rect2 Viewport::get_visible_rect() const {
}
void Viewport::_update_listener_2d() {
- AudioServer::get_singleton()->notify_listener_changed();
+ if (AudioServer::get_singleton()) {
+ AudioServer::get_singleton()->notify_listener_changed();
+ }
}
void Viewport::set_as_audio_listener_2d(bool p_enable) {
@@ -3063,7 +3065,9 @@ bool Viewport::is_audio_listener_3d() const {
}
void Viewport::_update_listener_3d() {
- AudioServer::get_singleton()->notify_listener_changed();
+ if (AudioServer::get_singleton()) {
+ AudioServer::get_singleton()->notify_listener_changed();
+ }
}
void Viewport::_listener_transform_3d_changed_notify() {
@@ -3594,7 +3598,7 @@ void Viewport::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_2d_transforms_to_pixel"), "set_snap_2d_transforms_to_pixel", "is_snap_2d_transforms_to_pixel_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_2d_vertices_to_pixel"), "set_snap_2d_vertices_to_pixel", "is_snap_2d_vertices_to_pixel_enabled");
ADD_GROUP("Rendering", "");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Fast),4× (Average),8× (Slow),16× (Slower)")), "set_msaa", "get_msaa");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)")), "set_msaa", "get_msaa");
ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast)"), "set_screen_space_aa", "get_screen_space_aa");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "is_using_debanding");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_occlusion_culling"), "set_use_occlusion_culling", "is_using_occlusion_culling");
@@ -3646,7 +3650,6 @@ void Viewport::_bind_methods() {
BIND_ENUM_CONSTANT(MSAA_2X);
BIND_ENUM_CONSTANT(MSAA_4X);
BIND_ENUM_CONSTANT(MSAA_8X);
- BIND_ENUM_CONSTANT(MSAA_16X);
BIND_ENUM_CONSTANT(MSAA_MAX);
BIND_ENUM_CONSTANT(SCREEN_SPACE_AA_DISABLED);
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 06efd27073..bfb52c4b98 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -113,7 +113,7 @@ public:
MSAA_2X,
MSAA_4X,
MSAA_8X,
- MSAA_16X,
+ // 16x MSAA is not supported due to its high cost and driver bugs.
MSAA_MAX
};
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 4845c556c6..fa3824e6eb 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -502,8 +502,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("increment", "HScrollBar", empty_icon);
theme->set_icon("increment_highlight", "HScrollBar", empty_icon);
+ theme->set_icon("increment_pressed", "HScrollBar", empty_icon);
theme->set_icon("decrement", "HScrollBar", empty_icon);
theme->set_icon("decrement_highlight", "HScrollBar", empty_icon);
+ theme->set_icon("decrement_pressed", "HScrollBar", empty_icon);
// VScrollBar
@@ -515,8 +517,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("increment", "VScrollBar", empty_icon);
theme->set_icon("increment_highlight", "VScrollBar", empty_icon);
+ theme->set_icon("increment_pressed", "VScrollBar", empty_icon);
theme->set_icon("decrement", "VScrollBar", empty_icon);
theme->set_icon("decrement_highlight", "VScrollBar", empty_icon);
+ theme->set_icon("decrement_pressed", "VScrollBar", empty_icon);
// HSlider
diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp
index 33c9ca6d1e..cfb7c3e037 100644
--- a/scene/resources/mesh_library.cpp
+++ b/scene/resources/mesh_library.cpp
@@ -43,6 +43,8 @@ bool MeshLibrary::_set(const StringName &p_name, const Variant &p_value) {
set_item_name(idx, p_value);
} else if (what == "mesh") {
set_item_mesh(idx, p_value);
+ } else if (what == "mesh_transform") {
+ set_item_mesh_transform(idx, p_value);
} else if (what == "shape") {
Vector<ShapeData> shapes;
ShapeData sd;
@@ -77,6 +79,8 @@ bool MeshLibrary::_get(const StringName &p_name, Variant &r_ret) const {
r_ret = get_item_name(idx);
} else if (what == "mesh") {
r_ret = get_item_mesh(idx);
+ } else if (what == "mesh_transform") {
+ r_ret = get_item_mesh_transform(idx);
} else if (what == "shapes") {
r_ret = _get_item_shapes(idx);
} else if (what == "navmesh") {
@@ -127,6 +131,14 @@ void MeshLibrary::set_item_mesh(int p_item, const Ref<Mesh> &p_mesh) {
notify_property_list_changed();
}
+void MeshLibrary::set_item_mesh_transform(int p_item, const Transform3D &p_transform) {
+ ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
+ item_map[p_item].mesh_transform = p_transform;
+ notify_change_to_owners();
+ emit_changed();
+ notify_property_list_changed();
+}
+
void MeshLibrary::set_item_shapes(int p_item, const Vector<ShapeData> &p_shapes) {
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].shapes = p_shapes;
@@ -170,6 +182,11 @@ Ref<Mesh> MeshLibrary::get_item_mesh(int p_item) const {
return item_map[p_item].mesh;
}
+Transform3D MeshLibrary::get_item_mesh_transform(int p_item) const {
+ ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Transform3D(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
+ return item_map[p_item].mesh_transform;
+}
+
Vector<MeshLibrary::ShapeData> MeshLibrary::get_item_shapes(int p_item) const {
ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Vector<ShapeData>(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
return item_map[p_item].shapes;
@@ -271,12 +288,14 @@ 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);
ClassDB::bind_method(D_METHOD("set_item_mesh", "id", "mesh"), &MeshLibrary::set_item_mesh);
+ ClassDB::bind_method(D_METHOD("set_item_mesh_transform", "id", "mesh_transform"), &MeshLibrary::set_item_mesh_transform);
ClassDB::bind_method(D_METHOD("set_item_navmesh", "id", "navmesh"), &MeshLibrary::set_item_navmesh);
ClassDB::bind_method(D_METHOD("set_item_navmesh_transform", "id", "navmesh"), &MeshLibrary::set_item_navmesh_transform);
ClassDB::bind_method(D_METHOD("set_item_shapes", "id", "shapes"), &MeshLibrary::_set_item_shapes);
ClassDB::bind_method(D_METHOD("set_item_preview", "id", "texture"), &MeshLibrary::set_item_preview);
ClassDB::bind_method(D_METHOD("get_item_name", "id"), &MeshLibrary::get_item_name);
ClassDB::bind_method(D_METHOD("get_item_mesh", "id"), &MeshLibrary::get_item_mesh);
+ ClassDB::bind_method(D_METHOD("get_item_mesh_transform", "id"), &MeshLibrary::get_item_mesh_transform);
ClassDB::bind_method(D_METHOD("get_item_navmesh", "id"), &MeshLibrary::get_item_navmesh);
ClassDB::bind_method(D_METHOD("get_item_navmesh_transform", "id"), &MeshLibrary::get_item_navmesh_transform);
ClassDB::bind_method(D_METHOD("get_item_shapes", "id"), &MeshLibrary::_get_item_shapes);
diff --git a/scene/resources/mesh_library.h b/scene/resources/mesh_library.h
index 1e8a6bf3ff..c25df757e9 100644
--- a/scene/resources/mesh_library.h
+++ b/scene/resources/mesh_library.h
@@ -52,6 +52,7 @@ public:
Vector<ShapeData> shapes;
Ref<Texture2D> preview;
Transform3D navmesh_transform;
+ Transform3D mesh_transform;
Ref<NavigationMesh> navmesh;
};
@@ -72,12 +73,14 @@ public:
void create_item(int p_item);
void set_item_name(int p_item, const String &p_name);
void set_item_mesh(int p_item, const Ref<Mesh> &p_mesh);
+ void set_item_mesh_transform(int p_item, const Transform3D &p_transform);
void set_item_navmesh(int p_item, const Ref<NavigationMesh> &p_navmesh);
void set_item_navmesh_transform(int p_item, const Transform3D &p_transform);
void set_item_shapes(int p_item, const Vector<ShapeData> &p_shapes);
void set_item_preview(int p_item, const Ref<Texture2D> &p_preview);
String get_item_name(int p_item) const;
Ref<Mesh> get_item_mesh(int p_item) const;
+ Transform3D get_item_mesh_transform(int p_item) const;
Ref<NavigationMesh> get_item_navmesh(int p_item) const;
Transform3D get_item_navmesh_transform(int p_item) const;
Vector<ShapeData> get_item_shapes(int p_item) const;
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 063a13efc0..3dc32632cc 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -131,25 +131,6 @@ void ImageTexture::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, ""));
}
-void ImageTexture::_reload_hook(const RID &p_hook) {
- String path = get_path();
- if (!path.is_resource_file()) {
- return;
- }
-
- Ref<Image> img;
- img.instantiate();
- Error err = ImageLoader::load_image(path, img);
-
- ERR_FAIL_COND_MSG(err != OK, "Cannot load image from path '" + path + "'.");
-
- RID new_texture = RenderingServer::get_singleton()->texture_2d_create(img);
- RenderingServer::get_singleton()->texture_replace(texture, new_texture);
-
- notify_property_list_changed();
- emit_changed();
-}
-
void ImageTexture::create_from_image(const Ref<Image> &p_image) {
ERR_FAIL_COND_MSG(p_image.is_null() || p_image->is_empty(), "Invalid image");
w = p_image->get_width();
@@ -192,10 +173,6 @@ void ImageTexture::update(const Ref<Image> &p_image) {
image_stored = true;
}
-void ImageTexture::_resource_path_changed() {
- String path = get_path();
-}
-
Ref<Image> ImageTexture::get_image() const {
if (image_stored) {
return RenderingServer::get_singleton()->texture_2d_get(texture);
@@ -303,7 +280,6 @@ void ImageTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("update", "image"), &ImageTexture::update);
ClassDB::bind_method(D_METHOD("set_size_override", "size"), &ImageTexture::set_size_override);
- ClassDB::bind_method(D_METHOD("_reload_hook", "rid"), &ImageTexture::_reload_hook);
}
ImageTexture::ImageTexture() {}
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index f6b991c335..93f4e2de5a 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -98,8 +98,6 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
- void _reload_hook(const RID &p_hook);
- virtual void _resource_path_changed() override;
static void _bind_methods();
public: