summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/classes/LineEdit.xml3
-rw-r--r--doc/classes/RichTextLabel.xml3
-rw-r--r--doc/classes/TextEdit.xml3
-rw-r--r--doc/classes/TileMap.xml30
-rw-r--r--editor/code_editor.cpp1
-rw-r--r--editor/find_in_files.cpp63
-rw-r--r--editor/import/resource_importer_scene.cpp1
-rw-r--r--scene/2d/collision_object_2d.cpp4
-rw-r--r--scene/2d/physics_body_2d.cpp15
-rw-r--r--scene/2d/physics_body_2d.h2
-rw-r--r--scene/2d/tile_map.cpp121
-rw-r--r--scene/2d/tile_map.h17
-rw-r--r--scene/3d/collision_object_3d.cpp4
-rw-r--r--scene/gui/line_edit.cpp17
-rw-r--r--scene/gui/line_edit.h4
-rw-r--r--scene/gui/rich_text_label.cpp25
-rw-r--r--scene/gui/rich_text_label.h3
-rw-r--r--scene/gui/tab_bar.cpp2
-rw-r--r--scene/gui/text_edit.cpp20
-rw-r--r--scene/gui/text_edit.h4
-rw-r--r--scene/resources/material.cpp2
-rw-r--r--scene/resources/tile_set.cpp31
-rw-r--r--scene/resources/tile_set.h3
23 files changed, 309 insertions, 69 deletions
diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml
index a37bab9b11..f79ba5a16f 100644
--- a/doc/classes/LineEdit.xml
+++ b/doc/classes/LineEdit.xml
@@ -184,6 +184,9 @@
<member name="context_menu_enabled" type="bool" setter="set_context_menu_enabled" getter="is_context_menu_enabled" default="true">
If [code]true[/code], the context menu will appear when right-clicked.
</member>
+ <member name="deselect_on_focus_loss_enabled" type="bool" setter="set_deselect_on_focus_loss_enabled" getter="is_deselect_on_focus_loss_enabled" default="true">
+ If [code]true[/code], the selected text will be deselected when focus is lost.
+ </member>
<member name="draw_control_chars" type="bool" setter="set_draw_control_chars" getter="get_draw_control_chars" default="false">
If [code]true[/code], control characters are displayed.
</member>
diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml
index 9337339f73..0fd25615ba 100644
--- a/doc/classes/RichTextLabel.xml
+++ b/doc/classes/RichTextLabel.xml
@@ -379,6 +379,9 @@
The currently installed custom effects. This is an array of [RichTextEffect]s.
To add a custom effect, it's more convenient to use [method install_effect].
</member>
+ <member name="deselect_on_focus_loss_enabled" type="bool" setter="set_deselect_on_focus_loss_enabled" getter="is_deselect_on_focus_loss_enabled" default="true">
+ If [code]true[/code], the selected text will be deselected when focus is lost.
+ </member>
<member name="fit_content_height" type="bool" setter="set_fit_content_height" getter="is_fit_content_height_enabled" default="false">
If [code]true[/code], the label's height will be automatically updated to fit its content.
[b]Note:[/b] This property is used as a workaround to fix issues with [RichTextLabel] in [Container]s, but it's unreliable in some cases and will be removed in future versions.
diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml
index ba3394b54a..b8e2f7f03c 100644
--- a/doc/classes/TextEdit.xml
+++ b/doc/classes/TextEdit.xml
@@ -922,6 +922,9 @@
<member name="context_menu_enabled" type="bool" setter="set_context_menu_enabled" getter="is_context_menu_enabled" default="true">
If [code]true[/code], a right-click displays the context menu.
</member>
+ <member name="deselect_on_focus_loss_enabled" type="bool" setter="set_deselect_on_focus_loss_enabled" getter="is_deselect_on_focus_loss_enabled" default="true">
+ If [code]true[/code], the selected text will be deselected when focus is lost.
+ </member>
<member name="draw_control_chars" type="bool" setter="set_draw_control_chars" getter="get_draw_control_chars" default="false">
If [code]true[/code], control characters are displayed.
</member>
diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml
index 4ac5718e04..22d61c7285 100644
--- a/doc/classes/TileMap.xml
+++ b/doc/classes/TileMap.xml
@@ -16,6 +16,27 @@
<link title="2D Kinematic Character Demo">https://godotengine.org/asset-library/asset/113</link>
</tutorials>
<methods>
+ <method name="_tile_data_runtime_update" qualifiers="virtual">
+ <return type="void" />
+ <argument index="0" name="layer" type="int" />
+ <argument index="1" name="coords" type="Vector2i" />
+ <argument index="2" name="tile_data" type="TileData" />
+ <description>
+ Called with a TileData object about to be used internally by the TileMap, allowing its modification at runtime.
+ This method is only called if [method _use_tile_data_runtime_update] is implemented and returns [code]true[/code] for the given tile [code]coords[/coords] and [code]layer[/code].
+ [b]Warning:[/b] The [code]tile_data[/code] object's sub-resources are the same as the one in the TileSet. Modifying them might impact the whole TileSet. Instead, make sure to duplicate those resources.
+ [b]Note:[/b] If the properties of [code]tile_data[/code] object should change over time, use [method force_update] to trigger a TileMap update.
+ </description>
+ </method>
+ <method name="_use_tile_data_runtime_update" qualifiers="virtual">
+ <return type="bool" />
+ <argument index="0" name="layer" type="int" />
+ <argument index="1" name="coords" type="Vector2i" />
+ <description>
+ Should return [code]true[/code] if the tile at coordinates [code]coords[/coords] on layer [code]layer[/code] requires a runtime update.
+ [b]Warning:[/b] Make sure this function only return [code]true[/code] when needed. Any tile processed at runtime without a need for it will imply a significant performance penalty.
+ </description>
+ </method>
<method name="add_layer">
<return type="void" />
<argument index="0" name="to_position" type="int" />
@@ -42,6 +63,15 @@
Clears cells that do not exist in the tileset.
</description>
</method>
+ <method name="force_update">
+ <return type="void" />
+ <argument index="0" name="layer" type="int" default="-1" />
+ <description>
+ Triggers an update of the TileMap. If [code]layer[/code] is provided, only updates the given layer.
+ [b]Note:[/b] The TileMap node updates automatically when one of its properties is modified. A manual update is only needed if runtime modifications (implemented in [method _tile_data_runtime_update]) need to be applied.
+ [b]Warning:[/b] Updating the TileMap is a performance demanding task. Limit occurences of those updates to the minimum and limit the amount tiles they impact (by segregating tiles updated often to a dedicated layer for example).
+ </description>
+ </method>
<method name="get_cell_alternative_tile" qualifiers="const">
<return type="int" />
<argument index="0" name="layer" type="int" />
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index 7bf82fbd1b..1902ae66fb 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -1824,6 +1824,7 @@ CodeTextEditor::CodeTextEditor() {
text_editor->set_draw_line_numbers(true);
text_editor->set_highlight_matching_braces_enabled(true);
text_editor->set_auto_indent_enabled(true);
+ text_editor->set_deselect_on_focus_loss_enabled(false);
status_bar = memnew(HBoxContainer);
add_child(status_bar);
diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp
index 6ed12c31ff..56356ff25b 100644
--- a/editor/find_in_files.cpp
+++ b/editor/find_in_files.cpp
@@ -47,13 +47,13 @@
const char *FindInFiles::SIGNAL_RESULT_FOUND = "result_found";
const char *FindInFiles::SIGNAL_FINISHED = "finished";
-// TODO Would be nice in Vector and Vectors
+// TODO: Would be nice in Vector and Vectors.
template <typename T>
inline void pop_back(T &container) {
container.resize(container.size() - 1);
}
-// TODO Copied from TextEdit private, would be nice to extract it in a single place
+// TODO: Copied from TextEdit private, would be nice to extract it in a single place.
static bool is_text_char(char32_t c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
}
@@ -125,7 +125,7 @@ void FindInFiles::start() {
return;
}
- // Init search
+ // Init search.
_current_dir = "";
PackedStringArray init_folder;
init_folder.push_back(_root_dir);
@@ -145,14 +145,14 @@ void FindInFiles::stop() {
}
void FindInFiles::_process() {
- // This part can be moved to a thread if needed
+ // This part can be moved to a thread if needed.
OS &os = *OS::get_singleton();
uint64_t time_before = os.get_ticks_msec();
while (is_processing()) {
_iterate();
uint64_t elapsed = (os.get_ticks_msec() - time_before);
- if (elapsed > 8) { // Process again after waiting 8 ticks
+ if (elapsed > 8) { // Process again after waiting 8 ticks.
break;
}
}
@@ -160,12 +160,12 @@ void FindInFiles::_process() {
void FindInFiles::_iterate() {
if (_folders_stack.size() != 0) {
- // Scan folders first so we can build a list of files and have progress info later
+ // Scan folders first so we can build a list of files and have progress info later.
PackedStringArray &folders_to_scan = _folders_stack.write[_folders_stack.size() - 1];
if (folders_to_scan.size() != 0) {
- // Scan one folder below
+ // Scan one folder below.
String folder_name = folders_to_scan[folders_to_scan.size() - 1];
pop_back(folders_to_scan);
@@ -178,19 +178,19 @@ void FindInFiles::_iterate() {
_folders_stack.push_back(sub_dirs);
} else {
- // Go back one level
+ // Go back one level.
pop_back(_folders_stack);
_current_dir = _current_dir.get_base_dir();
if (_folders_stack.size() == 0) {
- // All folders scanned
+ // All folders scanned.
_initial_files_count = _files_to_scan.size();
}
}
} else if (_files_to_scan.size() != 0) {
- // Then scan files
+ // Then scan files.
String fpath = _files_to_scan[_files_to_scan.size() - 1];
pop_back(_files_to_scan);
@@ -228,12 +228,12 @@ void FindInFiles::_scan_dir(String path, PackedStringArray &out_folders) {
break;
}
- // If there is a .gdignore file in the directory, don't bother searching it
+ // If there is a .gdignore file in the directory, skip searching the directory.
if (file == ".gdignore") {
break;
}
- // Ignore special dirs (such as .git and project data directory)
+ // Ignore special directories (such as those beginning with . and the project data directory).
String project_data_dir_name = ProjectSettings::get_singleton()->get_project_data_dir_name();
if (file.begins_with(".") || file == project_data_dir_name) {
continue;
@@ -264,7 +264,7 @@ void FindInFiles::_scan_file(String fpath) {
int line_number = 0;
while (!f->eof_reached()) {
- // line number starts at 1
+ // Line number starts at 1.
++line_number;
int begin = 0;
@@ -331,7 +331,7 @@ FindInFilesDialog::FindInFilesDialog() {
_replace_text_line_edit->hide();
gc->add_child(_replace_text_line_edit);
- gc->add_child(memnew(Control)); // Space to maintain the grid aligned.
+ gc->add_child(memnew(Control)); // Space to maintain the grid alignment.
{
HBoxContainer *hbc = memnew(HBoxContainer);
@@ -421,7 +421,7 @@ void FindInFilesDialog::set_find_in_files_mode(FindInFilesMode p_mode) {
_replace_text_line_edit->show();
}
- // After hiding some child controls, let's recalculate proper Dialog size
+ // Recalculate the dialog size after hiding child controls.
set_size(Size2(get_size().x, 0));
}
@@ -448,7 +448,7 @@ String FindInFilesDialog::get_folder() const {
}
Set<String> FindInFilesDialog::get_filter() const {
- // could check the _filters_preferences but it might not have been generated yet.
+ // Could check the _filters_preferences but it might not have been generated yet.
Set<String> filters;
for (int i = 0; i < _filters_container->get_child_count(); ++i) {
CheckBox *cb = (CheckBox *)_filters_container->get_child(i);
@@ -492,6 +492,7 @@ void FindInFilesDialog::custom_action(const String &p_action) {
CheckBox *cb = (CheckBox *)_filters_container->get_child(i);
_filters_preferences[cb->get_text()] = cb->is_pressed();
}
+
if (p_action == "find") {
emit_signal(SNAME(SIGNAL_FIND_REQUESTED));
hide();
@@ -510,7 +511,7 @@ void FindInFilesDialog::_on_search_text_modified(String text) {
}
void FindInFilesDialog::_on_search_text_submitted(String text) {
- // This allows to trigger a global search without leaving the keyboard
+ // This allows to trigger a global search without leaving the keyboard.
if (!_find_button->is_disabled()) {
if (_mode == SEARCH_MODE) {
custom_action("find");
@@ -525,7 +526,7 @@ void FindInFilesDialog::_on_search_text_submitted(String text) {
}
void FindInFilesDialog::_on_replace_text_submitted(String text) {
- // This allows to trigger a global search without leaving the keyboard
+ // This allows to trigger a global search without leaving the keyboard.
if (!_replace_button->is_disabled()) {
if (_mode == REPLACE_MODE) {
custom_action("replace");
@@ -641,13 +642,12 @@ void FindInFilesPanel::set_with_replace(bool with_replace) {
_replace_container->set_visible(with_replace);
if (with_replace) {
- // Results show checkboxes on their left so they can be opted out
+ // Results show checkboxes on their left so they can be opted out.
_results_display->set_columns(2);
_results_display->set_column_expand(0, false);
_results_display->set_column_custom_minimum_width(0, 48 * EDSCALE);
-
} else {
- // Results are single-cell items
+ // Results are single-cell items.
_results_display->set_column_expand(0, true);
_results_display->set_columns(1);
}
@@ -708,12 +708,12 @@ void FindInFilesPanel::_on_result_found(String fpath, int line_number, int begin
file_item->set_text(0, fpath);
file_item->set_metadata(0, fpath);
- // The width of this column is restrained to checkboxes, but that doesn't make sense for the parent items,
- // so we override their width so they can expand to full width
+ // The width of this column is restrained to checkboxes,
+ // but that doesn't make sense for the parent items,
+ // so we override their width so they can expand to full width.
file_item->set_expand_right(0, true);
_file_items[fpath] = file_item;
-
} else {
file_item = E->value();
}
@@ -725,7 +725,7 @@ void FindInFilesPanel::_on_result_found(String fpath, int line_number, int begin
// Do this first because it resets properties of the cell...
item->set_cell_mode(text_index, TreeItem::CELL_MODE_CUSTOM);
- // Trim result item line
+ // Trim result item line.
int old_text_size = text.size();
text = text.strip_edges(true, false);
int chars_removed = old_text_size - text.size();
@@ -780,9 +780,8 @@ void FindInFilesPanel::_on_item_edited() {
if (item->is_checked(0)) {
item->set_custom_color(1, _results_display->get_theme_color(SNAME("font_color")));
-
} else {
- // Grey out
+ // Grey out.
Color color = _results_display->get_theme_color(SNAME("font_color"));
color.a /= 2.0;
item->set_custom_color(1, color);
@@ -857,19 +856,19 @@ void FindInFilesPanel::_on_replace_all_clicked() {
}
if (locations.size() != 0) {
- // Results are sorted by file, so we can batch replaces
+ // Results are sorted by file, so we can batch replaces.
apply_replaces_in_file(fpath, locations, replace_text);
modified_files.push_back(fpath);
}
}
- // Hide replace bar so we can't trigger the action twice without doing a new search
+ // Hide replace bar so we can't trigger the action twice without doing a new search.
_replace_container->hide();
emit_signal(SNAME(SIGNAL_FILES_MODIFIED), modified_files);
}
-// Same as get_line, but preserves line ending characters
+// Same as get_line, but preserves line ending characters.
class ConservativeGetLine {
public:
String get_line(FileAccess *f) {
@@ -941,7 +940,7 @@ void FindInFilesPanel::apply_replaces_in_file(String fpath, const Vector<Result>
}
line = line.left(repl_begin) + new_text + line.substr(repl_end);
- // keep an offset in case there are successive replaces in the same line
+ // Keep an offset in case there are successive replaces in the same line.
offset += new_text.length() - (repl_end - repl_begin);
}
@@ -951,7 +950,7 @@ void FindInFilesPanel::apply_replaces_in_file(String fpath, const Vector<Result>
buffer += conservative.get_line(f);
}
- // Now the modified contents are in the buffer, rewrite the file with our changes
+ // Now the modified contents are in the buffer, rewrite the file with our changes.
Error err = f->reopen(fpath, FileAccess::WRITE);
ERR_FAIL_COND_MSG(err != OK, "Cannot create file in path '" + fpath + "'.");
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index bebf05d481..9cb69357bd 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -342,6 +342,7 @@ static String _fixstr(const String &p_what, const String &p_str) {
static void _pre_gen_shape_list(Ref<ImporterMesh> &mesh, Vector<Ref<Shape3D>> &r_shape_list, bool p_convex) {
ERR_FAIL_NULL_MSG(mesh, "Cannot generate shape list with null mesh value");
+ ERR_FAIL_NULL_MSG(mesh->get_mesh(), "Cannot generate shape list with null mesh value");
if (!p_convex) {
Ref<Shape3D> shape = mesh->create_trimesh_shape();
r_shape_list.push_back(shape);
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index 28facd09ce..4b348f12e6 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -50,7 +50,9 @@ void CollisionObject2D::_notification(int p_what) {
}
if (!disabled || (disable_mode != DISABLE_MODE_REMOVE)) {
- RID space = get_world_2d()->get_space();
+ Ref<World2D> world_ref = get_world_2d();
+ ERR_FAIL_COND(!world_ref.is_valid());
+ RID space = world_ref->get_space();
if (area) {
PhysicsServer2D::get_singleton()->area_set_space(rid, space);
} else {
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 41288d646f..4d4d21bad7 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -1101,7 +1101,7 @@ bool CharacterBody2D::move_and_slide() {
}
if (motion_mode == MOTION_MODE_GROUNDED) {
- _move_and_slide_grounded(delta, was_on_floor, current_platform_velocity);
+ _move_and_slide_grounded(delta, was_on_floor);
} else {
_move_and_slide_free(delta);
}
@@ -1122,14 +1122,11 @@ bool CharacterBody2D::move_and_slide() {
return motion_results.size() > 0;
}
-void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_floor, const Vector2 &p_prev_platform_velocity) {
+void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_floor) {
Vector2 motion = motion_velocity * p_delta;
Vector2 motion_slide_up = motion.slide(up_direction);
Vector2 prev_floor_normal = floor_normal;
- RID prev_platform_rid = platform_rid;
- ObjectID prev_platform_object_id = platform_object_id;
- int prev_platform_layer = platform_layer;
platform_rid = RID();
platform_object_id = ObjectID();
@@ -1202,12 +1199,8 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
gt.elements[2] -= result.travel;
set_global_transform(gt);
}
- on_floor = true;
- platform_rid = prev_platform_rid;
- platform_object_id = prev_platform_object_id;
- platform_layer = prev_platform_layer;
- platform_velocity = p_prev_platform_velocity;
- floor_normal = prev_floor_normal;
+ // Determines if you are on the ground.
+ _snap_on_floor(true, false);
motion_velocity = Vector2();
last_motion = Vector2();
motion = Vector2();
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index d1f52b33f2..15e8469bb4 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -416,7 +416,7 @@ private:
MovingPlatformApplyVelocityOnLeave get_moving_platform_apply_velocity_on_leave() const;
void _move_and_slide_free(double p_delta);
- void _move_and_slide_grounded(double p_delta, bool p_was_on_floor, const Vector2 &p_prev_platform_velocity);
+ void _move_and_slide_grounded(double p_delta, bool p_was_on_floor);
Ref<KinematicCollision2D> _get_slide_collision(int p_bounce);
Ref<KinematicCollision2D> _get_last_slide_collision();
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index f7e02685cf..e54d1cd597 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -803,8 +803,10 @@ void TileMap::_update_dirty_quadrants() {
}
for (unsigned int layer = 0; layer < layers.size(); layer++) {
+ SelfList<TileMapQuadrant>::List &dirty_quadrant_list = layers[layer].dirty_quadrant_list;
+
// Update the coords cache.
- for (SelfList<TileMapQuadrant> *q = layers[layer].dirty_quadrant_list.first(); q; q = q->next()) {
+ for (SelfList<TileMapQuadrant> *q = dirty_quadrant_list.first(); q; q = q->next()) {
q->self()->map_to_world.clear();
q->self()->world_to_map.clear();
for (Set<Vector2i>::Element *E = q->self()->cells.front(); E; E = E->next()) {
@@ -815,15 +817,18 @@ void TileMap::_update_dirty_quadrants() {
}
}
+ // Find TileData that need a runtime modification.
+ _build_runtime_update_tile_data(dirty_quadrant_list);
+
// Call the update_dirty_quadrant method on plugins.
- _rendering_update_dirty_quadrants(layers[layer].dirty_quadrant_list);
- _physics_update_dirty_quadrants(layers[layer].dirty_quadrant_list);
- _navigation_update_dirty_quadrants(layers[layer].dirty_quadrant_list);
- _scenes_update_dirty_quadrants(layers[layer].dirty_quadrant_list);
+ _rendering_update_dirty_quadrants(dirty_quadrant_list);
+ _physics_update_dirty_quadrants(dirty_quadrant_list);
+ _navigation_update_dirty_quadrants(dirty_quadrant_list);
+ _scenes_update_dirty_quadrants(dirty_quadrant_list);
// Redraw the debug canvas_items.
RenderingServer *rs = RenderingServer::get_singleton();
- for (SelfList<TileMapQuadrant> *q = layers[layer].dirty_quadrant_list.first(); q; q = q->next()) {
+ for (SelfList<TileMapQuadrant> *q = dirty_quadrant_list.first(); q; q = q->next()) {
rs->canvas_item_clear(q->self()->debug_canvas_item);
Transform2D xform;
xform.set_origin(map_to_world(q->self()->coords * get_effective_quadrant_size(layer)));
@@ -836,8 +841,13 @@ void TileMap::_update_dirty_quadrants() {
}
// Clear the list
- while (layers[layer].dirty_quadrant_list.first()) {
- layers[layer].dirty_quadrant_list.remove(layers[layer].dirty_quadrant_list.first());
+ while (dirty_quadrant_list.first()) {
+ // Clear the runtime tile data.
+ for (const KeyValue<Vector2i, TileData *> &kv : dirty_quadrant_list.first()->self()->runtime_tile_data_cache) {
+ memdelete(kv.value);
+ }
+
+ dirty_quadrant_list.remove(dirty_quadrant_list.first());
}
}
@@ -847,6 +857,8 @@ void TileMap::_update_dirty_quadrants() {
}
void TileMap::_recreate_layer_internals(int p_layer) {
+ ERR_FAIL_INDEX(p_layer, (int)layers.size());
+
// Make sure that _clear_internals() was called prior.
ERR_FAIL_COND_MSG(layers[p_layer].quadrant_map.size() > 0, "TileMap layer " + itos(p_layer) + " had a non-empty quadrant map.");
@@ -1103,7 +1115,13 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
if (atlas_source) {
// Get the tile data.
- TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile));
+ const TileData *tile_data;
+ if (q.runtime_tile_data_cache.has(E_cell.value)) {
+ tile_data = q.runtime_tile_data_cache[E_cell.value];
+ } else {
+ tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile));
+ }
+
Ref<ShaderMaterial> mat = tile_data->get_material();
int z_index = tile_data->get_z_index();
@@ -1150,7 +1168,7 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
}
// Drawing the tile in the canvas item.
- draw_tile(canvas_item, E_cell.key - position, tile_set, c.source_id, c.get_atlas_coords(), c.alternative_tile, -1, modulate);
+ draw_tile(canvas_item, E_cell.key - position, tile_set, c.source_id, c.get_atlas_coords(), c.alternative_tile, -1, modulate, tile_data);
// --- Occluders ---
for (int i = 0; i < tile_set->get_occlusion_layers_count(); i++) {
@@ -1267,7 +1285,7 @@ void TileMap::_rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
}
}
-void TileMap::draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, int p_frame, Color p_modulation) {
+void TileMap::draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, int p_frame, Color p_modulation, const TileData *p_tile_data_override) {
ERR_FAIL_COND(!p_tile_set.is_valid());
ERR_FAIL_COND(!p_tile_set->has_source(p_atlas_source_id));
ERR_FAIL_COND(!p_tile_set->get_source(p_atlas_source_id)->has_tile(p_atlas_coords));
@@ -1293,7 +1311,7 @@ void TileMap::draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSe
}
// Get tile data.
- TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(p_atlas_coords, p_alternative_tile));
+ const TileData *tile_data = p_tile_data_override ? p_tile_data_override : Object::cast_to<TileData>(atlas_source->get_tile_data(p_atlas_coords, p_alternative_tile));
// Get the tile modulation.
Color modulate = tile_data->get_modulate() * p_modulation;
@@ -1452,8 +1470,12 @@ void TileMap::_physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
if (atlas_source) {
- TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile));
-
+ const TileData *tile_data;
+ if (q.runtime_tile_data_cache.has(E_cell->get())) {
+ tile_data = q.runtime_tile_data_cache[E_cell->get()];
+ } else {
+ tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile));
+ }
for (int tile_set_physics_layer = 0; tile_set_physics_layer < tile_set->get_physics_layers_count(); tile_set_physics_layer++) {
Ref<PhysicsMaterial> physics_material = tile_set->get_physics_layer_physics_material(tile_set_physics_layer);
uint32_t physics_layer = tile_set->get_physics_layer_collision_layer(tile_set_physics_layer);
@@ -1645,7 +1667,12 @@ void TileMap::_navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
if (atlas_source) {
- TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile));
+ const TileData *tile_data;
+ if (q.runtime_tile_data_cache.has(E_cell->get())) {
+ tile_data = q.runtime_tile_data_cache[E_cell->get()];
+ } else {
+ tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile));
+ }
q.navigation_regions[E_cell->get()].resize(tile_set->get_navigation_layers_count());
for (int layer_index = 0; layer_index < tile_set->get_navigation_layers_count(); layer_index++) {
@@ -1729,7 +1756,12 @@ void TileMap::_navigation_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
if (atlas_source) {
- TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile));
+ const TileData *tile_data;
+ if (p_quadrant->runtime_tile_data_cache.has(E_cell->get())) {
+ tile_data = p_quadrant->runtime_tile_data_cache[E_cell->get()];
+ } else {
+ tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile));
+ }
Transform2D xform;
xform.set_origin(map_to_world(E_cell->get()) - quadrant_pos);
@@ -2407,6 +2439,17 @@ void TileMap::clear() {
used_rect_cache_dirty = true;
}
+void TileMap::force_update(int p_layer) {
+ if (p_layer >= 0) {
+ ERR_FAIL_INDEX(p_layer, (int)layers.size());
+ _clear_layer_internals(p_layer);
+ _recreate_layer_internals(p_layer);
+ } else {
+ _clear_internals();
+ _recreate_internals();
+ }
+}
+
void TileMap::_set_tile_data(int p_layer, const Vector<int> &p_data) {
ERR_FAIL_INDEX(p_layer, (int)layers.size());
ERR_FAIL_COND(format > FORMAT_3);
@@ -2516,6 +2559,44 @@ Vector<int> TileMap::_get_tile_data(int p_layer) const {
return data;
}
+void TileMap::_build_runtime_update_tile_data(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) {
+ if (GDVIRTUAL_IS_OVERRIDDEN(_use_tile_data_runtime_update) && GDVIRTUAL_IS_OVERRIDDEN(_tile_data_runtime_update)) {
+ SelfList<TileMapQuadrant> *q_list_element = r_dirty_quadrant_list.first();
+ while (q_list_element) {
+ TileMapQuadrant &q = *q_list_element->self();
+ // Iterate over the cells of the quadrant.
+ for (const KeyValue<Vector2i, Vector2i> &E_cell : q.world_to_map) {
+ TileMapCell c = get_cell(q.layer, E_cell.value, true);
+
+ TileSetSource *source;
+ if (tile_set->has_source(c.source_id)) {
+ source = *tile_set->get_source(c.source_id);
+
+ if (!source->has_tile(c.get_atlas_coords()) || !source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
+ continue;
+ }
+
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ bool ret = false;
+ if (GDVIRTUAL_CALL(_use_tile_data_runtime_update, q.layer, E_cell.value, ret) && ret) {
+ TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile));
+
+ // Create the runtime TileData.
+ TileData *tile_data_runtime_use = tile_data->duplicate();
+ tile_data->set_allow_transform(true);
+ q.runtime_tile_data_cache[E_cell.value] = tile_data_runtime_use;
+
+ GDVIRTUAL_CALL(_tile_data_runtime_update, q.layer, E_cell.value, tile_data_runtime_use);
+ }
+ }
+ }
+ }
+ q_list_element = q_list_element->next();
+ }
+ }
+}
+
#ifdef TOOLS_ENABLED
Rect2 TileMap::_edit_get_rect() const {
// Return the visible rect of the tilemap
@@ -3553,6 +3634,8 @@ void TileMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear_layer", "layer"), &TileMap::clear_layer);
ClassDB::bind_method(D_METHOD("clear"), &TileMap::clear);
+ ClassDB::bind_method(D_METHOD("force_update", "layer"), &TileMap::force_update, DEFVAL(-1));
+
ClassDB::bind_method(D_METHOD("get_surrounding_tiles", "coords"), &TileMap::get_surrounding_tiles);
ClassDB::bind_method(D_METHOD("get_used_cells", "layer"), &TileMap::get_used_cells);
@@ -3570,6 +3653,9 @@ void TileMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("_tile_set_changed_deferred_update"), &TileMap::_tile_set_changed_deferred_update);
+ GDVIRTUAL_BIND(_use_tile_data_runtime_update, "layer", "coords");
+ GDVIRTUAL_BIND(_tile_data_runtime_update, "layer", "coords", "tile_data");
+
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tile_set", PROPERTY_HINT_RESOURCE_TYPE, "TileSet"), "set_tileset", "get_tileset");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_quadrant_size", PROPERTY_HINT_RANGE, "1,128,1"), "set_quadrant_size", "get_quadrant_size");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_animatable"), "set_collision_animatable", "is_collision_animatable");
@@ -3590,7 +3676,7 @@ void TileMap::_bind_methods() {
void TileMap::_tile_set_changed() {
emit_signal(SNAME("changed"));
_tile_set_changed_deferred_update_needed = true;
- call_deferred("_tile_set_changed_deferred_update");
+ call_deferred(SNAME("_tile_set_changed_deferred_update"));
}
void TileMap::_tile_set_changed_deferred_update() {
@@ -3612,5 +3698,6 @@ TileMap::~TileMap() {
if (tile_set.is_valid()) {
tile_set->disconnect("changed", callable_mp(this, &TileMap::_tile_set_changed));
}
+
_clear_internals();
}
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index 6054f818a2..f260422290 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -79,6 +79,9 @@ struct TileMapQuadrant {
// Scenes.
Map<Vector2i, String> scenes;
+ // Runtime TileData cache.
+ Map<Vector2i, TileData *> runtime_tile_data_cache;
+
void operator=(const TileMapQuadrant &q) {
layer = q.layer;
coords = q.coords;
@@ -254,6 +257,8 @@ private:
void _set_tile_data(int p_layer, const Vector<int> &p_data);
Vector<int> _get_tile_data(int p_layer) const;
+ void _build_runtime_update_tile_data(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list);
+
void _tile_set_changed();
bool _tile_set_changed_deferred_update_needed = false;
void _tile_set_changed_deferred_update();
@@ -283,7 +288,7 @@ public:
void set_quadrant_size(int p_size);
int get_quadrant_size() const;
- static void draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, int p_frame = -1, Color p_modulation = Color(1.0, 1.0, 1.0, 1.0));
+ static void draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, int p_frame = -1, Color p_modulation = Color(1.0, 1.0, 1.0, 1.0), const TileData *p_tile_data_override = nullptr);
// Layers management.
int get_layers_count() const;
@@ -362,13 +367,21 @@ public:
// Fixing a nclearing methods.
void fix_invalid_tiles();
+ // Clears tiles from a given layer
void clear_layer(int p_layer);
void clear();
- // Helpers
+ // Force a TileMap update
+ void force_update(int p_layer = -1);
+
+ // Helpers?
TypedArray<Vector2i> get_surrounding_tiles(Vector2i coords);
void draw_cells_outline(Control *p_control, Set<Vector2i> p_cells, Color p_color, Transform2D p_transform = Transform2D());
+ // Virtual function to modify the TileData at runtime
+ GDVIRTUAL2R(bool, _use_tile_data_runtime_update, int, Vector2i);
+ GDVIRTUAL3(_tile_data_runtime_update, int, Vector2i, TileData *);
+
// Configuration warnings.
TypedArray<String> get_configuration_warnings() const override;
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index fd891a5e13..a166a05c71 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -64,7 +64,9 @@ void CollisionObject3D::_notification(int p_what) {
}
if (!disabled || (disable_mode != DISABLE_MODE_REMOVE)) {
- RID space = get_world_3d()->get_space();
+ Ref<World3D> world_ref = get_world_3d();
+ ERR_FAIL_COND(!world_ref.is_valid());
+ RID space = world_ref->get_space();
if (area) {
PhysicsServer3D::get_singleton()->area_set_space(rid, space);
} else {
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index dda1151273..8c33d306a1 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -920,6 +920,9 @@ void LineEdit::_notification(int p_what) {
DisplayServer::get_singleton()->virtual_keyboard_hide();
}
+ if (deselect_on_focus_loss_enabled) {
+ deselect();
+ }
} break;
case MainLoop::NOTIFICATION_OS_IME_UPDATE: {
if (has_focus()) {
@@ -1938,6 +1941,17 @@ bool LineEdit::is_selecting_enabled() const {
return selecting_enabled;
}
+void LineEdit::set_deselect_on_focus_loss_enabled(const bool p_enabled) {
+ deselect_on_focus_loss_enabled = p_enabled;
+ if (p_enabled && selection.enabled && !has_focus()) {
+ deselect();
+ }
+}
+
+bool LineEdit::is_deselect_on_focus_loss_enabled() const {
+ return deselect_on_focus_loss_enabled;
+}
+
void LineEdit::set_right_icon(const Ref<Texture2D> &p_icon) {
if (right_icon == p_icon) {
return;
@@ -2196,6 +2210,8 @@ void LineEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_middle_mouse_paste_enabled"), &LineEdit::is_middle_mouse_paste_enabled);
ClassDB::bind_method(D_METHOD("set_selecting_enabled", "enable"), &LineEdit::set_selecting_enabled);
ClassDB::bind_method(D_METHOD("is_selecting_enabled"), &LineEdit::is_selecting_enabled);
+ ClassDB::bind_method(D_METHOD("set_deselect_on_focus_loss_enabled", "enable"), &LineEdit::set_deselect_on_focus_loss_enabled);
+ ClassDB::bind_method(D_METHOD("is_deselect_on_focus_loss_enabled"), &LineEdit::is_deselect_on_focus_loss_enabled);
ClassDB::bind_method(D_METHOD("set_right_icon", "icon"), &LineEdit::set_right_icon);
ClassDB::bind_method(D_METHOD("get_right_icon"), &LineEdit::get_right_icon);
@@ -2251,6 +2267,7 @@ void LineEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shortcut_keys_enabled"), "set_shortcut_keys_enabled", "is_shortcut_keys_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "middle_mouse_paste_enabled"), "set_middle_mouse_paste_enabled", "is_middle_mouse_paste_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selecting_enabled"), "set_selecting_enabled", "is_selecting_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deselect_on_focus_loss_enabled"), "set_deselect_on_focus_loss_enabled", "is_deselect_on_focus_loss_enabled");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "right_icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_right_icon", "get_right_icon");
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "language"), "set_language", "get_language");
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index 94179ce05b..3364e02e01 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -97,6 +97,7 @@ private:
float full_width = 0.0;
bool selecting_enabled = true;
+ bool deselect_on_focus_loss_enabled = true;
bool context_menu_enabled = true;
PopupMenu *menu = nullptr;
@@ -325,6 +326,9 @@ public:
void set_selecting_enabled(bool p_enabled);
bool is_selecting_enabled() const;
+ void set_deselect_on_focus_loss_enabled(const bool p_enabled);
+ bool is_deselect_on_focus_loss_enabled() const;
+
void set_right_icon(const Ref<Texture2D> &p_icon);
Ref<Texture2D> get_right_icon();
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 31767dd263..f1efbbda98 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -1491,7 +1491,13 @@ void RichTextLabel::_notification(int p_what) {
_update_fx(main, dt);
update();
}
- }
+ } break;
+ case NOTIFICATION_FOCUS_EXIT: {
+ if (deselect_on_focus_loss_enabled) {
+ selection.active = false;
+ update();
+ }
+ } break;
}
}
@@ -3609,6 +3615,14 @@ void RichTextLabel::set_selection_enabled(bool p_enabled) {
}
}
+void RichTextLabel::set_deselect_on_focus_loss_enabled(const bool p_enabled) {
+ deselect_on_focus_loss_enabled = p_enabled;
+ if (p_enabled && selection.active && !has_focus()) {
+ selection.active = false;
+ update();
+ }
+}
+
bool RichTextLabel::_search_table(ItemTable *p_table, List<Item *>::Element *p_from, const String &p_string, bool p_reverse_search) {
List<Item *>::Element *E = p_from;
while (E != nullptr) {
@@ -3858,6 +3872,10 @@ bool RichTextLabel::is_selection_enabled() const {
return selection.enabled;
}
+bool RichTextLabel::is_deselect_on_focus_loss_enabled() const {
+ return deselect_on_focus_loss_enabled;
+}
+
int RichTextLabel::get_selection_from() const {
if (!selection.active || !selection.enabled) {
return -1;
@@ -4111,6 +4129,9 @@ 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("set_deselect_on_focus_loss_enabled", "enable"), &RichTextLabel::set_deselect_on_focus_loss_enabled);
+ ClassDB::bind_method(D_METHOD("is_deselect_on_focus_loss_enabled"), &RichTextLabel::is_deselect_on_focus_loss_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);
@@ -4162,6 +4183,8 @@ void RichTextLabel::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selection_enabled"), "set_selection_enabled", "is_selection_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_selected_font_color"), "set_override_selected_font_color", "is_overriding_selected_font_color");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deselect_on_focus_loss_enabled"), "set_deselect_on_focus_loss_enabled", "is_deselect_on_focus_loss_enabled");
+
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "custom_effects", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "RichTextEffect"), (PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE)), "set_effects", "get_effects");
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index 48186ca8b8..6d772876ad 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -399,6 +399,7 @@ private:
};
Selection selection;
+ bool deselect_on_focus_loss_enabled = true;
int visible_characters = -1;
float percent_visible = 1.0;
@@ -551,6 +552,8 @@ public:
int get_selection_to() const;
String get_selected_text() const;
void selection_copy();
+ void set_deselect_on_focus_loss_enabled(const bool p_enabled);
+ bool is_deselect_on_focus_loss_enabled() const;
void parse_bbcode(const String &p_bbcode);
void append_text(const String &p_bbcode);
diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp
index 78b58c773a..780614302c 100644
--- a/scene/gui/tab_bar.cpp
+++ b/scene/gui/tab_bar.cpp
@@ -222,7 +222,7 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (max_drawn_tab <= 0) {
+ if (tabs.is_empty()) {
// Return early if there are no actual tabs to handle input for.
return;
}
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 8cb3b23020..cb7a6c0978 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1364,6 +1364,10 @@ void TextEdit::_notification(int p_what) {
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
DisplayServer::get_singleton()->virtual_keyboard_hide();
}
+
+ if (deselect_on_focus_loss_enabled) {
+ deselect();
+ }
} break;
case MainLoop::NOTIFICATION_OS_IME_UPDATE: {
if (has_focus()) {
@@ -3669,6 +3673,17 @@ bool TextEdit::is_selecting_enabled() const {
return selecting_enabled;
}
+void TextEdit::set_deselect_on_focus_loss_enabled(const bool p_enabled) {
+ deselect_on_focus_loss_enabled = p_enabled;
+ if (p_enabled && selection.active && !has_focus()) {
+ deselect();
+ }
+}
+
+bool TextEdit::is_deselect_on_focus_loss_enabled() const {
+ return deselect_on_focus_loss_enabled;
+}
+
void TextEdit::set_override_selected_font_color(bool p_override_selected_font_color) {
override_selected_font_color = p_override_selected_font_color;
}
@@ -4716,6 +4731,9 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_selecting_enabled", "enable"), &TextEdit::set_selecting_enabled);
ClassDB::bind_method(D_METHOD("is_selecting_enabled"), &TextEdit::is_selecting_enabled);
+ ClassDB::bind_method(D_METHOD("set_deselect_on_focus_loss_enabled", "enable"), &TextEdit::set_deselect_on_focus_loss_enabled);
+ ClassDB::bind_method(D_METHOD("is_deselect_on_focus_loss_enabled"), &TextEdit::is_deselect_on_focus_loss_enabled);
+
ClassDB::bind_method(D_METHOD("set_override_selected_font_color", "override"), &TextEdit::set_override_selected_font_color);
ClassDB::bind_method(D_METHOD("is_overriding_selected_font_color"), &TextEdit::is_overriding_selected_font_color);
@@ -4875,9 +4893,9 @@ void TextEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shortcut_keys_enabled"), "set_shortcut_keys_enabled", "is_shortcut_keys_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selecting_enabled"), "set_selecting_enabled", "is_selecting_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deselect_on_focus_loss_enabled"), "set_deselect_on_focus_loss_enabled", "is_deselect_on_focus_loss_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "virtual_keyboard_enabled"), "set_virtual_keyboard_enabled", "is_virtual_keyboard_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "middle_mouse_paste_enabled"), "set_middle_mouse_paste_enabled", "is_middle_mouse_paste_enabled");
-
ADD_PROPERTY(PropertyInfo(Variant::INT, "wrap_mode", PROPERTY_HINT_ENUM, "None,Boundary"), "set_line_wrapping_mode", "get_line_wrapping_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_selected_font_color"), "set_override_selected_font_color", "is_overriding_selected_font_color");
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 8823e44c0d..23f80efce0 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -395,6 +395,7 @@ private:
} selection;
bool selecting_enabled = true;
+ bool deselect_on_focus_loss_enabled = true;
Color font_selected_color = Color(1, 1, 1);
Color selection_color = Color(1, 1, 1);
@@ -753,6 +754,9 @@ public:
void set_selecting_enabled(const bool p_enabled);
bool is_selecting_enabled() const;
+ void set_deselect_on_focus_loss_enabled(const bool p_enabled);
+ bool is_deselect_on_focus_loss_enabled() const;
+
void set_override_selected_font_color(bool p_override_selected_font_color);
bool is_overriding_selected_font_color() const;
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index abb3381c4e..267180973f 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -1100,7 +1100,7 @@ void BaseMaterial3D::_update_shader() {
if (proximity_fade_enabled) {
code += " float depth_tex = textureLod(DEPTH_TEXTURE,SCREEN_UV,0.0).r;\n";
- code += " vec4 world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV*2.0-1.0,depth_tex*2.0-1.0,1.0);\n";
+ code += " vec4 world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV*2.0-1.0,depth_tex,1.0);\n";
code += " world_pos.xyz/=world_pos.w;\n";
code += " ALPHA*=clamp(1.0-smoothstep(world_pos.z+proximity_fade_distance,world_pos.z,VERTEX.z),0.0,1.0);\n";
}
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 6411a6d233..141e9e1b0e 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -4638,6 +4638,37 @@ bool TileData::is_allowing_transform() const {
return allow_transform;
}
+TileData *TileData::duplicate() {
+ TileData *output = memnew(TileData);
+ output->tile_set = tile_set;
+
+ output->allow_transform = allow_transform;
+
+ // Rendering
+ output->flip_h = flip_h;
+ output->flip_v = flip_v;
+ output->transpose = transpose;
+ output->tex_offset = tex_offset;
+ output->material = material;
+ output->modulate = modulate;
+ output->z_index = z_index;
+ output->y_sort_origin = y_sort_origin;
+ output->occluders = occluders;
+ // Physics
+ output->physics = physics;
+ // Terrain
+ output->terrain_set = -1;
+ memcpy(output->terrain_peering_bits, terrain_peering_bits, 16 * sizeof(int));
+ // Navigation
+ output->navigation = navigation;
+ // Misc
+ output->probability = probability;
+ // Custom data
+ output->custom_data = custom_data;
+
+ return output;
+}
+
// Rendering
void TileData::set_flip_h(bool p_flip_h) {
ERR_FAIL_COND_MSG(!allow_transform && p_flip_h, "Transform is only allowed for alternative tiles (with its alternative_id != 0)");
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index 52446fd680..077315e58d 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -794,6 +794,9 @@ public:
void set_allow_transform(bool p_allow_transform);
bool is_allowing_transform() const;
+ // To duplicate a TileData object, needed for runtiume update.
+ TileData *duplicate();
+
// Rendering
void set_flip_h(bool p_flip_h);
bool get_flip_h() const;