summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/animated_sprite.cpp29
-rw-r--r--scene/2d/animated_sprite.h1
-rw-r--r--scene/2d/area_2d.cpp6
-rw-r--r--scene/2d/audio_stream_player_2d.cpp4
-rw-r--r--scene/2d/camera_2d.cpp8
-rw-r--r--scene/2d/mesh_instance_2d.cpp30
-rw-r--r--scene/2d/mesh_instance_2d.h30
-rw-r--r--scene/2d/navigation2d.cpp2
-rw-r--r--scene/2d/parallax_layer.cpp1
-rw-r--r--scene/2d/particles_2d.cpp4
-rw-r--r--scene/2d/path_2d.cpp2
-rw-r--r--scene/2d/skeleton_2d.cpp30
-rw-r--r--scene/2d/skeleton_2d.h30
-rw-r--r--scene/2d/tile_map.cpp42
-rw-r--r--scene/3d/area.cpp2
-rw-r--r--scene/3d/audio_stream_player_3d.cpp2
-rw-r--r--scene/3d/camera.cpp4
-rw-r--r--scene/3d/light.cpp12
-rw-r--r--scene/3d/particles.cpp22
-rw-r--r--scene/3d/path.cpp2
-rw-r--r--scene/3d/physics_body.cpp11
-rw-r--r--scene/3d/reflection_probe.cpp2
-rw-r--r--scene/3d/scenario_fx.cpp7
-rw-r--r--scene/3d/skeleton.cpp94
-rw-r--r--scene/3d/skeleton.h7
-rw-r--r--scene/3d/vehicle_body.cpp7
-rw-r--r--scene/3d/voxel_light_baker.cpp5
-rw-r--r--scene/animation/animation_player.cpp3
-rw-r--r--scene/gui/color_picker.cpp54
-rw-r--r--scene/gui/color_picker.h6
-rw-r--r--scene/gui/container.cpp11
-rw-r--r--scene/gui/control.cpp59
-rw-r--r--scene/gui/control.h8
-rw-r--r--scene/gui/gradient_edit.cpp1
-rw-r--r--scene/gui/label.cpp13
-rw-r--r--scene/gui/popup_menu.cpp24
-rw-r--r--scene/gui/range.cpp45
-rw-r--r--scene/gui/range.h8
-rw-r--r--scene/gui/rich_text_label.h1
-rw-r--r--scene/gui/scroll_container.cpp16
-rw-r--r--scene/gui/split_container.cpp7
-rw-r--r--scene/gui/text_edit.cpp1512
-rw-r--r--scene/gui/text_edit.h59
-rw-r--r--scene/main/node.cpp3
-rw-r--r--scene/main/node.h1
-rw-r--r--scene/main/viewport.cpp16
-rw-r--r--scene/main/viewport.h1
-rw-r--r--scene/resources/default_theme/default_theme.cpp5
-rw-r--r--scene/resources/dynamic_font.cpp7
-rw-r--r--scene/resources/mesh.cpp4
-rw-r--r--scene/resources/primitive_meshes.cpp2
-rw-r--r--scene/resources/style_box.cpp9
-rw-r--r--scene/resources/texture.cpp11
-rw-r--r--scene/resources/texture.h2
-rw-r--r--scene/resources/tile_set.cpp3
-rw-r--r--scene/resources/tile_set.h1
56 files changed, 1527 insertions, 761 deletions
diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp
index 60a7961293..54194ff543 100644
--- a/scene/2d/animated_sprite.cpp
+++ b/scene/2d/animated_sprite.cpp
@@ -361,7 +361,7 @@ void AnimatedSprite::_notification(int p_what) {
if (timeout <= 0) {
- timeout = 1.0 / speed;
+ timeout = _get_frame_duration();
int fc = frames->get_frame_count(animation);
if (frame >= fc - 1) {
@@ -483,7 +483,13 @@ int AnimatedSprite::get_frame() const {
void AnimatedSprite::set_speed_scale(float p_speed_scale) {
+ float elapsed = _get_frame_duration() - timeout;
+
speed_scale = MAX(p_speed_scale, 0.0f);
+
+ // We adapt the timeout so that the animation speed adapts as soon as the speed scale is changed
+ _reset_timeout();
+ timeout -= elapsed;
}
float AnimatedSprite::get_speed_scale() const {
@@ -574,21 +580,22 @@ bool AnimatedSprite::is_playing() const {
return playing;
}
-void AnimatedSprite::_reset_timeout() {
-
- if (!playing)
- return;
-
+float AnimatedSprite::_get_frame_duration() {
if (frames.is_valid() && frames->has_animation(animation)) {
float speed = frames->get_animation_speed(animation) * speed_scale;
if (speed > 0) {
- timeout = 1.0 / speed;
- } else {
- timeout = 0;
+ return 1.0 / speed;
}
- } else {
- timeout = 0;
}
+ return 0.0;
+}
+
+void AnimatedSprite::_reset_timeout() {
+
+ if (!playing)
+ return;
+
+ timeout = _get_frame_duration();
}
void AnimatedSprite::set_animation(const StringName &p_animation) {
diff --git a/scene/2d/animated_sprite.h b/scene/2d/animated_sprite.h
index 7b91a1faef..be5b1ef6d6 100644
--- a/scene/2d/animated_sprite.h
+++ b/scene/2d/animated_sprite.h
@@ -141,6 +141,7 @@ class AnimatedSprite : public Node2D {
void _res_changed();
+ float _get_frame_duration();
void _reset_timeout();
void _set_playing(bool p_playing);
bool _is_playing() const;
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp
index bb914b90fc..c375374dce 100644
--- a/scene/2d/area_2d.cpp
+++ b/scene/2d/area_2d.cpp
@@ -666,11 +666,11 @@ void Area2D::_bind_methods() {
ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine"), "set_space_override_mode", "get_space_override_mode");
ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "gravity_point"), "set_gravity_is_point", "is_gravity_a_point");
- ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "gravity_distance_scale", PROPERTY_HINT_RANGE, "0,1024,0.001"), "set_gravity_distance_scale", "get_gravity_distance_scale");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "gravity_distance_scale", PROPERTY_HINT_EXP_RANGE, "0,1024,0.001,or_greater"), "set_gravity_distance_scale", "get_gravity_distance_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity_vec"), "set_gravity_vector", "get_gravity_vector");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity", PROPERTY_HINT_RANGE, "-1024,1024,0.001"), "set_gravity", "get_gravity");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "linear_damp", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_linear_damp", "get_linear_damp");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_damp", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_angular_damp", "get_angular_damp");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "linear_damp", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_linear_damp", "get_linear_damp");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_damp", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_angular_damp", "get_angular_damp");
ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,128,1"), "set_priority", "get_priority");
ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "monitoring"), "set_monitoring", "is_monitoring");
ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "monitorable"), "set_monitorable", "is_monitorable");
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index f998f23d3b..54541293fd 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -461,8 +461,8 @@ void AudioStreamPlayer2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,32,0.01"), "set_pitch_scale", "get_pitch_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "is_playing");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_RANGE, "1,65536,1"), "set_max_distance", "get_max_distance");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "attenuation", PROPERTY_HINT_EXP_EASING), "set_attenuation", "get_attenuation");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_EXP_RANGE, "1,4096,1,or_greater"), "set_max_distance", "get_max_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_attenuation", "get_attenuation");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus");
ADD_PROPERTY(PropertyInfo(Variant::INT, "area_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_area_mask", "get_area_mask");
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index d172da5bd9..3b86ca76ea 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -91,8 +91,8 @@ Transform2D Camera2D::get_camera_transform() {
if (anchor_mode == ANCHOR_MODE_DRAG_CENTER) {
if (h_drag_enabled && !Engine::get_singleton()->is_editor_hint()) {
- camera_pos.x = MIN(camera_pos.x, (new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_LEFT]));
- camera_pos.x = MAX(camera_pos.x, (new_camera_pos.x - screen_size.x * 0.5 * drag_margin[MARGIN_RIGHT]));
+ camera_pos.x = MIN(camera_pos.x, (new_camera_pos.x + screen_size.x * 0.5 * zoom.x * drag_margin[MARGIN_LEFT]));
+ camera_pos.x = MAX(camera_pos.x, (new_camera_pos.x - screen_size.x * 0.5 * zoom.x * drag_margin[MARGIN_RIGHT]));
} else {
if (h_ofs < 0) {
@@ -104,8 +104,8 @@ Transform2D Camera2D::get_camera_transform() {
if (v_drag_enabled && !Engine::get_singleton()->is_editor_hint()) {
- camera_pos.y = MIN(camera_pos.y, (new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_TOP]));
- camera_pos.y = MAX(camera_pos.y, (new_camera_pos.y - screen_size.y * 0.5 * drag_margin[MARGIN_BOTTOM]));
+ camera_pos.y = MIN(camera_pos.y, (new_camera_pos.y + screen_size.y * 0.5 * zoom.y * drag_margin[MARGIN_TOP]));
+ camera_pos.y = MAX(camera_pos.y, (new_camera_pos.y - screen_size.y * 0.5 * zoom.y * drag_margin[MARGIN_BOTTOM]));
} else {
diff --git a/scene/2d/mesh_instance_2d.cpp b/scene/2d/mesh_instance_2d.cpp
index adbb227d0c..9f21fe1a1f 100644
--- a/scene/2d/mesh_instance_2d.cpp
+++ b/scene/2d/mesh_instance_2d.cpp
@@ -1,3 +1,33 @@
+/*************************************************************************/
+/* mesh_instance_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
#include "mesh_instance_2d.h"
void MeshInstance2D::_notification(int p_what) {
diff --git a/scene/2d/mesh_instance_2d.h b/scene/2d/mesh_instance_2d.h
index d1d1ade0ae..c9889c1c03 100644
--- a/scene/2d/mesh_instance_2d.h
+++ b/scene/2d/mesh_instance_2d.h
@@ -1,3 +1,33 @@
+/*************************************************************************/
+/* mesh_instance_2d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
#ifndef MESH_INSTANCE_2D_H
#define MESH_INSTANCE_2D_H
diff --git a/scene/2d/navigation2d.cpp b/scene/2d/navigation2d.cpp
index 4737e14111..16e0386952 100644
--- a/scene/2d/navigation2d.cpp
+++ b/scene/2d/navigation2d.cpp
@@ -671,7 +671,7 @@ Object *Navigation2D::get_closest_point_owner(const Vector2 &p_point) {
if (Geometry::is_point_in_triangle(p_point, _get_vertex(p.edges[0].point), _get_vertex(p.edges[i - 1].point), _get_vertex(p.edges[i].point))) {
- E->get().owner;
+ return E->get().owner;
}
}
}
diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp
index 584c2f2c85..2ac6c76032 100644
--- a/scene/2d/parallax_layer.cpp
+++ b/scene/2d/parallax_layer.cpp
@@ -120,7 +120,6 @@ void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, float p_sc
if (mirroring.x) {
double den = mirroring.x * p_scale;
- double before = new_ofs.x;
new_ofs.x -= den * ceil(new_ofs.x / den);
}
diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp
index 7eaa5bb88c..1da1d44b17 100644
--- a/scene/2d/particles_2d.cpp
+++ b/scene/2d/particles_2d.cpp
@@ -367,9 +367,9 @@ void Particles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("restart"), &Particles2D::restart);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,100000,1"), "set_amount", "get_amount");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount");
ADD_GROUP("Time", "");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_speed_scale", "get_speed_scale");
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index 7377591f7d..658b998d17 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -299,7 +299,7 @@ void PathFollow2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_lookahead", "lookahead"), &PathFollow2D::set_lookahead);
ClassDB::bind_method(D_METHOD("get_lookahead"), &PathFollow2D::get_lookahead);
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset", PROPERTY_HINT_RANGE, "0,10000,0.01"), "set_offset", "get_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset", PROPERTY_HINT_EXP_RANGE, "0,10000,0.01,or_greater"), "set_offset", "get_offset");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "h_offset"), "set_h_offset", "get_h_offset");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_offset"), "set_v_offset", "get_v_offset");
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
index 2363c791fa..0595cc43b8 100644
--- a/scene/2d/skeleton_2d.cpp
+++ b/scene/2d/skeleton_2d.cpp
@@ -1,3 +1,33 @@
+/*************************************************************************/
+/* skeleton_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
#include "skeleton_2d.h"
void Bone2D::_notification(int p_what) {
diff --git a/scene/2d/skeleton_2d.h b/scene/2d/skeleton_2d.h
index cd270dac85..b86cf3be81 100644
--- a/scene/2d/skeleton_2d.h
+++ b/scene/2d/skeleton_2d.h
@@ -1,3 +1,33 @@
+/*************************************************************************/
+/* skeleton_2d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
#ifndef SKELETON_2D_H
#define SKELETON_2D_H
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 60766862cc..d88e148b2c 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -61,6 +61,7 @@ void TileMap::_notification(int p_what) {
}
pending_update = true;
+ _recreate_quadrants();
_update_dirty_quadrants();
RID space = get_world_2d()->get_space();
_update_quadrant_transform();
@@ -716,7 +717,7 @@ void TileMap::_make_quadrant_dirty(Map<PosKey, Quadrant>::Element *Q) {
pending_update = true;
if (!is_inside_tree())
return;
- call_deferred("_update_dirty_quadrants");
+ _update_dirty_quadrants();
}
void TileMap::set_cellv(const Vector2 &p_pos, int p_tile, bool p_flip_x, bool p_flip_y, bool p_transpose) {
@@ -844,16 +845,37 @@ void TileMap::update_cell_bitmask(int p_x, int p_y) {
if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y))) {
mask |= TileSet::BIND_BOTTOMRIGHT;
}
- } else if (tile_set->autotile_get_bitmask_mode(id) == TileSet::BITMASK_3X3) {
- if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y - 1))) {
- mask |= TileSet::BIND_TOPLEFT;
+ } else {
+ if (tile_set->autotile_get_bitmask_mode(id) == TileSet::BITMASK_3X3_MINIMAL) {
+ if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) {
+ mask |= TileSet::BIND_TOPLEFT;
+ }
+ if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y))) {
+ mask |= TileSet::BIND_TOPRIGHT;
+ }
+ if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) {
+ mask |= TileSet::BIND_BOTTOMLEFT;
+ }
+ if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y))) {
+ mask |= TileSet::BIND_BOTTOMRIGHT;
+ }
+ } else {
+ if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y - 1))) {
+ mask |= TileSet::BIND_TOPLEFT;
+ }
+ if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y - 1))) {
+ mask |= TileSet::BIND_TOPRIGHT;
+ }
+ if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y + 1))) {
+ mask |= TileSet::BIND_BOTTOMLEFT;
+ }
+ if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y + 1))) {
+ mask |= TileSet::BIND_BOTTOMRIGHT;
+ }
}
if (tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1))) {
mask |= TileSet::BIND_TOP;
}
- if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y - 1))) {
- mask |= TileSet::BIND_TOPRIGHT;
- }
if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) {
mask |= TileSet::BIND_LEFT;
}
@@ -861,15 +883,9 @@ void TileMap::update_cell_bitmask(int p_x, int p_y) {
if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y))) {
mask |= TileSet::BIND_RIGHT;
}
- if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y + 1))) {
- mask |= TileSet::BIND_BOTTOMLEFT;
- }
if (tile_set->is_tile_bound(id, get_cell(p_x, p_y + 1))) {
mask |= TileSet::BIND_BOTTOM;
}
- if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y + 1))) {
- mask |= TileSet::BIND_BOTTOMRIGHT;
- }
}
Vector2 coord = tile_set->autotile_get_subtile_for_bitmask(id, mask, this, Vector2(p_x, p_y));
E->get().autotile_coord_x = (int)coord.x;
diff --git a/scene/3d/area.cpp b/scene/3d/area.cpp
index 21f471039f..6ea980ec97 100644
--- a/scene/3d/area.cpp
+++ b/scene/3d/area.cpp
@@ -711,7 +711,7 @@ void Area::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine"), "set_space_override_mode", "get_space_override_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gravity_point"), "set_gravity_is_point", "is_gravity_a_point");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_distance_scale", PROPERTY_HINT_RANGE, "0,1024,0.001"), "set_gravity_distance_scale", "get_gravity_distance_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_distance_scale", PROPERTY_HINT_EXP_RANGE, "0,1024,0.001,or_greater"), "set_gravity_distance_scale", "get_gravity_distance_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity_vec"), "set_gravity_vector", "get_gravity_vector");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_gravity", "get_gravity");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "linear_damp", PROPERTY_HINT_RANGE, "0,1024,0.001"), "set_linear_damp", "get_linear_damp");
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index c2a50ec7bb..e7b3645001 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -898,7 +898,7 @@ void AudioStreamPlayer3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,32,0.01"), "set_pitch_scale", "get_pitch_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "is_playing");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_RANGE, "0,65536,1"), "set_max_distance", "get_max_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_EXP_RANGE, "0,4096,1,or_greater"), "set_max_distance", "get_max_distance");
ADD_PROPERTY(PropertyInfo(Variant::INT, "out_of_range_mode", PROPERTY_HINT_ENUM, "Mix,Pause"), "set_out_of_range_mode", "get_out_of_range_mode");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus");
ADD_PROPERTY(PropertyInfo(Variant::INT, "area_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_area_mask", "get_area_mask");
diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp
index 9de189c158..e11e8abe5b 100644
--- a/scene/3d/camera.cpp
+++ b/scene/3d/camera.cpp
@@ -480,8 +480,8 @@ void Camera::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "fov", PROPERTY_HINT_RANGE, "1,179,0.1"), "set_fov", "get_fov");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "size", PROPERTY_HINT_RANGE, "0.1,16384,0.01"), "set_size", "get_size");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "near"), "set_znear", "get_znear");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "far"), "set_zfar", "get_zfar");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "near", PROPERTY_HINT_EXP_RANGE, "0.1,8192,0.1,or_greater"), "set_znear", "get_znear");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "far", PROPERTY_HINT_EXP_RANGE, "0.1,8192,0.1,or_greater"), "set_zfar", "get_zfar");
BIND_ENUM_CONSTANT(PROJECTION_PERSPECTIVE);
BIND_ENUM_CONSTANT(PROJECTION_ORTHOGONAL);
diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp
index 240bd631a1..7c42638107 100644
--- a/scene/3d/light.cpp
+++ b/scene/3d/light.cpp
@@ -375,7 +375,7 @@ void DirectionalLight::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_normal_bias", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_SHADOW_NORMAL_BIAS);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_bias_split_scale", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SHADOW_BIAS_SPLIT_SCALE);
ADD_PROPERTY(PropertyInfo(Variant::INT, "directional_shadow_depth_range", PROPERTY_HINT_ENUM, "Stable,Optimized"), "set_shadow_depth_range", "get_shadow_depth_range");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_max_distance", PROPERTY_HINT_RANGE, "0,65536,0.1"), "set_param", "get_param", PARAM_SHADOW_MAX_DISTANCE);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_max_distance", PROPERTY_HINT_EXP_RANGE, "0,8192,0.1,or_greater"), "set_param", "get_param", PARAM_SHADOW_MAX_DISTANCE);
BIND_ENUM_CONSTANT(SHADOW_ORTHOGONAL);
BIND_ENUM_CONSTANT(SHADOW_PARALLEL_2_SPLITS);
@@ -428,8 +428,8 @@ void OmniLight::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_shadow_detail"), &OmniLight::get_shadow_detail);
ADD_GROUP("Omni", "omni_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "omni_range", PROPERTY_HINT_RANGE, "0,65536,0.1"), "set_param", "get_param", PARAM_RANGE);
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "omni_attenuation", PROPERTY_HINT_EXP_EASING), "set_param", "get_param", PARAM_ATTENUATION);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "omni_range", PROPERTY_HINT_EXP_RANGE, "0,4096,0.1,or_greater"), "set_param", "get_param", PARAM_RANGE);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "omni_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_ATTENUATION);
ADD_PROPERTY(PropertyInfo(Variant::INT, "omni_shadow_mode", PROPERTY_HINT_ENUM, "Dual Paraboloid,Cube"), "set_shadow_mode", "get_shadow_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "omni_shadow_detail", PROPERTY_HINT_ENUM, "Vertical,Horizontal"), "set_shadow_detail", "get_shadow_detail");
@@ -450,8 +450,8 @@ OmniLight::OmniLight() :
void SpotLight::_bind_methods() {
ADD_GROUP("Spot", "spot_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_range", PROPERTY_HINT_RANGE, "0,65536,0.1"), "set_param", "get_param", PARAM_RANGE);
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_attenuation", PROPERTY_HINT_EXP_EASING), "set_param", "get_param", PARAM_ATTENUATION);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_range", PROPERTY_HINT_EXP_RANGE, "0,4096,0.1,or_greater"), "set_param", "get_param", PARAM_RANGE);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_ATTENUATION);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_angle", PROPERTY_HINT_RANGE, "0,180,0.1"), "set_param", "get_param", PARAM_SPOT_ANGLE);
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_angle_attenuation", PROPERTY_HINT_EXP_EASING), "set_param", "get_param", PARAM_SPOT_ATTENUATION);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_angle_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_SPOT_ATTENUATION);
}
diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp
index a39ac5a8f5..7b5eb8ebc3 100644
--- a/scene/3d/particles.cpp
+++ b/scene/3d/particles.cpp
@@ -324,11 +324,11 @@ void Particles::_bind_methods() {
ClassDB::bind_method(D_METHOD("capture_aabb"), &Particles::capture_aabb);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,100000,1"), "set_amount", "get_amount");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount");
ADD_GROUP("Time", "");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_speed_scale", "get_speed_scale");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio");
@@ -1460,26 +1460,26 @@ void ParticlesMaterial::_bind_methods() {
ADD_GROUP("Gravity", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity");
ADD_GROUP("Initial Velocity", "initial_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity", PROPERTY_HINT_RANGE, "0,1000,0.01"), "set_param", "get_param", PARAM_INITIAL_LINEAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_GROUP("Angular Velocity", "angular_");
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity", PROPERTY_HINT_RANGE, "-360,360,0.01"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGULAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGULAR_VELOCITY);
ADD_GROUP("Orbit Velocity", "orbit_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity", PROPERTY_HINT_RANGE, "-1000,1000,0.01"), "set_param", "get_param", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ORBIT_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ORBIT_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ORBIT_VELOCITY);
ADD_GROUP("Linear Accel", "linear_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel", PROPERTY_HINT_RANGE, "-100,100,0.01"), "set_param", "get_param", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_LINEAR_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_LINEAR_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_LINEAR_ACCEL);
ADD_GROUP("Radial Accel", "radial_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "radial_accel", PROPERTY_HINT_RANGE, "-100,100,0.01"), "set_param", "get_param", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "radial_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_RADIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "radial_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_RADIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_RADIAL_ACCEL);
ADD_GROUP("Tangential Accel", "tangential_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "tangential_accel", PROPERTY_HINT_RANGE, "-100,100,0.01"), "set_param", "get_param", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "tangential_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_TANGENTIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "tangential_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_TANGENTIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_TANGENTIAL_ACCEL);
ADD_GROUP("Damping", "");
@@ -1487,11 +1487,11 @@ void ParticlesMaterial::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_DAMPING);
ADD_GROUP("Angle", "");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1"), "set_param", "get_param", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGLE);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angle_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGLE);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGLE);
ADD_GROUP("Scale", "");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale", PROPERTY_HINT_RANGE, "0,1000,0.01"), "set_param", "get_param", PARAM_SCALE);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_SCALE);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_SCALE);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "scale_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_SCALE);
ADD_GROUP("Color", "");
@@ -1503,7 +1503,7 @@ void ParticlesMaterial::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "hue_variation_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_HUE_VARIATION);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_HUE_VARIATION);
ADD_GROUP("Animation", "anim_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_param", "get_param", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_param", "get_param", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET);
diff --git a/scene/3d/path.cpp b/scene/3d/path.cpp
index 57d79c960f..154dcb4259 100644
--- a/scene/3d/path.cpp
+++ b/scene/3d/path.cpp
@@ -230,7 +230,7 @@ void PathFollow::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_loop", "loop"), &PathFollow::set_loop);
ClassDB::bind_method(D_METHOD("has_loop"), &PathFollow::has_loop);
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset", PROPERTY_HINT_RANGE, "0,10000,0.01"), "set_offset", "get_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset", PROPERTY_HINT_EXP_RANGE, "0,10000,0.01,or_greater"), "set_offset", "get_offset");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "h_offset"), "set_h_offset", "get_h_offset");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_offset"), "set_v_offset", "get_v_offset");
diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp
index 5512fd4f10..5056fb2fe4 100644
--- a/scene/3d/physics_body.cpp
+++ b/scene/3d/physics_body.cpp
@@ -1400,7 +1400,7 @@ void PhysicalBone::ConeJointData::_get_property_list(List<PropertyInfo> *p_list)
JointData::_get_property_list(p_list);
p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/swing_span", PROPERTY_HINT_RANGE, "-180,180,0.01"));
- p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/twist_span", PROPERTY_HINT_RANGE, "-40000,40000,0.1"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/twist_span", PROPERTY_HINT_RANGE, "-40000,40000,0.1,or_lesser,or_greater"));
p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/bias", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/relaxation", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
@@ -1825,6 +1825,7 @@ void PhysicalBone::_notification(int p_what) {
parent_skeleton = find_skeleton_parent(get_parent());
update_bone_id();
reset_to_rest_position();
+ _reset_physics_simulation_state();
break;
case NOTIFICATION_EXIT_TREE:
if (parent_skeleton) {
@@ -1886,10 +1887,8 @@ void PhysicalBone::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_body_offset", "offset"), &PhysicalBone::set_body_offset);
ClassDB::bind_method(D_METHOD("get_body_offset"), &PhysicalBone::get_body_offset);
- ClassDB::bind_method(D_METHOD("set_static_body", "simulate"), &PhysicalBone::set_static_body);
ClassDB::bind_method(D_METHOD("is_static_body"), &PhysicalBone::is_static_body);
- ClassDB::bind_method(D_METHOD("set_simulate_physics", "simulate"), &PhysicalBone::set_simulate_physics);
ClassDB::bind_method(D_METHOD("get_simulate_physics"), &PhysicalBone::get_simulate_physics);
ClassDB::bind_method(D_METHOD("is_simulating_physics"), &PhysicalBone::is_simulating_physics);
@@ -1913,9 +1912,7 @@ void PhysicalBone::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "joint_type", PROPERTY_HINT_ENUM, "None,PinJoint,ConeJoint,HingeJoint,SliderJoint,6DOFJoint"), "set_joint_type", "get_joint_type");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "joint_offset"), "set_joint_offset", "get_joint_offset");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "simulate_physics"), "set_simulate_physics", "get_simulate_physics");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "body_offset"), "set_body_offset", "get_body_offset");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "static_body"), "set_static_body", "is_static_body");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "mass", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_mass", "get_mass");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_weight", "get_weight");
@@ -2255,8 +2252,8 @@ PhysicalBone::PhysicalBone() :
joint_data(NULL),
static_body(false),
simulate_physics(false),
- _internal_static_body(!static_body),
- _internal_simulate_physics(simulate_physics),
+ _internal_static_body(false),
+ _internal_simulate_physics(false),
bone_id(-1),
parent_skeleton(NULL),
bone_name(""),
diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp
index 2178da02b5..7e3a87cbd4 100644
--- a/scene/3d/reflection_probe.cpp
+++ b/scene/3d/reflection_probe.cpp
@@ -240,7 +240,7 @@ void ReflectionProbe::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "Once,Always"), "set_update_mode", "get_update_mode");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "intensity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_intensity", "get_intensity");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_RANGE, "0,16384,0.1"), "set_max_distance", "get_max_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_EXP_RANGE, "0,16384,0.1,or_greater"), "set_max_distance", "get_max_distance");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "extents"), "set_extents", "get_extents");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "origin_offset"), "set_origin_offset", "get_origin_offset");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "box_projection"), "set_enable_box_projection", "is_box_projection_enabled");
diff --git a/scene/3d/scenario_fx.cpp b/scene/3d/scenario_fx.cpp
index d5bff676cb..26cbfc0b11 100644
--- a/scene/3d/scenario_fx.cpp
+++ b/scene/3d/scenario_fx.cpp
@@ -93,9 +93,10 @@ String WorldEnvironment::get_configuration_warning() const {
return TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes).");
}
- if (environment.is_valid() && get_viewport() && !get_viewport()->get_camera() && environment->get_background() != Environment::BG_CANVAS) {
- return TTR("This WorldEnvironment is ignored. Either add a Camera (for 3D scenes) or set this environment's Background Mode to Canvas (for 2D scenes).");
- }
+ // Commenting this warning for now, I think it makes no sense. If anyone can figure out what its supposed to do, feedback welcome. Else it should be deprecated.
+ //if (environment.is_valid() && get_viewport() && !get_viewport()->get_camera() && environment->get_background() != Environment::BG_CANVAS) {
+ // return TTR("This WorldEnvironment is ignored. Either add a Camera (for 3D scenes) or set this environment's Background Mode to Canvas (for 2D scenes).");
+ //}
return String();
}
diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp
index a7eb54c85d..76d90dc6ff 100644
--- a/scene/3d/skeleton.cpp
+++ b/scene/3d/skeleton.cpp
@@ -330,7 +330,7 @@ void Skeleton::add_bone(const String &p_name) {
_make_dirty();
update_gizmo();
}
-int Skeleton::find_bone(String p_name) const {
+int Skeleton::find_bone(const String &p_name) const {
for (int i = 0; i < bones.size(); i++) {
@@ -347,6 +347,19 @@ String Skeleton::get_bone_name(int p_bone) const {
return bones[p_bone].name;
}
+bool Skeleton::is_bone_parent_of(int p_bone, int p_parent_bone_id) const {
+
+ int parent_of_bone = get_bone_parent(p_bone);
+
+ if (-1 == parent_of_bone)
+ return false;
+
+ if (parent_of_bone == p_parent_bone_id)
+ return true;
+
+ return is_bone_parent_of(parent_of_bone, p_parent_bone_id);
+}
+
int Skeleton::get_bone_count() const {
return bones.size();
@@ -534,18 +547,6 @@ void Skeleton::localize_rests() {
}
}
-void _notify_physical_bones_simulation(bool start, Node *p_node) {
-
- for (int i = p_node->get_child_count() - 1; 0 <= i; --i) {
- _notify_physical_bones_simulation(start, p_node->get_child(i));
- }
-
- PhysicalBone *pb = Object::cast_to<PhysicalBone>(p_node);
- if (pb) {
- pb->set_simulate_physics(start);
- }
-}
-
void Skeleton::bind_physical_bone_to_bone(int p_bone, PhysicalBone *p_physical_bone) {
ERR_FAIL_INDEX(p_bone, bones.size());
ERR_FAIL_COND(bones[p_bone].physical_bone);
@@ -603,8 +604,67 @@ void Skeleton::_rebuild_physical_bones_cache() {
}
}
-void Skeleton::physical_bones_simulation(bool start) {
- _notify_physical_bones_simulation(start, this);
+void _pb_stop_simulation(Node *p_node) {
+
+ for (int i = p_node->get_child_count() - 1; 0 <= i; --i) {
+ _pb_stop_simulation(p_node->get_child(i));
+ }
+
+ PhysicalBone *pb = Object::cast_to<PhysicalBone>(p_node);
+ if (pb) {
+ pb->set_simulate_physics(false);
+ pb->set_static_body(false);
+ }
+}
+
+void Skeleton::physical_bones_stop_simulation() {
+ _pb_stop_simulation(this);
+}
+
+void _pb_start_simulation(const Skeleton *p_skeleton, Node *p_node, const Vector<int> &p_sim_bones) {
+
+ for (int i = p_node->get_child_count() - 1; 0 <= i; --i) {
+ _pb_start_simulation(p_skeleton, p_node->get_child(i), p_sim_bones);
+ }
+
+ PhysicalBone *pb = Object::cast_to<PhysicalBone>(p_node);
+ if (pb) {
+ bool sim = false;
+ for (int i = p_sim_bones.size() - 1; 0 <= i; --i) {
+ if (p_sim_bones[i] == pb->get_bone_id() || p_skeleton->is_bone_parent_of(pb->get_bone_id(), p_sim_bones[i])) {
+ sim = true;
+ break;
+ }
+ }
+
+ pb->set_simulate_physics(true);
+ if (sim) {
+ pb->set_static_body(false);
+ } else {
+ pb->set_static_body(true);
+ }
+ }
+}
+
+void Skeleton::physical_bones_start_simulation_on(const Array &p_bones) {
+
+ Vector<int> sim_bones;
+ if (p_bones.size() <= 0) {
+ sim_bones.push_back(0); // if no bones is specified, activate ragdoll on full body
+ } else {
+ sim_bones.resize(p_bones.size());
+ int c = 0;
+ for (int i = sim_bones.size() - 1; 0 <= i; --i) {
+ if (Variant::STRING == p_bones.get(i).get_type()) {
+ int bone_id = find_bone(p_bones.get(i));
+ if (bone_id != -1)
+ sim_bones[c++] = bone_id;
+ }
+ }
+ sim_bones.resize(c);
+ }
+
+ _pb_start_simulation(this, this, sim_bones);
}
void _physical_bones_add_remove_collision_exception(bool p_add, Node *p_node, RID p_exception) {
@@ -667,7 +727,8 @@ void Skeleton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_bone_transform", "bone_idx"), &Skeleton::get_bone_transform);
- ClassDB::bind_method(D_METHOD("physical_bones_simulation", "start"), &Skeleton::physical_bones_simulation);
+ ClassDB::bind_method(D_METHOD("physical_bones_stop_simulation"), &Skeleton::physical_bones_stop_simulation);
+ ClassDB::bind_method(D_METHOD("physical_bones_start_simulation", "bones"), &Skeleton::physical_bones_start_simulation_on, DEFVAL(Array()));
ClassDB::bind_method(D_METHOD("physical_bones_add_collision_exception", "exception"), &Skeleton::physical_bones_add_collision_exception);
ClassDB::bind_method(D_METHOD("physical_bones_remove_collision_exception", "exception"), &Skeleton::physical_bones_remove_collision_exception);
@@ -683,6 +744,5 @@ Skeleton::Skeleton() {
}
Skeleton::~Skeleton() {
-
VisualServer::get_singleton()->free(skeleton);
}
diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h
index f0e71c8b4f..dad11960a5 100644
--- a/scene/3d/skeleton.h
+++ b/scene/3d/skeleton.h
@@ -120,9 +120,11 @@ public:
// skeleton creation api
void add_bone(const String &p_name);
- int find_bone(String p_name) const;
+ int find_bone(const String &p_name) const;
String get_bone_name(int p_bone) const;
+ bool is_bone_parent_of(int p_bone_id, int p_parent_bone_id) const;
+
void set_bone_parent(int p_bone, int p_parent);
int get_bone_parent(int p_bone) const;
@@ -176,7 +178,8 @@ private:
void _rebuild_physical_bones_cache();
public:
- void physical_bones_simulation(bool start);
+ void physical_bones_stop_simulation();
+ void physical_bones_start_simulation_on(const Array &p_bones);
void physical_bones_add_collision_exception(RID p_exception);
void physical_bones_remove_collision_exception(RID p_exception);
diff --git a/scene/3d/vehicle_body.cpp b/scene/3d/vehicle_body.cpp
index b72665aa2b..ee8d249981 100644
--- a/scene/3d/vehicle_body.cpp
+++ b/scene/3d/vehicle_body.cpp
@@ -672,13 +672,8 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) {
m_forwardImpulse.resize(numWheel);
m_sideImpulse.resize(numWheel);
- int numWheelsOnGround = 0;
-
//collapse all those loops into one!
for (int i = 0; i < wheels.size(); i++) {
- VehicleWheel &wheelInfo = *wheels[i];
- if (wheelInfo.m_raycastInfo.m_isInContact)
- numWheelsOnGround++;
m_sideImpulse[i] = real_t(0.);
m_forwardImpulse[i] = real_t(0.);
}
@@ -929,7 +924,7 @@ void VehicleBody::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_steering"), &VehicleBody::get_steering);
ADD_GROUP("Motion", "");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "engine_force", PROPERTY_HINT_RANGE, "0.00,1024.0,0.01"), "set_engine_force", "get_engine_force");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "engine_force", PROPERTY_HINT_RANGE, "0.00,1024.0,0.01,or_greater"), "set_engine_force", "get_engine_force");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "brake", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_brake", "get_brake");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "steering", PROPERTY_HINT_RANGE, "-180,180.0,0.01"), "set_steering", "get_steering");
}
diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp
index 13700e0bd3..670df5cc7f 100644
--- a/scene/3d/voxel_light_baker.cpp
+++ b/scene/3d/voxel_light_baker.cpp
@@ -2316,13 +2316,10 @@ Ref<MultiMesh> VoxelLightBaker::create_debug_multimesh(DebugMode p_mode) {
PoolVector<Vector3> vertices;
PoolVector<Color> colors;
-
- int vtx_idx = 0;
#define ADD_VTX(m_idx) \
; \
vertices.push_back(face_points[m_idx]); \
- colors.push_back(Color(1, 1, 1, 1)); \
- vtx_idx++;
+ colors.push_back(Color(1, 1, 1, 1));
for (int i = 0; i < 6; i++) {
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index c0d1e62e07..a0e0137863 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -507,7 +507,6 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float
void AnimationPlayer::_animation_process_data(PlaybackData &cd, float p_delta, float p_blend) {
float delta = p_delta * speed_scale * cd.speed_scale;
- bool backwards = delta < 0;
float next_pos = cd.pos + delta;
float len = cd.from->animation->get_length();
@@ -525,6 +524,8 @@ void AnimationPlayer::_animation_process_data(PlaybackData &cd, float p_delta, f
if (&cd == &playback.current) {
+ bool backwards = delta < 0;
+
if (!backwards && cd.pos <= len && next_pos == len /*&& playback.blend.empty()*/) {
//playback finished
end_reached = true;
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 6f34f3e49f..34891832e2 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -656,8 +656,9 @@ ColorPicker::ColorPicker() :
void ColorPickerButton::_color_changed(const Color &p_color) {
+ color = p_color;
update();
- emit_signal("color_changed", p_color);
+ emit_signal("color_changed", color);
}
void ColorPickerButton::_modal_closed() {
@@ -667,6 +668,7 @@ void ColorPickerButton::_modal_closed() {
void ColorPickerButton::pressed() {
+ _update_picker();
popup->set_position(get_global_position() - picker->get_combined_minimum_size());
popup->popup();
picker->set_focus_on_line_edit();
@@ -679,37 +681,44 @@ void ColorPickerButton::_notification(int p_what) {
Ref<StyleBox> normal = get_stylebox("normal");
Rect2 r = Rect2(normal->get_offset(), get_size() - normal->get_minimum_size());
draw_texture_rect(Control::get_icon("bg", "ColorPickerButton"), r, true);
- draw_rect(r, picker->get_pick_color());
+ draw_rect(r, color);
}
- if (p_what == MainLoop::NOTIFICATION_WM_QUIT_REQUEST) {
+ if (p_what == MainLoop::NOTIFICATION_WM_QUIT_REQUEST && popup) {
popup->hide();
}
}
void ColorPickerButton::set_pick_color(const Color &p_color) {
- picker->set_pick_color(p_color);
+ color = p_color;
+ if (picker) {
+ picker->set_pick_color(p_color);
+ }
+
update();
- emit_signal("color_changed", p_color);
}
Color ColorPickerButton::get_pick_color() const {
- return picker->get_pick_color();
+ return color;
}
void ColorPickerButton::set_edit_alpha(bool p_show) {
- picker->set_edit_alpha(p_show);
+ edit_alpha = p_show;
+ if (picker) {
+ picker->set_edit_alpha(p_show);
+ }
}
bool ColorPickerButton::is_editing_alpha() const {
- return picker->is_editing_alpha();
+ return edit_alpha;
}
-ColorPicker *ColorPickerButton::get_picker() const {
+ColorPicker *ColorPickerButton::get_picker() {
+ _update_picker();
return picker;
}
@@ -718,6 +727,19 @@ PopupPanel *ColorPickerButton::get_popup() const {
return popup;
}
+void ColorPickerButton::_update_picker() {
+ if (!picker) {
+ popup = memnew(PopupPanel);
+ picker = memnew(ColorPicker);
+ popup->add_child(picker);
+ add_child(popup);
+ picker->connect("color_changed", this, "_color_changed");
+ popup->connect("modal_closed", this, "_modal_closed");
+ picker->set_pick_color(color);
+ picker->set_edit_alpha(edit_alpha);
+ }
+}
+
void ColorPickerButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pick_color", "color"), &ColorPickerButton::set_pick_color);
@@ -737,12 +759,10 @@ void ColorPickerButton::_bind_methods() {
ColorPickerButton::ColorPickerButton() {
- popup = memnew(PopupPanel);
- picker = memnew(ColorPicker);
- popup->add_child(picker);
-
- picker->connect("color_changed", this, "_color_changed");
- popup->connect("modal_closed", this, "_modal_closed");
-
- add_child(popup);
+ //Initialization is now done deferred
+ //this improves performance in the inspector as the color picker
+ //can be expensive to initialize
+ picker = NULL;
+ popup = NULL;
+ edit_alpha = true;
}
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index 7d1a554ada..6b63e5fe60 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -118,12 +118,16 @@ class ColorPickerButton : public Button {
PopupPanel *popup;
ColorPicker *picker;
+ Color color;
+ bool edit_alpha;
void _color_changed(const Color &p_color);
void _modal_closed();
virtual void pressed();
+ void _update_picker();
+
protected:
void _notification(int);
static void _bind_methods();
@@ -135,7 +139,7 @@ public:
void set_edit_alpha(bool p_show);
bool is_editing_alpha() const;
- ColorPicker *get_picker() const;
+ ColorPicker *get_picker();
PopupPanel *get_popup() const;
ColorPickerButton();
diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp
index 7cb0ad5707..7df03bf7c6 100644
--- a/scene/gui/container.cpp
+++ b/scene/gui/container.cpp
@@ -34,9 +34,9 @@
void Container::_child_minsize_changed() {
- Size2 ms = get_combined_minimum_size();
- if (ms.width > get_size().width || ms.height > get_size().height)
- minimum_size_changed();
+ //Size2 ms = get_combined_minimum_size();
+ //if (ms.width > get_size().width || ms.height > get_size().height) {
+ minimum_size_changed();
queue_sort();
}
@@ -51,6 +51,8 @@ void Container::add_child_notify(Node *p_child) {
control->connect("size_flags_changed", this, "queue_sort");
control->connect("minimum_size_changed", this, "_child_minsize_changed");
control->connect("visibility_changed", this, "_child_minsize_changed");
+
+ minimum_size_changed();
queue_sort();
}
@@ -61,6 +63,7 @@ void Container::move_child_notify(Node *p_child) {
if (!Object::cast_to<Control>(p_child))
return;
+ minimum_size_changed();
queue_sort();
}
@@ -75,6 +78,8 @@ void Container::remove_child_notify(Node *p_child) {
control->disconnect("size_flags_changed", this, "queue_sort");
control->disconnect("minimum_size_changed", this, "_child_minsize_changed");
control->disconnect("visibility_changed", this, "_child_minsize_changed");
+
+ minimum_size_changed();
queue_sort();
}
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index b7c1d35fd7..d07b5a9f65 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -155,12 +155,21 @@ Size2 Control::get_custom_minimum_size() const {
return data.custom_minimum_size;
}
-Size2 Control::get_combined_minimum_size() const {
+void Control::_update_minimum_size_cache() {
Size2 minsize = get_minimum_size();
minsize.x = MAX(minsize.x, data.custom_minimum_size.x);
minsize.y = MAX(minsize.y, data.custom_minimum_size.y);
- return minsize;
+ data.minimum_size_cache = minsize;
+ data.minimum_size_valid = true;
+}
+
+Size2 Control::get_combined_minimum_size() const {
+
+ if (!data.minimum_size_valid) {
+ const_cast<Control *>(this)->_update_minimum_size_cache();
+ }
+ return data.minimum_size_cache;
}
Size2 Control::_edit_get_minimum_size() const {
@@ -259,14 +268,18 @@ void Control::_update_minimum_size() {
if (!is_inside_tree())
return;
- data.pending_min_size_update = false;
Size2 minsize = get_combined_minimum_size();
if (minsize.x > data.size_cache.x ||
minsize.y > data.size_cache.y) {
_size_changed();
}
- emit_signal(SceneStringNames::get_singleton()->minimum_size_changed);
+ data.updating_last_minimum_size = false;
+
+ if (minsize != data.last_minimum_size) {
+ data.last_minimum_size = minsize;
+ emit_signal(SceneStringNames::get_singleton()->minimum_size_changed);
+ }
}
bool Control::_get(const StringName &p_name, Variant &r_ret) const {
@@ -437,8 +450,12 @@ void Control::_notification(int p_notification) {
case NOTIFICATION_ENTER_TREE: {
- _size_changed();
-
+ } break;
+ case NOTIFICATION_POST_ENTER_TREE: {
+ if (is_visible_in_tree()) {
+ data.minimum_size_valid = false;
+ _size_changed();
+ }
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -620,13 +637,12 @@ void Control::_notification(int p_notification) {
if (is_inside_tree()) {
_modal_stack_remove();
- minimum_size_changed();
}
//remove key focus
//remove modalness
} else {
-
+ data.minimum_size_valid = false;
_size_changed();
}
@@ -2464,17 +2480,25 @@ void Control::minimum_size_changed() {
if (!is_inside_tree() || data.block_minimum_size_adjust)
return;
- if (data.pending_min_size_update)
+ Control *invalidate = this;
+
+ //invalidate cache upwards
+ while (invalidate && invalidate->data.minimum_size_valid) {
+ invalidate->data.minimum_size_valid = false;
+ if (invalidate->is_set_as_toplevel())
+ break; // do not go further up
+ invalidate = invalidate->data.parent;
+ }
+
+ if (!is_visible_in_tree())
+ return;
+
+ if (data.updating_last_minimum_size)
return;
- data.pending_min_size_update = true;
- MessageQueue::get_singleton()->push_call(this, "_update_minimum_size");
+ data.updating_last_minimum_size = true;
- if (!is_toplevel_control()) {
- Control *pc = get_parent_control();
- if (pc)
- pc->minimum_size_changed();
- }
+ MessageQueue::get_singleton()->push_call(this, "_update_minimum_size");
}
int Control::get_v_size_flags() const {
@@ -2985,7 +3009,6 @@ Control::Control() {
data.h_size_flags = SIZE_FILL;
data.v_size_flags = SIZE_FILL;
data.expand = 1;
- data.pending_min_size_update = false;
data.rotation = 0;
data.parent_canvas_item = NULL;
data.scale = Vector2(1, 1);
@@ -2995,6 +3018,8 @@ Control::Control() {
data.disable_visibility_clip = false;
data.h_grow = GROW_DIRECTION_END;
data.v_grow = GROW_DIRECTION_END;
+ data.minimum_size_valid = false;
+ data.updating_last_minimum_size = false;
data.clip_contents = false;
for (int i = 0; i < 4; i++) {
diff --git a/scene/gui/control.h b/scene/gui/control.h
index b5453e60f5..9124256624 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -148,6 +148,11 @@ private:
Point2 pos_cache;
Size2 size_cache;
+ Size2 minimum_size_cache;
+ bool minimum_size_valid;
+
+ Size2 last_minimum_size;
+ bool updating_last_minimum_size;
float margin[4];
float anchor[4];
@@ -164,7 +169,6 @@ private:
int h_size_flags;
int v_size_flags;
float expand;
- bool pending_min_size_update;
Point2 custom_minimum_size;
bool pass_on_modal_close_click;
@@ -244,6 +248,8 @@ private:
void _modal_stack_remove();
void _modal_set_prev_focus_owner(ObjectID p_prev);
+ void _update_minimum_size_cache();
+
protected:
virtual void add_child_notify(Node *p_child);
virtual void remove_child_notify(Node *p_child);
diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp
index 9fc8e98a7f..b5622604e2 100644
--- a/scene/gui/gradient_edit.cpp
+++ b/scene/gui/gradient_edit.cpp
@@ -147,6 +147,7 @@ void GradientEdit::_gui_input(const Ref<InputEvent> &p_event) {
grabbed = _get_point_from_pos(x);
//grab or select
if (grabbed != -1) {
+ grabbed = false;
return;
}
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index f1b0d36f32..9af479c1cc 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -103,7 +103,8 @@ void Label::_notification(int p_what) {
int lines_visible = (size.y + line_spacing) / font_h;
- int space_w = font->get_char_size(' ').width;
+ // ceiling to ensure autowrapping does not cut text
+ int space_w = Math::ceil(font->get_char_size(' ').width);
int chars_total = 0;
int vbegin = 0, vsep = 0;
@@ -331,7 +332,8 @@ int Label::get_longest_line_width() const {
}
} else {
- int char_width = font->get_char_size(current, xl_text[i + 1]).width;
+ // ceiling to ensure autowrapping does not cut text
+ int char_width = Math::ceil(font->get_char_size(current, xl_text[i + 1]).width);
line_width += char_width;
}
}
@@ -384,7 +386,8 @@ void Label::regenerate_word_cache() {
int word_pos = 0;
int line_width = 0;
int space_count = 0;
- int space_width = font->get_char_size(' ').width;
+ // ceiling to ensure autowrapping does not cut text
+ int space_width = Math::ceil(font->get_char_size(' ').width);
int line_spacing = get_constant("line_spacing");
line_count = 1;
total_char_cache = 0;
@@ -446,8 +449,8 @@ void Label::regenerate_word_cache() {
if (current_word_size == 0) {
word_pos = i;
}
-
- char_width = font->get_char_size(current, xl_text[i + 1]).width;
+ // ceiling to ensure autowrapping does not cut text
+ char_width = Math::ceil(font->get_char_size(current, xl_text[i + 1]).width);
current_word_size += char_width;
line_width += char_width;
total_char_cache++;
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index fd2466407e..93865cebde 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -533,6 +533,7 @@ void PopupMenu::add_icon_item(const Ref<Texture> &p_icon, const String &p_label,
item.ID = p_ID;
items.push_back(item);
update();
+ minimum_size_changed();
}
void PopupMenu::add_item(const String &p_label, int p_ID, uint32_t p_accel) {
@@ -543,6 +544,7 @@ void PopupMenu::add_item(const String &p_label, int p_ID, uint32_t p_accel) {
item.ID = p_ID;
items.push_back(item);
update();
+ minimum_size_changed();
}
void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu, int p_ID) {
@@ -554,6 +556,7 @@ void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu,
item.submenu = p_submenu;
items.push_back(item);
update();
+ minimum_size_changed();
}
void PopupMenu::add_icon_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_ID, uint32_t p_accel) {
@@ -567,6 +570,7 @@ void PopupMenu::add_icon_check_item(const Ref<Texture> &p_icon, const String &p_
item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
items.push_back(item);
update();
+ minimum_size_changed();
}
void PopupMenu::add_check_item(const String &p_label, int p_ID, uint32_t p_accel) {
@@ -579,6 +583,7 @@ void PopupMenu::add_check_item(const String &p_label, int p_ID, uint32_t p_accel
item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
items.push_back(item);
update();
+ minimum_size_changed();
}
void PopupMenu::add_radio_check_item(const String &p_label, int p_ID, uint32_t p_accel) {
@@ -586,6 +591,7 @@ void PopupMenu::add_radio_check_item(const String &p_label, int p_ID, uint32_t p
add_check_item(p_label, p_ID, p_accel);
items[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
update();
+ minimum_size_changed();
}
void PopupMenu::add_icon_radio_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_ID, uint32_t p_accel) {
@@ -593,6 +599,7 @@ void PopupMenu::add_icon_radio_check_item(const Ref<Texture> &p_icon, const Stri
add_icon_check_item(p_icon, p_label, p_ID, p_accel);
items[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
update();
+ minimum_size_changed();
}
void PopupMenu::add_icon_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_ID, bool p_global) {
@@ -608,6 +615,7 @@ void PopupMenu::add_icon_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut
item.shortcut_is_global = p_global;
items.push_back(item);
update();
+ minimum_size_changed();
}
void PopupMenu::add_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bool p_global) {
@@ -622,6 +630,7 @@ void PopupMenu::add_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bool p_g
item.shortcut_is_global = p_global;
items.push_back(item);
update();
+ minimum_size_changed();
}
void PopupMenu::add_icon_check_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_ID, bool p_global) {
@@ -638,6 +647,7 @@ void PopupMenu::add_icon_check_shortcut(const Ref<Texture> &p_icon, const Ref<Sh
item.shortcut_is_global = p_global;
items.push_back(item);
update();
+ minimum_size_changed();
}
void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bool p_global) {
@@ -653,6 +663,7 @@ void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bo
item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
items.push_back(item);
update();
+ minimum_size_changed();
}
void PopupMenu::add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bool p_global) {
@@ -660,6 +671,7 @@ void PopupMenu::add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_
add_check_shortcut(p_shortcut, p_ID, p_global);
items[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
update();
+ minimum_size_changed();
}
void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int p_default_state, int p_ID, uint32_t p_accel) {
@@ -673,6 +685,7 @@ void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int
item.state = p_default_state;
items.push_back(item);
update();
+ minimum_size_changed();
}
void PopupMenu::set_item_text(int p_idx, const String &p_text) {
@@ -682,6 +695,7 @@ void PopupMenu::set_item_text(int p_idx, const String &p_text) {
items[p_idx].xl_text = tr(p_text);
update();
+ minimum_size_changed();
}
void PopupMenu::set_item_icon(int p_idx, const Ref<Texture> &p_icon) {
@@ -689,6 +703,7 @@ void PopupMenu::set_item_icon(int p_idx, const Ref<Texture> &p_icon) {
items[p_idx].icon = p_icon;
update();
+ minimum_size_changed();
}
void PopupMenu::set_item_checked(int p_idx, bool p_checked) {
@@ -697,6 +712,7 @@ void PopupMenu::set_item_checked(int p_idx, bool p_checked) {
items[p_idx].checked = p_checked;
update();
+ minimum_size_changed();
}
void PopupMenu::set_item_id(int p_idx, int p_ID) {
@@ -704,6 +720,7 @@ void PopupMenu::set_item_id(int p_idx, int p_ID) {
items[p_idx].ID = p_ID;
update();
+ minimum_size_changed();
}
void PopupMenu::set_item_accelerator(int p_idx, uint32_t p_accel) {
@@ -712,6 +729,7 @@ void PopupMenu::set_item_accelerator(int p_idx, uint32_t p_accel) {
items[p_idx].accel = p_accel;
update();
+ minimum_size_changed();
}
void PopupMenu::set_item_metadata(int p_idx, const Variant &p_meta) {
@@ -719,6 +737,7 @@ void PopupMenu::set_item_metadata(int p_idx, const Variant &p_meta) {
ERR_FAIL_INDEX(p_idx, items.size());
items[p_idx].metadata = p_meta;
update();
+ minimum_size_changed();
}
void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) {
@@ -726,6 +745,7 @@ void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) {
ERR_FAIL_INDEX(p_idx, items.size());
items[p_idx].disabled = p_disabled;
update();
+ minimum_size_changed();
}
void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) {
@@ -733,6 +753,7 @@ void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) {
ERR_FAIL_INDEX(p_idx, items.size());
items[p_idx].submenu = p_submenu;
update();
+ minimum_size_changed();
}
void PopupMenu::toggle_item_checked(int p_idx) {
@@ -740,6 +761,7 @@ void PopupMenu::toggle_item_checked(int p_idx) {
ERR_FAIL_INDEX(p_idx, items.size());
items[p_idx].checked = !items[p_idx].checked;
update();
+ minimum_size_changed();
}
String PopupMenu::get_item_text(int p_idx) const {
@@ -881,6 +903,7 @@ void PopupMenu::set_item_h_offset(int p_idx, int p_offset) {
ERR_FAIL_INDEX(p_idx, items.size());
items[p_idx].h_ofs = p_offset;
update();
+ minimum_size_changed();
}
void PopupMenu::set_item_multistate(int p_idx, int p_state) {
@@ -1045,6 +1068,7 @@ void PopupMenu::clear() {
items.clear();
mouse_over = -1;
update();
+ minimum_size_changed();
}
Array PopupMenu::_get_items() const {
diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp
index cd6c6bb65c..4062e48640 100644
--- a/scene/gui/range.cpp
+++ b/scene/gui/range.cpp
@@ -71,10 +71,10 @@ void Range::set_value(double p_val) {
p_val = Math::round(p_val);
}
- if (p_val > shared->max - shared->page)
+ if (!shared->allow_greater && p_val > shared->max - shared->page)
p_val = shared->max - shared->page;
- if (p_val < shared->min)
+ if (!shared->allow_lesser && p_val < shared->min)
p_val = shared->min;
if (shared->val == p_val)
@@ -136,9 +136,9 @@ void Range::set_as_ratio(double p_value) {
double v;
- if (shared->exp_ratio && get_min() > 0) {
+ if (shared->exp_ratio && get_min() >= 0) {
- double exp_min = Math::log(get_min()) / Math::log((double)2);
+ double exp_min = get_min() == 0 ? 0.0 : Math::log(get_min()) / Math::log((double)2);
double exp_max = Math::log(get_max()) / Math::log((double)2);
v = Math::pow(2, exp_min + (exp_max - exp_min) * p_value);
} else {
@@ -151,21 +151,24 @@ void Range::set_as_ratio(double p_value) {
v = percent + get_min();
}
}
+ v = CLAMP(v, get_min(), get_max());
set_value(v);
}
double Range::get_as_ratio() const {
- if (shared->exp_ratio && get_min() > 0) {
+ if (shared->exp_ratio && get_min() >= 0) {
- double exp_min = Math::log(get_min()) / Math::log((double)2);
+ double exp_min = get_min() == 0 ? 0.0 : Math::log(get_min()) / Math::log((double)2);
double exp_max = Math::log(get_max()) / Math::log((double)2);
- double v = Math::log(get_value()) / Math::log((double)2);
+ float value = CLAMP(get_value(), shared->min, shared->max);
+ double v = Math::log(value) / Math::log((double)2);
return (v - exp_min) / (exp_max - exp_min);
} else {
- return (get_value() - get_min()) / (get_max() - get_min());
+ float value = CLAMP(get_value(), shared->min, shared->max);
+ return (value - get_min()) / (get_max() - get_min());
}
}
@@ -193,6 +196,8 @@ void Range::unshare() {
nshared->val = shared->val;
nshared->step = shared->step;
nshared->page = shared->page;
+ nshared->allow_greater = shared->allow_greater;
+ nshared->allow_lesser = shared->allow_lesser;
_unref_shared();
_ref_shared(nshared);
}
@@ -236,6 +241,10 @@ void Range::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_using_rounded_values"), &Range::is_using_rounded_values);
ClassDB::bind_method(D_METHOD("set_exp_ratio", "enabled"), &Range::set_exp_ratio);
ClassDB::bind_method(D_METHOD("is_ratio_exp"), &Range::is_ratio_exp);
+ ClassDB::bind_method(D_METHOD("set_allow_greater", "allow"), &Range::set_allow_greater);
+ ClassDB::bind_method(D_METHOD("is_greater_allowed"), &Range::is_greater_allowed);
+ ClassDB::bind_method(D_METHOD("set_allow_lesser", "allow"), &Range::set_allow_lesser);
+ ClassDB::bind_method(D_METHOD("is_lesser_allowed"), &Range::is_lesser_allowed);
ClassDB::bind_method(D_METHOD("share", "with"), &Range::_share);
ClassDB::bind_method(D_METHOD("unshare"), &Range::unshare);
@@ -251,6 +260,8 @@ void Range::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "ratio", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_as_ratio", "get_as_ratio");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exp_edit"), "set_exp_ratio", "is_ratio_exp");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rounded"), "set_use_rounded_values", "is_using_rounded_values");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "allow_greater"), "set_allow_greater", "is_greater_allowed");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "allow_lesser"), "set_allow_lesser", "is_lesser_allowed");
}
void Range::set_use_rounded_values(bool p_enable) {
@@ -273,6 +284,22 @@ bool Range::is_ratio_exp() const {
return shared->exp_ratio;
}
+void Range::set_allow_greater(bool p_allow) {
+ shared->allow_greater = p_allow;
+}
+
+bool Range::is_greater_allowed() const {
+ return shared->allow_greater;
+}
+
+void Range::set_allow_lesser(bool p_allow) {
+ shared->allow_lesser = p_allow;
+}
+
+bool Range::is_lesser_allowed() const {
+ return shared->allow_lesser;
+}
+
Range::Range() {
shared = memnew(Shared);
shared->min = 0;
@@ -282,6 +309,8 @@ Range::Range() {
shared->page = 0;
shared->owners.insert(this);
shared->exp_ratio = false;
+ shared->allow_greater = false;
+ shared->allow_lesser = false;
_rounded_values = false;
}
diff --git a/scene/gui/range.h b/scene/gui/range.h
index de9383afd8..125f559248 100644
--- a/scene/gui/range.h
+++ b/scene/gui/range.h
@@ -43,6 +43,8 @@ class Range : public Control {
double val, min, max;
double step, page;
bool exp_ratio;
+ bool allow_greater;
+ bool allow_lesser;
Set<Range *> owners;
void emit_value_changed();
void emit_changed(const char *p_what = "");
@@ -86,6 +88,12 @@ public:
void set_exp_ratio(bool p_enable);
bool is_ratio_exp() const;
+ void set_allow_greater(bool p_allow);
+ bool is_greater_allowed() const;
+
+ void set_allow_lesser(bool p_allow);
+ bool is_lesser_allowed() const;
+
void share(Range *p_range);
void unshare();
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index d4ef735107..af368af46a 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -190,7 +190,6 @@ private:
struct ItemNewline : public Item {
- int line; // FIXME: Overriding base's line ?
ItemNewline() { type = ITEM_NEWLINE; }
};
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index a1dcf3b002..2dd5c64378 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -37,6 +37,7 @@ bool ScrollContainer::clips_input() const {
Size2 ScrollContainer::get_minimum_size() const {
+ Ref<StyleBox> sb = get_stylebox("bg");
Size2 min_size;
for (int i = 0; i < get_child_count(); i++) {
@@ -64,8 +65,9 @@ Size2 ScrollContainer::get_minimum_size() const {
if (v_scroll->is_visible_in_tree()) {
min_size.x += v_scroll->get_minimum_size().x;
}
+ min_size += sb->get_minimum_size();
return min_size;
-};
+}
void ScrollContainer::_cancel_drag() {
set_physics_process_internal(false);
@@ -233,6 +235,12 @@ void ScrollContainer::_notification(int p_what) {
child_max_size = Size2(0, 0);
Size2 size = get_size();
+ Point2 ofs;
+
+ Ref<StyleBox> sb = get_stylebox("bg");
+ size -= sb->get_minimum_size();
+ ofs += sb->get_offset();
+
if (h_scroll->is_visible_in_tree())
size.y -= h_scroll->get_minimum_size().y;
@@ -268,6 +276,7 @@ void ScrollContainer::_notification(int p_what) {
else
r.size.height = minsize.height;
}
+ r.position += ofs;
fit_child_in_rect(c, r);
}
update();
@@ -275,6 +284,9 @@ void ScrollContainer::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW) {
+ Ref<StyleBox> sb = get_stylebox("bg");
+ draw_style_box(sb, Rect2(Vector2(), get_size()));
+
update_scrollbars();
}
@@ -353,6 +365,8 @@ void ScrollContainer::_notification(int p_what) {
void ScrollContainer::update_scrollbars() {
Size2 size = get_size();
+ Ref<StyleBox> sb = get_stylebox("bg");
+ size -= sb->get_minimum_size();
Size2 hmin = h_scroll->get_combined_minimum_size();
Size2 vmin = v_scroll->get_combined_minimum_size();
diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp
index bf7033e8ba..c38c411333 100644
--- a/scene/gui/split_container.cpp
+++ b/scene/gui/split_container.cpp
@@ -33,13 +33,6 @@
#include "label.h"
#include "margin_container.h"
-struct _MinSizeCache {
-
- int min_size;
- bool will_stretch;
- int final_size;
-};
-
Control *SplitContainer::_getch(int p_idx) const {
int idx = 0;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index f33abcc8d6..0c2e5980b1 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -117,7 +117,6 @@ void TextEdit::Text::set_indent_size(int p_indent_size) {
void TextEdit::Text::_update_line_cache(int p_line) const {
int w = 0;
- int tab_w = font->get_char_size(' ').width * indent_size;
int len = text[p_line].data.length();
const CharType *str = text[p_line].data.c_str();
@@ -125,22 +124,13 @@ void TextEdit::Text::_update_line_cache(int p_line) const {
//update width
for (int i = 0; i < len; i++) {
- if (str[i] == '\t') {
-
- int left = w % tab_w;
- if (left == 0)
- w += tab_w;
- else
- w += tab_w - w % tab_w; // is right...
-
- } else {
-
- w += font->get_char_size(str[i], str[i + 1]).width;
- }
+ w += get_char_width(str[i], str[i + 1], w);
}
text[p_line].width_cache = w;
+ text[p_line].wrap_amount_cache = -1;
+
//update regions
text[p_line].region_info.clear();
@@ -242,10 +232,32 @@ int TextEdit::Text::get_line_width(int p_line) const {
return text[p_line].width_cache;
}
-void TextEdit::Text::clear_caches() {
+void TextEdit::Text::set_line_wrap_amount(int p_line, int p_wrap_amount) const {
+
+ ERR_FAIL_INDEX(p_line, text.size());
+
+ text[p_line].wrap_amount_cache = p_wrap_amount;
+}
+
+int TextEdit::Text::get_line_wrap_amount(int p_line) const {
+
+ ERR_FAIL_INDEX_V(p_line, text.size(), -1);
+
+ return text[p_line].wrap_amount_cache;
+}
+
+void TextEdit::Text::clear_width_cache() {
- for (int i = 0; i < text.size(); i++)
+ for (int i = 0; i < text.size(); i++) {
text[i].width_cache = -1;
+ }
+}
+
+void TextEdit::Text::clear_wrap_cache() {
+
+ for (int i = 0; i < text.size(); i++) {
+ text[i].wrap_amount_cache = -1;
+ }
}
void TextEdit::Text::clear() {
@@ -270,6 +282,7 @@ void TextEdit::Text::set(int p_line, const String &p_text) {
ERR_FAIL_INDEX(p_line, text.size());
text[p_line].width_cache = -1;
+ text[p_line].wrap_amount_cache = -1;
text[p_line].data = p_text;
}
@@ -280,6 +293,7 @@ void TextEdit::Text::insert(int p_at, const String &p_text) {
line.breakpoint = false;
line.hidden = false;
line.width_cache = -1;
+ line.wrap_amount_cache = -1;
line.data = p_text;
text.insert(p_at, line);
}
@@ -288,6 +302,25 @@ void TextEdit::Text::remove(int p_at) {
text.remove(p_at);
}
+int TextEdit::Text::get_char_width(CharType c, CharType next_c, int px) const {
+
+ int tab_w = font->get_char_size(' ').width * indent_size;
+ int w = 0;
+
+ if (c == '\t') {
+
+ int left = px % tab_w;
+ if (left == 0)
+ w = tab_w;
+ else
+ w = tab_w - px % tab_w; // is right...
+ } else {
+
+ w = font->get_char_size(c, next_c).width;
+ }
+ return w;
+}
+
void TextEdit::_update_scrollbars() {
Size2 size = get_size();
@@ -302,9 +335,12 @@ void TextEdit::_update_scrollbars() {
int hscroll_rows = ((hmin.height - 1) / get_row_height()) + 1;
int visible_rows = get_visible_rows();
- int num_rows = MAX(visible_rows, num_lines_from(CLAMP(cursor.line_ofs, 0, text.size() - 1), MIN(visible_rows, text.size() - 1 - cursor.line_ofs)));
- int total_rows = (is_hiding_enabled() ? get_total_unhidden_rows() : text.size());
+ int first_vis_line = get_first_visible_line();
+ int wi;
+ int num_rows = MAX(visible_rows, num_lines_from_rows(first_vis_line, cursor.wrap_ofs, visible_rows, wi));
+
+ int total_rows = get_total_visible_rows();
if (scroll_past_end_of_file_enabled) {
total_rows += visible_rows - 1;
}
@@ -350,28 +386,24 @@ void TextEdit::_update_scrollbars() {
if (use_vscroll) {
v_scroll->show();
- v_scroll->set_max(total_rows);
- v_scroll->set_page(visible_rows);
+ v_scroll->set_max(total_rows + get_visible_rows_offset());
+ v_scroll->set_page(visible_rows + get_visible_rows_offset());
if (smooth_scroll_enabled) {
v_scroll->set_step(0.25);
} else {
v_scroll->set_step(1);
}
-
- update_line_scroll_pos();
- if (fabs(v_scroll->get_value() - get_line_scroll_pos()) >= 1) {
- cursor.line_ofs += v_scroll->get_value() - get_line_scroll_pos();
- }
+ set_v_scroll(get_v_scroll());
} else {
cursor.line_ofs = 0;
- line_scroll_pos = 0;
+ cursor.wrap_ofs = 0;
v_scroll->set_value(0);
v_scroll->hide();
}
- if (use_hscroll) {
+ if (use_hscroll && !is_wrap_enabled()) {
h_scroll->show();
h_scroll->set_max(total_width);
@@ -422,8 +454,8 @@ void TextEdit::_update_selection_mode_pointer() {
select(selection.selecting_line, selection.selecting_column, row, col);
- cursor_set_line(row);
- cursor_set_column(col);
+ cursor_set_line(row, false);
+ cursor_set_column(col, false);
update();
click_select_held->start();
@@ -476,7 +508,7 @@ void TextEdit::_update_selection_mode_word() {
cursor_set_column(selection.to_column);
}
}
- cursor_set_line(row);
+ cursor_set_line(row, false);
update();
click_select_held->start();
@@ -491,15 +523,15 @@ void TextEdit::_update_selection_mode_line() {
col = 0;
if (row < selection.selecting_line) {
// cursor is above us
- cursor_set_line(row - 1);
+ cursor_set_line(row - 1, false);
selection.selecting_column = text[selection.selecting_line].length();
} else {
// cursor is below us
- cursor_set_line(row + 1);
+ cursor_set_line(row + 1, false);
selection.selecting_column = 0;
col = text[row].length();
}
- cursor_set_column(0);
+ cursor_set_column(0, false);
select(selection.selecting_line, selection.selecting_column, row, col);
update();
@@ -517,13 +549,13 @@ void TextEdit::_notification(int p_what) {
MessageQueue::get_singleton()->push_call(this, "_cursor_changed_emit");
if (text_changed_dirty)
MessageQueue::get_singleton()->push_call(this, "_text_changed_emit");
-
+ update_wrap_at();
} break;
case NOTIFICATION_RESIZED: {
cache.size = get_size();
- adjust_viewport_to_cursor();
-
+ _update_scrollbars();
+ update_wrap_at();
} break;
case NOTIFICATION_THEME_CHANGED: {
@@ -540,17 +572,17 @@ void TextEdit::_notification(int p_what) {
update();
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
- if (scrolling && v_scroll->get_value() != target_v_scroll) {
- double target_y = target_v_scroll - v_scroll->get_value();
+ if (scrolling && get_v_scroll() != target_v_scroll) {
+ double target_y = target_v_scroll - get_v_scroll();
double dist = sqrt(target_y * target_y);
double vel = ((target_y / dist) * v_scroll_speed) * get_physics_process_delta_time();
if (Math::abs(vel) >= dist) {
- v_scroll->set_value(target_v_scroll);
+ set_v_scroll(target_v_scroll);
scrolling = false;
set_physics_process_internal(false);
} else {
- v_scroll->set_value(v_scroll->get_value() + vel);
+ set_v_scroll(get_v_scroll() + vel);
}
} else {
scrolling = false;
@@ -777,12 +809,14 @@ void TextEdit::_notification(int p_what) {
String highlighted_text = get_selection_text();
String line_num_padding = line_numbers_zero_padded ? "0" : " ";
- update_line_scroll_pos();
- int line = cursor.line_ofs - 1;
- // another row may be visible during smooth scrolling
- int draw_amount = visible_rows + (smooth_scroll_enabled ? 1 : 0);
+ int cursor_wrap_index = get_cursor_wrap_index();
+
FontDrawer drawer(cache.font, Color(1, 1, 1));
+
+ int line = get_first_visible_line() - 1;
+ int draw_amount = visible_rows + (smooth_scroll_enabled ? 1 : 0);
+ draw_amount += times_line_wraps(line + 1);
for (int i = 0; i < draw_amount; i++) {
line++;
@@ -800,269 +834,360 @@ void TextEdit::_notification(int p_what) {
if (line < 0 || line >= (int)text.size())
continue;
- const String &str = text[line];
+ const String &fullstr = text[line];
- int char_margin = xmargin_beg - cursor.x_ofs;
- int char_ofs = 0;
-
- int ofs_readonly = 0;
- int ofs_x = 0;
+ Map<int, HighlighterInfo> color_map;
+ if (syntax_coloring) {
+ color_map = _get_line_syntax_highlighting(line);
+ }
+ // ensure we at least use the font color
+ Color current_color = cache.font_color;
if (readonly) {
- ofs_readonly = cache.style_readonly->get_offset().y / 2;
- ofs_x = cache.style_readonly->get_offset().x / 2;
+ current_color.a *= readonly_alpha;
}
- int ofs_y = (i * get_row_height() + cache.line_spacing / 2) + ofs_readonly;
- if (smooth_scroll_enabled)
- ofs_y -= ((v_scroll->get_value() - get_line_scroll_pos()) * get_row_height());
bool underlined = false;
- // check if line contains highlighted word
- int highlighted_text_col = -1;
- int search_text_col = -1;
- int highlighted_word_col = -1;
+ int line_wrap_amount = times_line_wraps(line);
+ int last_wrap_column = 0;
+ Vector<String> wrap_rows = get_wrap_rows_text(line);
- if (!search_text.empty())
- search_text_col = _get_column_pos_of_word(search_text, str, search_flags, 0);
+ for (int line_wrap_index = 0; line_wrap_index < line_wrap_amount + 1; line_wrap_index++) {
+ if (line_wrap_index != 0) {
+ i++;
+ if (i >= draw_amount)
+ break;
+ }
- if (highlighted_text.length() != 0 && highlighted_text != search_text)
- highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, 0);
+ const String &str = wrap_rows[line_wrap_index];
+ int indent_px = line_wrap_index != 0 ? get_indent_level(line) * cache.font->get_char_size(' ').width : 0;
- if (select_identifiers_enabled && highlighted_word.length() != 0) {
- if (_is_char(highlighted_word[0])) {
- highlighted_word_col = _get_column_pos_of_word(highlighted_word, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, 0);
+ if (line_wrap_index > 0)
+ last_wrap_column += wrap_rows[line_wrap_index - 1].length();
+
+ int char_margin = xmargin_beg - cursor.x_ofs;
+ char_margin += indent_px;
+ int char_ofs = 0;
+
+ int ofs_readonly = 0;
+ int ofs_x = 0;
+ if (readonly) {
+ ofs_readonly = cache.style_readonly->get_offset().y / 2;
+ ofs_x = cache.style_readonly->get_offset().x / 2;
}
- }
- if (text.is_marked(line)) {
+ int ofs_y = (i * get_row_height() + cache.line_spacing / 2) + ofs_readonly;
+ ofs_y -= cursor.wrap_ofs * get_row_height();
+ if (smooth_scroll_enabled)
+ ofs_y += (-get_v_scroll_offset()) * get_row_height();
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.mark_color);
- }
+ // check if line contains highlighted word
+ int highlighted_text_col = -1;
+ int search_text_col = -1;
+ int highlighted_word_col = -1;
+
+ if (!search_text.empty())
+ search_text_col = _get_column_pos_of_word(search_text, str, search_flags, 0);
- if (str.length() == 0) {
- // draw line background if empty as we won't loop at at all
- if (line == cursor.line && highlight_current_line) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(ofs_x, ofs_y, xmargin_end, get_row_height()), cache.current_line_color);
+ if (highlighted_text.length() != 0 && highlighted_text != search_text)
+ highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, 0);
+
+ if (select_identifiers_enabled && highlighted_word.length() != 0) {
+ if (_is_char(highlighted_word[0])) {
+ highlighted_word_col = _get_column_pos_of_word(highlighted_word, fullstr, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, 0);
+ }
}
- // 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(' ').width;
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, char_w, get_row_height()), cache.selection_color);
+ if (text.is_marked(line)) {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.mark_color);
}
- } else {
- // if it has text, then draw current line marker in the margin, as line number etc will draw over it, draw the rest of line marker later.
- if (line == cursor.line && highlight_current_line) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(0, ofs_y, xmargin_beg + ofs_x, get_row_height()), cache.current_line_color);
+
+ if (str.length() == 0) {
+ // draw line background if empty as we won't loop at at all
+ if (line == cursor.line && cursor_wrap_index == line_wrap_index && highlight_current_line) {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(ofs_x, ofs_y, xmargin_end, get_row_height()), cache.current_line_color);
+ }
+
+ // 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(' ').width;
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, char_w, get_row_height()), cache.selection_color);
+ }
+ } else {
+ // if it has text, then draw current line marker in the margin, as line number etc will draw over it, draw the rest of line marker later.
+ if (line == cursor.line && cursor_wrap_index == line_wrap_index && highlight_current_line) {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(0, ofs_y, xmargin_beg, get_row_height()), cache.current_line_color);
+ }
}
- }
- if (text.is_breakpoint(line) && !draw_breakpoint_gutter) {
+ if (line_wrap_index == 0) {
+ // only do these if we are on the first wrapped part of a line
+
+ if (text.is_breakpoint(line) && !draw_breakpoint_gutter) {
#ifdef TOOLS_ENABLED
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y + get_row_height() - EDSCALE, xmargin_end - xmargin_beg, EDSCALE), cache.breakpoint_color);
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y + get_row_height() - EDSCALE, xmargin_end - xmargin_beg, EDSCALE), cache.breakpoint_color);
#else
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.breakpoint_color);
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.breakpoint_color);
#endif
- }
+ }
- // draw breakpoint marker
- if (text.is_breakpoint(line)) {
- if (draw_breakpoint_gutter) {
- int vertical_gap = (get_row_height() * 40) / 100;
- int horizontal_gap = (cache.breakpoint_gutter_width * 30) / 100;
- int marker_height = get_row_height() - (vertical_gap * 2);
- int marker_width = cache.breakpoint_gutter_width - (horizontal_gap * 2);
- // no transparency on marker
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cache.style_normal->get_margin(MARGIN_LEFT) + horizontal_gap - 2, ofs_y + vertical_gap, marker_width, marker_height), Color(cache.breakpoint_color.r, cache.breakpoint_color.g, cache.breakpoint_color.b));
- }
- }
+ // draw breakpoint marker
+ if (text.is_breakpoint(line)) {
+ if (draw_breakpoint_gutter) {
+ int vertical_gap = (get_row_height() * 40) / 100;
+ int horizontal_gap = (cache.breakpoint_gutter_width * 30) / 100;
+ int marker_height = get_row_height() - (vertical_gap * 2);
+ int marker_width = cache.breakpoint_gutter_width - (horizontal_gap * 2);
+ // no transparency on marker
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cache.style_normal->get_margin(MARGIN_LEFT) + horizontal_gap - 2, ofs_y + vertical_gap, marker_width, marker_height), Color(cache.breakpoint_color.r, cache.breakpoint_color.g, cache.breakpoint_color.b));
+ }
+ }
- // draw fold markers
- if (draw_fold_gutter) {
- int horizontal_gap = (cache.fold_gutter_width * 30) / 100;
- int gutter_left = cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width + cache.line_number_w;
- if (is_folded(line)) {
- int xofs = horizontal_gap - (cache.can_fold_icon->get_width()) / 2;
- int yofs = (get_row_height() - cache.folded_icon->get_height()) / 2;
- cache.folded_icon->draw(ci, Point2(gutter_left + xofs + ofs_x, ofs_y + yofs), cache.code_folding_color);
- } else if (can_fold(line)) {
- int xofs = -cache.can_fold_icon->get_width() / 2 - horizontal_gap + 3;
- int yofs = (get_row_height() - cache.can_fold_icon->get_height()) / 2;
- cache.can_fold_icon->draw(ci, Point2(gutter_left + xofs + ofs_x, ofs_y + yofs), cache.code_folding_color);
- }
- }
+ // draw fold markers
+ if (draw_fold_gutter) {
+ int horizontal_gap = (cache.fold_gutter_width * 30) / 100;
+ int gutter_left = cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width + cache.line_number_w;
+ if (is_folded(line)) {
+ int xofs = horizontal_gap - (cache.can_fold_icon->get_width()) / 2;
+ int yofs = (get_row_height() - cache.folded_icon->get_height()) / 2;
+ cache.folded_icon->draw(ci, Point2(gutter_left + xofs + ofs_x, ofs_y + yofs), cache.code_folding_color);
+ } else if (can_fold(line)) {
+ int xofs = -cache.can_fold_icon->get_width() / 2 - horizontal_gap + 3;
+ int yofs = (get_row_height() - cache.can_fold_icon->get_height()) / 2;
+ cache.can_fold_icon->draw(ci, Point2(gutter_left + xofs + ofs_x, ofs_y + yofs), cache.code_folding_color);
+ }
+ }
+
+ // draw line numbers
+ if (cache.line_number_w) {
+ String fc = String::num(line + 1);
+ while (fc.length() < line_number_char_count) {
+ fc = line_num_padding + fc;
+ }
- if (cache.line_number_w) {
- String fc = String::num(line + 1);
- while (fc.length() < line_number_char_count) {
- fc = line_num_padding + fc;
+ cache.font->draw(ci, Point2(cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width + ofs_x, ofs_y + cache.font->get_ascent()), fc, cache.line_number_color);
+ }
}
- cache.font->draw(ci, Point2(cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width + ofs_x, ofs_y + cache.font->get_ascent()), fc, cache.line_number_color);
- }
+ //loop through characters in one line
+ for (int j = 0; j < str.length(); j++) {
- //loop through characters in one line
- Map<int, HighlighterInfo> color_map;
- if (syntax_coloring) {
- color_map = _get_line_syntax_highlighting(line);
- }
+ if (syntax_coloring) {
+ if (color_map.has(last_wrap_column + j)) {
+ current_color = color_map[last_wrap_column + j].color;
+ if (readonly) {
+ current_color.a *= readonly_alpha;
+ }
+ }
+ color = current_color;
+ }
- // ensure we at least use the font color
- Color current_color = cache.font_color;
- if (readonly) {
- current_color.a *= readonly_alpha;
- }
- for (int j = 0; j < str.length(); j++) {
+ int char_w;
+
+ //handle tabulator
+ char_w = text.get_char_width(str[j], str[j + 1], char_ofs);
+
+ if ((char_ofs + char_margin) < xmargin_beg) {
+ char_ofs += char_w;
- if (syntax_coloring) {
- if (color_map.has(j)) {
- current_color = color_map[j].color;
- if (readonly) {
- current_color.a *= readonly_alpha;
+ // line highlighting handle horizontal clipping
+ if (line == cursor.line && cursor_wrap_index == line_wrap_index && highlight_current_line) {
+
+ if (j == str.length() - 1) {
+ // end of line when last char is skipped
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - (char_ofs + char_margin + char_w), get_row_height()), cache.current_line_color);
+ } else if ((char_ofs + char_margin) > xmargin_beg) {
+ // char next to margin is skipped
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, (char_ofs + char_margin) - (xmargin_beg + ofs_x), get_row_height()), cache.current_line_color);
+ }
}
+ continue;
}
- color = current_color;
- }
- int char_w;
- //handle tabulator
+ if ((char_ofs + char_margin + char_w) >= xmargin_end) {
+ if (syntax_coloring)
+ continue;
+ else
+ break;
+ }
- if (str[j] == '\t') {
- int left = char_ofs % tab_w;
- if (left == 0)
- char_w = tab_w;
- else
- char_w = tab_w - char_ofs % tab_w; // is right...
+ bool in_search_result = false;
- } else {
- char_w = cache.font->get_char_size(str[j], str[j + 1]).width;
- }
+ if (search_text_col != -1) {
+ // if we are at the end check for new search result on same line
+ if (j >= search_text_col + search_text.length())
+ search_text_col = _get_column_pos_of_word(search_text, str, search_flags, j);
- if ((char_ofs + char_margin) < xmargin_beg) {
- char_ofs += char_w;
+ in_search_result = j >= search_text_col && j < search_text_col + search_text.length();
- // line highlighting handle horizontal clipping
- if (line == cursor.line && highlight_current_line) {
+ if (in_search_result) {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin, ofs_y), Size2i(char_w, get_row_height())), cache.search_result_color);
+ }
+ }
- if (j == str.length() - 1) {
- // end of line when last char is skipped
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - (xmargin_beg + ofs_x), get_row_height()), cache.current_line_color);
+ //current line highlighting
+ bool in_selection = (selection.active && line >= selection.from_line && line <= selection.to_line && (line > selection.from_line || last_wrap_column + j >= selection.from_column) && (line < selection.to_line || last_wrap_column + j < selection.to_column));
- } else if ((char_ofs + char_margin) > xmargin_beg) {
- // char next to margin is skipped
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, (char_ofs + char_margin) - xmargin_beg, get_row_height()), cache.current_line_color);
+ if (line == cursor.line && cursor_wrap_index == line_wrap_index && highlight_current_line) {
+ // draw the wrap indent offset highlight
+ if (line_wrap_index != 0 && j == 0) {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(char_ofs + char_margin - indent_px, ofs_y, (char_ofs + char_margin), get_row_height()), cache.current_line_color);
+ }
+ // if its the last char draw to end of the line
+ if (j == str.length() - 1) {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(char_ofs + char_margin + char_w, ofs_y, xmargin_end - (char_ofs + char_margin + char_w), get_row_height()), cache.current_line_color);
+ }
+ // actual text
+ if (!in_selection) {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, get_row_height())), cache.current_line_color);
}
}
- continue;
- }
- if ((char_ofs + char_margin + char_w) >= xmargin_end) {
- if (syntax_coloring)
- continue;
- else
- break;
- }
-
- bool in_search_result = false;
+ if (in_selection) {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, get_row_height())), cache.selection_color);
+ }
- if (search_text_col != -1) {
- // if we are at the end check for new search result on same line
- if (j >= search_text_col + search_text.length())
- search_text_col = _get_column_pos_of_word(search_text, str, search_flags, j);
+ if (in_search_result) {
+ Color border_color = (line == search_result_line && j >= search_result_col && j < search_result_col + search_text.length()) ? cache.font_color : cache.search_result_border_color;
- in_search_result = j >= search_text_col && j < search_text_col + search_text.length();
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, 1)), border_color);
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y + get_row_height() - 1), Size2i(char_w, 1)), border_color);
- if (in_search_result) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin, ofs_y), Size2i(char_w, get_row_height())), cache.search_result_color);
+ if (j == search_text_col)
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(1, get_row_height())), border_color);
+ if (j == search_text_col + search_text.length() - 1)
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + char_w + ofs_x - 1, ofs_y), Size2i(1, get_row_height())), border_color);
}
- }
- //current line highlighting
- bool in_selection = (selection.active && line >= selection.from_line && line <= selection.to_line && (line > selection.from_line || j >= selection.from_column) && (line < selection.to_line || j < selection.to_column));
+ if (highlight_all_occurrences) {
+ if (highlighted_text_col != -1) {
- if (line == cursor.line && highlight_current_line) {
- // if its the last char draw to end of the line
- if (j == str.length() - 1) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(char_ofs + char_margin + char_w, ofs_y, xmargin_end - (char_ofs + char_margin + char_w), get_row_height()), cache.current_line_color);
+ // if we are at the end check for new word on same line
+ if (j > highlighted_text_col + highlighted_text.length()) {
+ highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, j);
+ }
+
+ bool in_highlighted_word = (j >= highlighted_text_col && j < highlighted_text_col + highlighted_text.length());
+
+ // if this is the original highlighted text we don't want to highlight it again
+ if (cursor.line == line && cursor_wrap_index == line_wrap_index && (cursor.column >= highlighted_text_col && cursor.column <= highlighted_text_col + highlighted_text.length())) {
+ in_highlighted_word = false;
+ }
+
+ if (in_highlighted_word) {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, get_row_height())), cache.word_highlighted_color);
+ }
+ }
}
- // actual text
- if (!in_selection) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, get_row_height())), cache.current_line_color);
+
+ if (highlighted_word_col != -1) {
+ if (j + last_wrap_column > highlighted_word_col + highlighted_word.length()) {
+ highlighted_word_col = _get_column_pos_of_word(highlighted_word, fullstr, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, j + last_wrap_column);
+ }
+ underlined = (j + last_wrap_column >= highlighted_word_col && j + last_wrap_column < highlighted_word_col + highlighted_word.length());
}
- }
- if (in_selection) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, get_row_height())), cache.selection_color);
- }
+ if (brace_matching_enabled) {
+ if ((brace_open_match_line == line && brace_open_match_column == last_wrap_column + j) ||
+ (cursor.column == last_wrap_column + j && cursor.line == line && cursor_wrap_index == line_wrap_index && (brace_open_matching || brace_open_mismatch))) {
- if (in_search_result) {
- Color border_color = (line == search_result_line && j >= search_result_col && j < search_result_col + search_text.length()) ? cache.font_color : cache.search_result_border_color;
+ if (brace_open_mismatch)
+ color = cache.brace_mismatch_color;
+ drawer.draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, ofs_y + ascent), '_', str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color);
+ }
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, 1)), border_color);
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y + get_row_height() - 1), Size2i(char_w, 1)), border_color);
+ if ((brace_close_match_line == line && brace_close_match_column == last_wrap_column + j) ||
+ (cursor.column == last_wrap_column + j + 1 && cursor.line == line && cursor_wrap_index == line_wrap_index && (brace_close_matching || brace_close_mismatch))) {
- if (j == search_text_col)
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(1, get_row_height())), border_color);
- if (j == search_text_col + search_text.length() - 1)
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + char_w + ofs_x - 1, ofs_y), Size2i(1, get_row_height())), border_color);
- }
+ if (brace_close_mismatch)
+ color = cache.brace_mismatch_color;
+ drawer.draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, ofs_y + ascent), '_', str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color);
+ }
+ }
- if (highlight_all_occurrences) {
- if (highlighted_text_col != -1) {
+ if (cursor.column == last_wrap_column + j && cursor.line == line && cursor_wrap_index == line_wrap_index) {
- // if we are at the end check for new word on same line
- if (j > highlighted_text_col + highlighted_text.length()) {
- highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, j);
+ cursor_pos = Point2i(char_ofs + char_margin + ofs_x, ofs_y);
+
+ if (insert_mode) {
+ cursor_pos.y += (get_row_height() - 3);
}
- bool in_highlighted_word = (j >= highlighted_text_col && j < highlighted_text_col + highlighted_text.length());
+ int caret_w = (str[j] == '\t') ? cache.font->get_char_size(' ').width : char_w;
+ if (ime_text.length() > 0) {
+ int ofs = 0;
+ while (true) {
+ if (ofs >= ime_text.length())
+ break;
- /* if this is the original highlighted text we don't want to highlight it again */
- if (cursor.line == line && (cursor.column >= highlighted_text_col && cursor.column <= highlighted_text_col + highlighted_text.length())) {
- in_highlighted_word = false;
- }
+ CharType cchar = ime_text[ofs];
+ CharType next = ime_text[ofs + 1];
+ int im_char_width = cache.font->get_char_size(cchar, next).width;
+
+ if ((char_ofs + char_margin + im_char_width) >= xmargin_end)
+ break;
+
+ bool selected = ofs >= ime_selection.x && ofs < ime_selection.x + ime_selection.y;
+ if (selected) {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(char_ofs + char_margin, ofs_y + get_row_height()), Size2(im_char_width, 3)), color);
+ } else {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(char_ofs + char_margin, ofs_y + get_row_height()), Size2(im_char_width, 1)), color);
+ }
+
+ drawer.draw_char(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + ascent), cchar, next, color);
- if (in_highlighted_word) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, get_row_height())), cache.word_highlighted_color);
+ char_ofs += im_char_width;
+ ofs++;
+ }
+ }
+ if (ime_text.length() == 0) {
+ if (draw_caret) {
+ if (insert_mode) {
+ int caret_h = (block_caret) ? 4 : 1;
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(caret_w, caret_h)), cache.caret_color);
+ } else {
+ caret_w = (block_caret) ? caret_w : 1;
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(caret_w, get_row_height())), cache.caret_color);
+ }
+ }
}
}
- }
- if (highlighted_word_col != -1) {
- if (j > highlighted_word_col + highlighted_word.length()) {
- highlighted_word_col = _get_column_pos_of_word(highlighted_word, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, j);
+ if (cursor.column == last_wrap_column + j && cursor.line == line && cursor_wrap_index == line_wrap_index && block_caret && draw_caret && !insert_mode) {
+ color = cache.caret_background_color;
+ } else if (!syntax_coloring && block_caret) {
+ color = cache.font_color;
+ color.a *= readonly_alpha;
}
- underlined = (j >= highlighted_word_col && j < highlighted_word_col + highlighted_word.length());
- }
- if (brace_matching_enabled) {
- if ((brace_open_match_line == line && brace_open_match_column == j) ||
- (cursor.column == j && cursor.line == line && (brace_open_matching || brace_open_mismatch))) {
-
- if (brace_open_mismatch)
- color = cache.brace_mismatch_color;
- drawer.draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, ofs_y + ascent), '_', str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color);
+ if (str[j] >= 32) {
+ int w = drawer.draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, ofs_y + ascent), str[j], str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color);
+ if (underlined) {
+ draw_rect(Rect2(char_ofs + char_margin + ofs_x, ofs_y + ascent + 2, w, 1), in_selection && override_selected_font_color ? cache.font_selected_color : color);
+ }
+ } else if (draw_tabs && str[j] == '\t') {
+ int yofs = (get_row_height() - cache.tab_icon->get_height()) / 2;
+ cache.tab_icon->draw(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + yofs), in_selection && override_selected_font_color ? cache.font_selected_color : color);
}
- if (
- (brace_close_match_line == line && brace_close_match_column == j) ||
- (cursor.column == j + 1 && cursor.line == line && (brace_close_matching || brace_close_mismatch))) {
+ char_ofs += char_w;
- if (brace_close_mismatch)
- color = cache.brace_mismatch_color;
- drawer.draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, ofs_y + ascent), '_', str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color);
+ if (line_wrap_index == line_wrap_amount && j == str.length() - 1 && is_folded(line)) {
+ int yofs = (get_row_height() - cache.folded_eol_icon->get_height()) / 2;
+ int xofs = cache.folded_eol_icon->get_width() / 2;
+ Color eol_color = cache.code_folding_color;
+ eol_color.a = 1;
+ cache.folded_eol_icon->draw(ci, Point2(char_ofs + char_margin + xofs + ofs_x, ofs_y + yofs), eol_color);
}
}
- if (cursor.column == j && cursor.line == line) {
+ if (cursor.column == last_wrap_column + str.length() && cursor.line == line && cursor_wrap_index == line_wrap_index && (char_ofs + char_margin) >= xmargin_beg) {
cursor_pos = Point2i(char_ofs + char_margin + ofs_x, ofs_y);
if (insert_mode) {
cursor_pos.y += (get_row_height() - 3);
}
-
- int caret_w = (str[j] == '\t') ? cache.font->get_char_size(' ').width : char_w;
if (ime_text.length() > 0) {
int ofs = 0;
while (true) {
@@ -1092,92 +1217,17 @@ void TextEdit::_notification(int p_what) {
if (ime_text.length() == 0) {
if (draw_caret) {
if (insert_mode) {
+ int char_w = cache.font->get_char_size(' ').width;
int caret_h = (block_caret) ? 4 : 1;
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(caret_w, caret_h)), cache.caret_color);
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(char_w, caret_h)), cache.caret_color);
} else {
- caret_w = (block_caret) ? caret_w : 1;
+ int char_w = cache.font->get_char_size(' ').width;
+ int caret_w = (block_caret) ? char_w : 1;
VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(caret_w, get_row_height())), cache.caret_color);
}
}
}
}
-
- if (cursor.column == j && cursor.line == line && block_caret && draw_caret && !insert_mode) {
- color = cache.caret_background_color;
- } else if (!syntax_coloring && block_caret) {
- color = cache.font_color;
- color.a *= readonly_alpha;
- }
-
- if (str[j] >= 32) {
- int w = drawer.draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, ofs_y + ascent), str[j], str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color);
- if (underlined) {
- draw_rect(Rect2(char_ofs + char_margin + ofs_x, ofs_y + ascent + 2, w, 1), in_selection && override_selected_font_color ? cache.font_selected_color : color);
- }
- }
-
- else if (draw_tabs && str[j] == '\t') {
- int yofs = (get_row_height() - cache.tab_icon->get_height()) / 2;
- cache.tab_icon->draw(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + yofs), in_selection && override_selected_font_color ? cache.font_selected_color : color);
- }
-
- char_ofs += char_w;
-
- if (j == str.length() - 1 && is_folded(line)) {
- int yofs = (get_row_height() - cache.folded_eol_icon->get_height()) / 2;
- int xofs = cache.folded_eol_icon->get_width() / 2;
- Color eol_color = cache.code_folding_color;
- eol_color.a = 1;
- cache.folded_eol_icon->draw(ci, Point2(char_ofs + char_margin + xofs + ofs_x, ofs_y + yofs), eol_color);
- }
- }
-
- if (cursor.column == str.length() && cursor.line == line && (char_ofs + char_margin) >= xmargin_beg) {
-
- cursor_pos = Point2i(char_ofs + char_margin + ofs_x, ofs_y);
-
- if (insert_mode) {
- cursor_pos.y += (get_row_height() - 3);
- }
- if (ime_text.length() > 0) {
- int ofs = 0;
- while (true) {
- if (ofs >= ime_text.length())
- break;
-
- CharType cchar = ime_text[ofs];
- CharType next = ime_text[ofs + 1];
- int im_char_width = cache.font->get_char_size(cchar, next).width;
-
- if ((char_ofs + char_margin + im_char_width) >= xmargin_end)
- break;
-
- bool selected = ofs >= ime_selection.x && ofs < ime_selection.x + ime_selection.y;
- if (selected) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(char_ofs + char_margin, ofs_y + get_row_height()), Size2(im_char_width, 3)), color);
- } else {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(char_ofs + char_margin, ofs_y + get_row_height()), Size2(im_char_width, 1)), color);
- }
-
- drawer.draw_char(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + ascent), cchar, next, color);
-
- char_ofs += im_char_width;
- ofs++;
- }
- }
- if (ime_text.length() == 0) {
- if (draw_caret) {
- if (insert_mode) {
- int char_w = cache.font->get_char_size(' ').width;
- int caret_h = (block_caret) ? 4 : 1;
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(char_w, caret_h)), cache.caret_color);
- } else {
- int char_w = cache.font->get_char_size(' ').width;
- int caret_w = (block_caret) ? char_w : 1;
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(caret_w, get_row_height())), cache.caret_color);
- }
- }
- }
}
}
@@ -1604,16 +1654,17 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co
float rows = p_mouse.y;
rows -= cache.style_normal->get_margin(MARGIN_TOP);
- rows += (CLAMP(v_scroll->get_value() - get_line_scroll_pos(true), 0, 1) * get_row_height());
rows /= get_row_height();
- int first_vis_line = CLAMP(cursor.line_ofs, 0, text.size() - 1);
+ rows += get_v_scroll_offset();
+ int first_vis_line = get_first_visible_line();
int row = first_vis_line + Math::floor(rows);
+ int wrap_index = 0;
+
+ if (is_wrap_enabled() || is_hiding_enabled()) {
- if (is_hiding_enabled()) {
- // row will be offset by the hidden rows
- int f_ofs = num_lines_from(first_vis_line, rows + 1) - 1;
+ int f_ofs = num_lines_from_rows(first_vis_line, cursor.wrap_ofs, rows + 1, wrap_index) - 1;
row = first_vis_line + f_ofs;
- row = CLAMP(row, 0, text.size() - num_lines_from(text.size() - 1, -1));
+ row = CLAMP(row, 0, get_last_visible_line() + 1);
}
if (row < 0)
@@ -1627,9 +1678,19 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co
col = text[row].size();
} else {
- col = p_mouse.x - (cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width);
- col += cursor.x_ofs;
- col = get_char_pos_for(col, get_line(row));
+ int colx = p_mouse.x - (cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width);
+ colx += cursor.x_ofs;
+ col = get_char_pos_for_line(colx, row, wrap_index);
+ if (is_wrap_enabled() && wrap_index < times_line_wraps(row)) {
+ // move back one if we are at the end of the row
+ Vector<String> rows = get_wrap_rows_text(row);
+ int row_end_col = 0;
+ for (int i = 0; i < wrap_index + 1; i++) {
+ row_end_col += rows[i].length();
+ }
+ if (col >= row_end_col)
+ col -= 1;
+ }
}
r_row = row;
@@ -1704,7 +1765,6 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
_reset_caret_blink_timer();
int row, col;
- update_line_scroll_pos();
_get_mouse_pos(Point2i(mb->get_position().x, mb->get_position().y), row, col);
if (mb->get_command() && highlighted_word != String()) {
@@ -1836,7 +1896,6 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
_reset_caret_blink_timer();
int row, col;
- update_line_scroll_pos();
_get_mouse_pos(Point2i(mb->get_position().x, mb->get_position().y), row, col);
if (is_right_click_moving_caret()) {
@@ -2453,13 +2512,14 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
break;
} else if (k->get_command()) {
#endif
- bool prev_char = false;
int cc = cursor.column;
if (cc == 0 && cursor.line > 0) {
cursor_set_line(cursor.line - 1);
cursor_set_column(text[cursor.line].length());
} else {
+ bool prev_char = false;
+
while (cc > 0) {
bool ischar = _is_text_char(text[cursor.line][cc - 1]);
@@ -2514,13 +2574,14 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
break;
} else if (k->get_command()) {
#endif
- bool prev_char = false;
int cc = cursor.column;
if (cc == text[cursor.line].length() && cursor.line < text.size() - 1) {
cursor_set_line(cursor.line + 1);
cursor_set_column(0);
} else {
+ bool prev_char = false;
+
while (cc < text[cursor.line].length()) {
bool ischar = _is_text_char(text[cursor.line][cc]);
@@ -2572,11 +2633,25 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
break;
}
- if (k->get_command())
+ if (k->get_command()) {
cursor_set_line(0);
- else
+ } else
#endif
- cursor_set_line(cursor_get_line() - num_lines_from(CLAMP(cursor.line - 1, 0, text.size() - 1), -1));
+ {
+ int cur_wrap_index = get_cursor_wrap_index();
+ if (cur_wrap_index > 0) {
+ cursor_set_line(cursor.line, true, false, cur_wrap_index - 1);
+ } else if (cursor.line == 0) {
+ cursor_set_column(0);
+ } else {
+ int new_line = cursor.line - num_lines_from(cursor.line - 1, -1);
+ if (line_wraps(new_line)) {
+ cursor_set_line(new_line, true, false, times_line_wraps(new_line));
+ } else {
+ cursor_set_line(new_line, true, false);
+ }
+ }
+ }
if (k->get_shift())
_post_shift_selection();
@@ -2604,22 +2679,25 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
break;
}
- {
#else
if (k->get_command() && k->get_alt()) {
_scroll_lines_down();
break;
}
- if (k->get_command())
- cursor_set_line(text.size() - 1, true, false);
- else {
+ if (k->get_command()) {
+ cursor_set_line(get_last_unhidden_line(), true, false, 9999);
+ } else
#endif
- if (!is_last_visible_line(cursor.line)) {
- cursor_set_line(cursor_get_line() + num_lines_from(CLAMP(cursor.line + 1, 0, text.size() - 1), 1), true, false);
+ {
+ int cur_wrap_index = get_cursor_wrap_index();
+ if (cur_wrap_index < times_line_wraps(cursor.line)) {
+ cursor_set_line(cursor.line, true, false, cur_wrap_index + 1);
+ } else if (cursor.line == get_last_unhidden_line()) {
+ cursor_set_column(text[cursor.line].length());
} else {
- cursor_set_line(text.size() - 1);
- cursor_set_column(get_line(cursor.line).length(), true);
+ int new_line = cursor.line + num_lines_from(CLAMP(cursor.line + 1, 0, text.size() - 1), 1);
+ cursor_set_line(new_line, true, false, 0);
}
}
@@ -2628,7 +2706,6 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
_cancel_code_hint();
} break;
-
case KEY_DELETE: {
if (readonly)
@@ -2735,19 +2812,31 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
cursor_set_line(0);
cursor_set_column(0);
} else {
- // compute whitespace symbols seq length
- int current_line_whitespace_len = 0;
- while (current_line_whitespace_len < text[cursor.line].length()) {
- CharType c = text[cursor.line][current_line_whitespace_len];
- if (c != '\t' && c != ' ')
- break;
- current_line_whitespace_len++;
+
+ // move cursor column to start of wrapped row and then to start of text
+ Vector<String> rows = get_wrap_rows_text(cursor.line);
+ int wi = get_cursor_wrap_index();
+ int row_start_col = 0;
+ for (int i = 0; i < wi; i++) {
+ row_start_col += rows[i].length();
}
+ if (cursor.column == row_start_col || wi == 0) {
+ // compute whitespace symbols seq length
+ int current_line_whitespace_len = 0;
+ while (current_line_whitespace_len < text[cursor.line].length()) {
+ CharType c = text[cursor.line][current_line_whitespace_len];
+ if (c != '\t' && c != ' ')
+ break;
+ current_line_whitespace_len++;
+ }
- if (cursor_get_column() == current_line_whitespace_len)
- cursor_set_column(0);
- else
- cursor_set_column(current_line_whitespace_len);
+ if (cursor_get_column() == current_line_whitespace_len)
+ cursor_set_column(0);
+ else
+ cursor_set_column(current_line_whitespace_len);
+ } else {
+ cursor_set_column(row_start_col);
+ }
}
if (k->get_shift())
@@ -2772,7 +2861,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (k->get_shift())
_pre_shift_selection();
- cursor_set_line(text.size() - 1, true, false);
+ cursor_set_line(get_last_unhidden_line(), true, false, 9999);
if (k->get_shift())
_post_shift_selection();
@@ -2787,8 +2876,20 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
_pre_shift_selection();
if (k->get_command())
- cursor_set_line(text.size() - 1, true, false);
- cursor_set_column(text[cursor.line].length());
+ cursor_set_line(get_last_unhidden_line(), true, false, 9999);
+
+ // move cursor column to end of wrapped row and then to end of text
+ Vector<String> rows = get_wrap_rows_text(cursor.line);
+ int wi = get_cursor_wrap_index();
+ int row_end_col = -1;
+ for (int i = 0; i < wi + 1; i++) {
+ row_end_col += rows[i].length();
+ }
+ if (wi == rows.size() - 1 || cursor.column == row_end_col) {
+ cursor_set_column(text[cursor.line].length());
+ } else {
+ cursor_set_column(row_end_col);
+ }
if (k->get_shift())
_post_shift_selection();
@@ -2812,7 +2913,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (k->get_shift())
_pre_shift_selection();
- cursor_set_line(cursor_get_line() - num_lines_from(cursor.line, -get_visible_rows()), true, false);
+ int wi;
+ int n_line = cursor.line - num_lines_from_rows(cursor.line, get_cursor_wrap_index(), -get_visible_rows(), wi) + 1;
+ cursor_set_line(n_line, true, false, wi);
if (k->get_shift())
_post_shift_selection();
@@ -2826,14 +2929,16 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
scancode_handled = false;
break;
}
- // numlock disabled. fallthrough to key_pageup
+ // numlock disabled. fallthrough to key_pagedown
}
case KEY_PAGEDOWN: {
if (k->get_shift())
_pre_shift_selection();
- cursor_set_line(cursor_get_line() + num_lines_from(cursor.line, get_visible_rows()), true, false);
+ int wi;
+ int n_line = cursor.line + num_lines_from_rows(cursor.line, get_cursor_wrap_index(), get_visible_rows(), wi) - 1;
+ cursor_set_line(n_line, true, false, wi);
if (k->get_shift())
_post_shift_selection();
@@ -3078,7 +3183,7 @@ void TextEdit::_scroll_up(real_t p_delta) {
if (scrolling) {
target_v_scroll = (target_v_scroll - p_delta);
} else {
- target_v_scroll = (v_scroll->get_value() - p_delta);
+ target_v_scroll = (get_v_scroll() - p_delta);
}
if (smooth_scroll_enabled) {
@@ -3092,7 +3197,7 @@ void TextEdit::_scroll_up(real_t p_delta) {
set_physics_process_internal(true);
}
} else {
- v_scroll->set_value(target_v_scroll);
+ set_v_scroll(target_v_scroll);
}
}
@@ -3104,20 +3209,15 @@ void TextEdit::_scroll_down(real_t p_delta) {
if (scrolling) {
target_v_scroll = (target_v_scroll + p_delta);
} else {
- target_v_scroll = (v_scroll->get_value() + p_delta);
+ target_v_scroll = (get_v_scroll() + p_delta);
}
if (smooth_scroll_enabled) {
- int max_v_scroll = get_total_unhidden_rows();
- if (!scroll_past_end_of_file_enabled) {
- max_v_scroll -= get_visible_rows();
- max_v_scroll = CLAMP(max_v_scroll, 0, get_total_unhidden_rows());
- }
-
+ int max_v_scroll = v_scroll->get_max() - v_scroll->get_page();
if (target_v_scroll > max_v_scroll) {
target_v_scroll = max_v_scroll;
+ v_scroll->set_value(target_v_scroll);
}
-
if (Math::abs(target_v_scroll - v_scroll->get_value()) < 1.0) {
v_scroll->set_value(target_v_scroll);
} else {
@@ -3125,7 +3225,7 @@ void TextEdit::_scroll_down(real_t p_delta) {
set_physics_process_internal(true);
}
} else {
- v_scroll->set_value(target_v_scroll);
+ set_v_scroll(target_v_scroll);
}
}
@@ -3156,35 +3256,37 @@ void TextEdit::_scroll_lines_up() {
scrolling = false;
// adjust the vertical scroll
- if (get_v_scroll() >= 0) {
- set_v_scroll(get_v_scroll() - 1);
- }
+ set_v_scroll(get_v_scroll() - 1);
+
+ // adjust the cursor to viewport
+ 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();
- // adjust the cursor
- int num_lines = num_lines_from(CLAMP(cursor.line_ofs, 0, text.size() - 1), get_visible_rows());
- if (cursor.line >= cursor.line_ofs + num_lines && !selection.active) {
- cursor_set_line(cursor.line_ofs + num_lines, false, false);
+ 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);
+ }
}
}
void TextEdit::_scroll_lines_down() {
scrolling = false;
- // calculate the maximum vertical scroll position
- int max_v_scroll = get_total_unhidden_rows();
- if (!scroll_past_end_of_file_enabled) {
- max_v_scroll -= get_visible_rows();
- max_v_scroll = CLAMP(max_v_scroll, 0, get_total_unhidden_rows());
- }
-
// adjust the vertical scroll
- if (get_v_scroll() < max_v_scroll) {
- set_v_scroll(get_v_scroll() + 1);
- }
+ set_v_scroll(get_v_scroll() + 1);
- // adjust the cursor
- if (cursor.line <= cursor.line_ofs - 1 && !selection.active) {
- cursor_set_line(cursor.line_ofs, false, false);
+ // adjust the cursor to viewport
+ if (!selection.active) {
+ int cur_line = cursor.line;
+ int cur_wrap = get_cursor_wrap_index();
+ int first_vis_line = get_first_visible_line();
+ int first_vis_wrap = cursor.wrap_ofs;
+
+ if (cur_line < first_vis_line || (cur_line == first_vis_line && cur_wrap < first_vis_wrap)) {
+ cursor_set_line(first_vis_line, false, false, first_vis_wrap);
+ }
}
}
@@ -3238,6 +3340,8 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i
text.set_hidden(p_line, false);
}
+ text.set_line_wrap_amount(p_line, -1);
+
r_end_line = p_line + substrings.size() - 1;
r_end_column = text[r_end_line].length() - postinsert_text.length();
@@ -3292,6 +3396,8 @@ void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_li
text.set(p_from_line, pre_text + post_text);
+ text.set_line_wrap_amount(p_from_line, -1);
+
if (!text_changed_dirty && !setting_text) {
if (is_inside_tree())
MessageQueue::get_singleton()->push_call(this, "_text_changed_emit");
@@ -3450,61 +3556,63 @@ int TextEdit::get_visible_rows() const {
int total = cache.size.height;
total -= cache.style_normal->get_minimum_size().height;
+ if (h_scroll->is_visible_in_tree())
+ total -= h_scroll->get_size().height;
total /= get_row_height();
return total;
}
-int TextEdit::get_total_unhidden_rows() const {
- if (!is_hiding_enabled())
+int TextEdit::get_total_visible_rows() const {
+
+ // returns the total amount of rows we need in the editor.
+ // This skips hidden lines and counts each wrapping of a line.
+ if (!is_hiding_enabled() && !is_wrap_enabled())
return text.size();
- int total_unhidden = 0;
+ int total_rows = 0;
for (int i = 0; i < text.size(); i++) {
- if (!text.is_hidden(i))
- total_unhidden++;
+ if (!text.is_hidden(i)) {
+ total_rows++;
+ total_rows += times_line_wraps(i);
+ }
}
- return total_unhidden;
+ return total_rows;
}
-double TextEdit::get_line_scroll_pos(bool p_recalculate) const {
+void TextEdit::update_wrap_at() {
- if (!is_hiding_enabled())
- return cursor.line_ofs;
- if (!p_recalculate)
- return line_scroll_pos;
+ wrap_at = cache.size.width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width - wrap_right_offset;
+ update_cursor_wrap_offset();
+ text.clear_wrap_cache();
- // count num unhidden lines to the cursor line ofs
- double new_line_scroll_pos = 0;
- int to = CLAMP(cursor.line_ofs, 0, text.size() - 1);
- for (int i = 0; i < to; i++) {
- if (!text.is_hidden(i))
- new_line_scroll_pos++;
+ for (int i = 0; i < text.size(); i++) {
+ // update all values that wrap
+ if (!line_wraps(i))
+ continue;
+ Vector<String> rows = get_wrap_rows_text(i);
+ text.set_line_wrap_amount(i, rows.size() - 1);
}
- return new_line_scroll_pos;
}
-void TextEdit::update_line_scroll_pos() {
+void TextEdit::adjust_viewport_to_cursor() {
- if (!is_hiding_enabled()) {
- line_scroll_pos = cursor.line_ofs;
- return;
- }
+ // make sure cursor is visible on the screen
+ scrolling = false;
- // count num unhidden lines to the cursor line ofs
- double new_line_scroll_pos = 0;
- int to = CLAMP(cursor.line_ofs, 0, text.size() - 1);
- for (int i = 0; i < to; i++) {
- if (!text.is_hidden(i))
- new_line_scroll_pos++;
- }
- line_scroll_pos = new_line_scroll_pos;
-}
+ int cur_line = cursor.line;
+ int cur_wrap = get_cursor_wrap_index();
-void TextEdit::adjust_viewport_to_cursor() {
- scrolling = false;
+ 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();
- if (cursor.line_ofs > cursor.line) {
- cursor.line_ofs = cursor.line;
+ if (cur_line < first_vis_line || (cur_line == first_vis_line && cur_wrap < first_vis_wrap)) {
+ // cursor is above screen
+ set_line_as_first_visible(cur_line, cur_wrap);
+ } else if (cur_line > last_vis_line || (cur_line == last_vis_line && cur_wrap > last_vis_wrap)) {
+ // cursor is below screen
+ set_line_as_last_visible(cur_line, cur_wrap);
}
int visible_width = cache.size.width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width;
@@ -3512,91 +3620,174 @@ void TextEdit::adjust_viewport_to_cursor() {
visible_width -= v_scroll->get_combined_minimum_size().width;
visible_width -= 20; // give it a little more space
- int visible_rows = get_visible_rows();
- if (h_scroll->is_visible_in_tree() && !scroll_past_end_of_file_enabled)
- visible_rows -= ((h_scroll->get_combined_minimum_size().height - 1) / get_row_height());
- int num_rows = num_lines_from(CLAMP(cursor.line_ofs, 0, text.size() - 1), MIN(visible_rows, text.size() - 1 - cursor.line_ofs));
-
- // make sure the cursor is on the screen
- // above the caret
- if (cursor.line > (cursor.line_ofs + MAX(num_rows, visible_rows))) {
- cursor.line_ofs = cursor.line - num_lines_from(cursor.line, -visible_rows) + 1;
- }
- // below the caret
- if (cursor.line_ofs == cursor.line) {
- cursor.line_ofs = cursor.line - 2;
- }
- int line_ofs_max = text.size() - 1;
- if (!scroll_past_end_of_file_enabled) {
- line_ofs_max -= num_lines_from(text.size() - 1, -visible_rows) - 1;
- line_ofs_max += (h_scroll->is_visible_in_tree() ? 1 : 0);
- line_ofs_max += (cursor.line == text.size() - 1 ? 1 : 0);
- }
- line_ofs_max = MAX(line_ofs_max, 0);
- cursor.line_ofs = CLAMP(cursor.line_ofs, 0, line_ofs_max);
-
- // adjust x offset
- int cursor_x = get_column_x_offset(cursor.column, text[cursor.line]);
+ if (!is_wrap_enabled()) {
+ // adjust x offset
+ int cursor_x = get_column_x_offset(cursor.column, text[cursor.line]);
- if (cursor_x > (cursor.x_ofs + visible_width))
- cursor.x_ofs = cursor_x - visible_width + 1;
+ if (cursor_x > (cursor.x_ofs + visible_width))
+ cursor.x_ofs = cursor_x - visible_width + 1;
- if (cursor_x < cursor.x_ofs)
- cursor.x_ofs = cursor_x;
-
- updating_scrolls = true;
- h_scroll->set_value(cursor.x_ofs);
- update_line_scroll_pos();
- double new_v_scroll = get_line_scroll_pos();
- // keep offset if smooth scroll is enabled
- if (smooth_scroll_enabled) {
- new_v_scroll += fmod(v_scroll->get_value(), 1.0);
+ if (cursor_x < cursor.x_ofs)
+ cursor.x_ofs = cursor_x;
+ } else {
+ cursor.x_ofs = 0;
}
- v_scroll->set_value(new_v_scroll);
- updating_scrolls = false;
+ h_scroll->set_value(cursor.x_ofs);
+
update();
}
void TextEdit::center_viewport_to_cursor() {
- scrolling = false;
- if (cursor.line_ofs > cursor.line)
- cursor.line_ofs = cursor.line;
+ // move viewport so the cursor is in the center of the screen
+ scrolling = false;
if (is_line_hidden(cursor.line))
unfold_line(cursor.line);
+ set_line_as_center_visible(cursor.line, get_cursor_wrap_index());
int visible_width = cache.size.width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width;
if (v_scroll->is_visible_in_tree())
visible_width -= v_scroll->get_combined_minimum_size().width;
visible_width -= 20; // give it a little more space
- int visible_rows = get_visible_rows();
- if (h_scroll->is_visible_in_tree())
- visible_rows -= ((h_scroll->get_combined_minimum_size().height - 1) / get_row_height());
- if (text.size() >= visible_rows) {
- int max_ofs = text.size() - (scroll_past_end_of_file_enabled ? 1 : MAX(num_lines_from(text.size() - 1, -visible_rows), 0));
- cursor.line_ofs = CLAMP(cursor.line - num_lines_from(MAX(cursor.line - visible_rows / 2, 0), -visible_rows / 2), 0, max_ofs);
+ if (is_wrap_enabled()) {
+ // center x offset
+ int cursor_x = get_column_x_offset_for_line(cursor.column, cursor.line);
+
+ if (cursor_x > (cursor.x_ofs + visible_width))
+ cursor.x_ofs = cursor_x - visible_width + 1;
+
+ if (cursor_x < cursor.x_ofs)
+ cursor.x_ofs = cursor_x;
+ } else {
+ cursor.x_ofs = 0;
}
- int cursor_x = get_column_x_offset(cursor.column, text[cursor.line]);
+ h_scroll->set_value(cursor.x_ofs);
- if (cursor_x > (cursor.x_ofs + visible_width))
- cursor.x_ofs = cursor_x - visible_width + 1;
+ update();
+}
- if (cursor_x < cursor.x_ofs)
- cursor.x_ofs = cursor_x;
+void TextEdit::update_cursor_wrap_offset() {
+ int first_vis_line = get_first_visible_line();
+ if (line_wraps(first_vis_line)) {
+ cursor.wrap_ofs = MIN(cursor.wrap_ofs, times_line_wraps(first_vis_line));
+ } else {
+ cursor.wrap_ofs = 0;
+ }
+ set_line_as_first_visible(cursor.line_ofs, cursor.wrap_ofs);
+}
- updating_scrolls = true;
- h_scroll->set_value(cursor.x_ofs);
- update_line_scroll_pos();
- double new_v_scroll = get_line_scroll_pos();
- // keep offset if smooth scroll is enabled
- if (smooth_scroll_enabled) {
- new_v_scroll += fmod(v_scroll->get_value(), 1.0);
+bool TextEdit::line_wraps(int line) const {
+
+ ERR_FAIL_INDEX_V(line, text.size(), 0);
+ if (!is_wrap_enabled())
+ return false;
+ return text.get_line_width(line) > wrap_at;
+}
+
+int TextEdit::times_line_wraps(int line) const {
+
+ ERR_FAIL_INDEX_V(line, text.size(), 0);
+ if (!line_wraps(line))
+ return 0;
+
+ int wrap_amount = text.get_line_wrap_amount(line);
+ if (wrap_amount == -1) {
+ // update the value
+ Vector<String> rows = get_wrap_rows_text(line);
+ wrap_amount = rows.size() - 1;
+ text.set_line_wrap_amount(line, wrap_amount);
}
- v_scroll->set_value(new_v_scroll);
- updating_scrolls = false;
- update();
+
+ return wrap_amount;
+}
+
+Vector<String> TextEdit::get_wrap_rows_text(int p_line) const {
+
+ ERR_FAIL_INDEX_V(p_line, text.size(), Vector<String>());
+
+ Vector<String> lines;
+ if (!line_wraps(p_line)) {
+ lines.push_back(text[p_line]);
+ return lines;
+ }
+
+ int px = 0;
+ int col = 0;
+ String line_text = text[p_line];
+ String wrap_substring = "";
+
+ int word_px = 0;
+ String word_str = "";
+ int cur_wrap_index = 0;
+
+ int tab_offset_px = get_indent_level(p_line) * cache.font->get_char_size(' ').width;
+
+ while (col < line_text.length()) {
+ char c = line_text[col];
+ int w = text.get_char_width(c, line_text[col + 1], px + word_px);
+
+ int indent_ofs = (cur_wrap_index != 0 ? tab_offset_px : 0);
+
+ word_str += c;
+ word_px += w;
+ if (c == ' ') {
+ // end of a word; add this word to the substring
+ wrap_substring += word_str;
+ px += word_px;
+ word_str = "";
+ word_px = 0;
+ }
+
+ if ((indent_ofs + px + word_px) > wrap_at) {
+ // do not want to add this word
+ if (indent_ofs + word_px > wrap_at) {
+ // not enough space; add it anyway
+ wrap_substring += word_str;
+ px += word_px;
+ word_str = "";
+ word_px = 0;
+ }
+ lines.push_back(wrap_substring);
+ // reset for next wrap
+ cur_wrap_index++;
+ wrap_substring = "";
+ px = 0;
+ }
+ col++;
+ }
+ // line ends before hit wrap_at; add this word to the substring
+ wrap_substring += word_str;
+ px += word_px;
+ lines.push_back(wrap_substring);
+ return lines;
+}
+
+int TextEdit::get_cursor_wrap_index() const {
+
+ return get_line_wrap_index_at_col(cursor.line, cursor.column);
+}
+
+int TextEdit::get_line_wrap_index_at_col(int p_line, int p_column) const {
+
+ ERR_FAIL_INDEX_V(p_line, text.size(), 0);
+
+ if (!line_wraps(p_line))
+ return 0;
+
+ // loop through wraps in the line text until we get to the column
+ int wrap_index = 0;
+ int col = 0;
+ Vector<String> rows = get_wrap_rows_text(p_line);
+ for (int i = 0; i < rows.size(); i++) {
+ wrap_index = i;
+ String s = rows[wrap_index];
+ col += s.length();
+ if (col > p_column)
+ break;
+ }
+ return wrap_index;
}
void TextEdit::cursor_set_column(int p_col, bool p_adjust_viewport) {
@@ -3608,7 +3799,7 @@ void TextEdit::cursor_set_column(int p_col, bool p_adjust_viewport) {
if (cursor.column > get_line(cursor.line).length())
cursor.column = get_line(cursor.line).length();
- cursor.last_fit_x = get_column_x_offset(cursor.column, get_line(cursor.line));
+ cursor.last_fit_x = get_column_x_offset_for_line(cursor.column, cursor.line);
if (p_adjust_viewport)
adjust_viewport_to_cursor();
@@ -3620,7 +3811,7 @@ void TextEdit::cursor_set_column(int p_col, bool p_adjust_viewport) {
}
}
-void TextEdit::cursor_set_line(int p_row, bool p_adjust_viewport, bool p_can_be_hidden) {
+void TextEdit::cursor_set_line(int p_row, bool p_adjust_viewport, bool p_can_be_hidden, int p_wrap_index) {
if (setting_row)
return;
@@ -3629,8 +3820,8 @@ void TextEdit::cursor_set_line(int p_row, bool p_adjust_viewport, bool p_can_be_
if (p_row < 0)
p_row = 0;
- if (p_row >= (int)text.size())
- p_row = (int)text.size() - 1;
+ if (p_row >= text.size())
+ p_row = text.size() - 1;
if (!p_can_be_hidden) {
if (is_line_hidden(CLAMP(p_row, 0, text.size() - 1))) {
@@ -3648,7 +3839,18 @@ void TextEdit::cursor_set_line(int p_row, bool p_adjust_viewport, bool p_can_be_
}
}
cursor.line = p_row;
- cursor.column = get_char_pos_for(cursor.last_fit_x, get_line(cursor.line));
+
+ int n_col = get_char_pos_for_line(cursor.last_fit_x, p_row, p_wrap_index);
+ if (is_wrap_enabled() && p_wrap_index < times_line_wraps(p_row)) {
+ Vector<String> rows = get_wrap_rows_text(p_row);
+ int row_end_col = 0;
+ for (int i = 0; i < p_wrap_index + 1; i++) {
+ row_end_col += rows[i].length();
+ }
+ if (n_col >= row_end_col)
+ n_col -= 1;
+ }
+ cursor.column = n_col;
if (p_adjust_viewport)
adjust_viewport_to_cursor();
@@ -3725,9 +3927,25 @@ void TextEdit::_scroll_moved(double p_to_val) {
if (h_scroll->is_visible_in_tree())
cursor.x_ofs = h_scroll->get_value();
if (v_scroll->is_visible_in_tree()) {
- double val = v_scroll->get_value();
- cursor.line_ofs = num_lines_from(0, (int)floor(val));
- line_scroll_pos = (int)floor(val);
+
+ // set line ofs and wrap ofs
+ int v_scroll_i = floor(get_v_scroll());
+ int sc = 0;
+ int n_line;
+ for (n_line = 0; n_line < text.size(); n_line++) {
+ if (!is_line_hidden(n_line)) {
+ sc++;
+ sc += times_line_wraps(n_line);
+ if (sc > v_scroll_i)
+ break;
+ }
+ }
+ int line_wrap_amount = times_line_wraps(n_line);
+ int wi = line_wrap_amount - (sc - v_scroll_i - 1);
+ wi = CLAMP(wi, 0, line_wrap_amount);
+
+ cursor.line_ofs = n_line;
+ cursor.wrap_ofs = wi;
}
update();
}
@@ -3737,29 +3955,73 @@ int TextEdit::get_row_height() const {
return cache.font->get_height() + cache.line_spacing;
}
-int TextEdit::get_char_pos_for(int p_px, String p_str) const {
+int TextEdit::get_char_pos_for_line(int p_px, int p_line, int p_wrap_index) const {
- int px = 0;
- int c = 0;
+ ERR_FAIL_INDEX_V(p_line, text.size(), 0);
- int tab_w = cache.font->get_char_size(' ').width * indent_size;
+ if (line_wraps(p_line)) {
- while (c < p_str.length()) {
+ int line_wrap_amount = times_line_wraps(p_line);
+ int wrap_offset_px = get_indent_level(p_line) * cache.font->get_char_size(' ').width;
+ if (p_wrap_index > line_wrap_amount)
+ p_wrap_index = line_wrap_amount;
+ if (p_wrap_index > 0)
+ p_px -= wrap_offset_px;
+ else
+ p_wrap_index = 0;
+ Vector<String> rows = get_wrap_rows_text(p_line);
+ int c_pos = get_char_pos_for(p_px, rows[p_wrap_index]);
+ for (int i = 0; i < p_wrap_index; i++) {
+ String s = rows[i];
+ c_pos += s.length();
+ }
- int w = 0;
+ return c_pos;
+ } else {
- if (p_str[c] == '\t') {
+ return get_char_pos_for(p_px, text[p_line]);
+ }
+}
- int left = px % tab_w;
- if (left == 0)
- w = tab_w;
- else
- w = tab_w - px % tab_w; // is right...
+int TextEdit::get_column_x_offset_for_line(int p_char, int p_line) const {
- } else {
+ ERR_FAIL_INDEX_V(p_line, text.size(), 0);
- w = cache.font->get_char_size(p_str[c], p_str[c + 1]).width;
+ if (line_wraps(p_line)) {
+
+ int n_char = p_char;
+ int col = 0;
+ Vector<String> rows = get_wrap_rows_text(p_line);
+ int wrap_index = 0;
+ for (int i = 0; i < rows.size(); i++) {
+ wrap_index = i;
+ String s = rows[wrap_index];
+ col += s.length();
+ if (col > p_char)
+ break;
+ n_char -= s.length();
}
+ int px = get_column_x_offset(n_char, rows[wrap_index]);
+
+ int wrap_offset_px = get_indent_level(p_line) * cache.font->get_char_size(' ').width;
+ if (wrap_index != 0)
+ px += wrap_offset_px;
+
+ return px;
+ } else {
+
+ return get_column_x_offset(p_char, text[p_line]);
+ }
+}
+
+int TextEdit::get_char_pos_for(int p_px, String p_str) const {
+
+ int px = 0;
+ int c = 0;
+
+ while (c < p_str.length()) {
+
+ int w = text.get_char_width(p_str[c], p_str[c + 1], px);
if (p_px < (px + w / 2))
break;
@@ -3770,28 +4032,16 @@ int TextEdit::get_char_pos_for(int p_px, String p_str) const {
return c;
}
-int TextEdit::get_column_x_offset(int p_char, String p_str) {
+int TextEdit::get_column_x_offset(int p_char, String p_str) const {
int px = 0;
- int tab_w = cache.font->get_char_size(' ').width * indent_size;
-
for (int i = 0; i < p_char; i++) {
if (i >= p_str.length())
break;
- if (p_str[i] == '\t') {
-
- int left = px % tab_w;
- if (left == 0)
- px += tab_w;
- else
- px += tab_w - px % tab_w; // is right...
-
- } else {
- px += cache.font->get_char_size(p_str[i], p_str[i + 1]).width;
- }
+ px += text.get_char_width(p_str[i], p_str[i + 1], px);
}
return px;
@@ -3867,7 +4117,7 @@ void TextEdit::set_text(String p_text) {
cursor.line = 0;
cursor.x_ofs = 0;
cursor.line_ofs = 0;
- line_scroll_pos = 0;
+ cursor.wrap_ofs = 0;
cursor.last_fit_x = 0;
cursor_set_line(0);
cursor_set_column(0);
@@ -3953,7 +4203,7 @@ void TextEdit::_clear() {
cursor.line = 0;
cursor.x_ofs = 0;
cursor.line_ofs = 0;
- line_scroll_pos = 0;
+ cursor.wrap_ofs = 0;
cursor.last_fit_x = 0;
}
@@ -3975,14 +4225,14 @@ bool TextEdit::is_readonly() const {
return readonly;
}
-void TextEdit::set_wrap(bool p_wrap) {
+void TextEdit::set_wrap_enabled(bool p_wrap_enabled) {
- wrap = p_wrap;
+ wrap_enabled = p_wrap_enabled;
}
-bool TextEdit::is_wrapping() const {
+bool TextEdit::is_wrap_enabled() const {
- return wrap;
+ return wrap_enabled;
}
void TextEdit::set_max_chars(int p_max_chars) {
@@ -4131,7 +4381,7 @@ void TextEdit::clear_colors() {
keywords.clear();
color_regions.clear();
color_region_cache.clear();
- text.clear_caches();
+ text.clear_width_cache();
}
void TextEdit::add_keyword_color(const String &p_keyword, const Color &p_color) {
@@ -4151,7 +4401,7 @@ Color TextEdit::get_keyword_color(String p_keyword) const {
void TextEdit::add_color_region(const String &p_begin_key, const String &p_end_key, const Color &p_color, bool p_line_only) {
color_regions.push_back(ColorRegion(p_begin_key, p_end_key, p_color, p_line_only));
- text.clear_caches();
+ text.clear_width_cache();
update();
}
@@ -4648,52 +4898,99 @@ void TextEdit::unhide_all_lines() {
update();
}
-int TextEdit::num_lines_from(int p_line_from, int unhidden_amount) const {
+int TextEdit::num_lines_from(int p_line_from, int visible_amount) const {
- // returns the number of hidden and unhidden lines from p_line_from to p_line_from + amount of visible lines
- ERR_FAIL_INDEX_V(p_line_from, text.size(), ABS(unhidden_amount));
+ // returns the number of lines (hidden and unhidden) from p_line_from to (p_line_from + visible_amount of unhidden lines)
+ ERR_FAIL_INDEX_V(p_line_from, text.size(), ABS(visible_amount));
if (!is_hiding_enabled())
- return ABS(unhidden_amount);
+ return ABS(visible_amount);
+
int num_visible = 0;
int num_total = 0;
- if (unhidden_amount >= 0) {
+ if (visible_amount >= 0) {
for (int i = p_line_from; i < text.size(); i++) {
num_total++;
- if (!is_line_hidden(i))
+ if (!is_line_hidden(i)) {
num_visible++;
- if (num_visible >= unhidden_amount)
+ }
+ if (num_visible >= visible_amount)
break;
}
} else {
- unhidden_amount = ABS(unhidden_amount);
+ visible_amount = ABS(visible_amount);
for (int i = p_line_from; i >= 0; i--) {
num_total++;
- if (!is_line_hidden(i))
+ if (!is_line_hidden(i)) {
num_visible++;
- if (num_visible >= unhidden_amount)
+ }
+ if (num_visible >= visible_amount)
break;
}
}
return num_total;
}
-bool TextEdit::is_last_visible_line(int p_line) const {
+int TextEdit::num_lines_from_rows(int p_line_from, int p_wrap_index_from, int visible_amount, int &wrap_index) const {
- ERR_FAIL_INDEX_V(p_line, text.size(), false);
+ // returns the number of lines (hidden and unhidden) from (p_line_from + p_wrap_index_from) row to (p_line_from + visible_amount of unhidden and wrapped rows)
+ // wrap index is set to the wrap index of the last line
+ wrap_index = 0;
+ ERR_FAIL_INDEX_V(p_line_from, text.size(), ABS(visible_amount));
- if (p_line == text.size() - 1)
- return true;
+ if (!is_hiding_enabled() && !is_wrap_enabled())
+ return ABS(visible_amount);
+
+ int num_visible = 0;
+ int num_total = 0;
+ if (visible_amount == 0) {
+ num_total = 0;
+ wrap_index = 0;
+ } else if (visible_amount > 0) {
+ int i;
+ num_visible -= p_wrap_index_from;
+ for (i = p_line_from; i < text.size(); i++) {
+ num_total++;
+ if (!is_line_hidden(i)) {
+ num_visible++;
+ num_visible += times_line_wraps(i);
+ }
+ if (num_visible >= visible_amount)
+ break;
+ }
+ wrap_index = times_line_wraps(MIN(i, text.size() - 1)) - (num_visible - visible_amount);
+ } else {
+ visible_amount = ABS(visible_amount);
+ int i;
+ num_visible -= times_line_wraps(p_line_from) - p_wrap_index_from;
+ for (i = p_line_from; i >= 0; i--) {
+ num_total++;
+ if (!is_line_hidden(i)) {
+ num_visible++;
+ num_visible += times_line_wraps(i);
+ }
+ if (num_visible >= visible_amount)
+ break;
+ }
+ wrap_index = (num_visible - visible_amount);
+ }
+ wrap_index = MAX(wrap_index, 0);
+ return num_total;
+}
+
+int TextEdit::get_last_unhidden_line() const {
+ // returns the last line in the text that is not hidden
if (!is_hiding_enabled())
- return false;
+ return text.size() - 1;
- for (int i = p_line + 1; i < text.size(); i++) {
- if (!is_line_hidden(i))
- return false;
+ int last_line;
+ for (last_line = text.size() - 1; last_line > 0; last_line--) {
+ if (!is_line_hidden(last_line)) {
+ break;
+ }
}
-
- return true;
+ return last_line;
}
int TextEdit::get_indent_level(int p_line) const {
@@ -4713,7 +5010,7 @@ int TextEdit::get_indent_level(int p_line) const {
break;
}
}
- return tab_count + whitespace_count / indent_size;
+ return tab_count * indent_size + whitespace_count;
}
bool TextEdit::is_line_comment(int p_line) const {
@@ -5061,6 +5358,7 @@ bool TextEdit::is_drawing_tabs() const {
void TextEdit::set_override_selected_font_color(bool p_override_selected_font_color) {
override_selected_font_color = p_override_selected_font_color;
}
+
bool TextEdit::is_overriding_selected_font_color() const {
return override_selected_font_color;
}
@@ -5081,58 +5379,143 @@ bool TextEdit::is_insert_text_operation() {
uint32_t TextEdit::get_version() const {
return current_op.version;
}
+
uint32_t TextEdit::get_saved_version() const {
return saved_version;
}
+
void TextEdit::tag_saved_version() {
saved_version = get_version();
}
-int TextEdit::get_v_scroll() const {
+double TextEdit::get_scroll_pos_for_line(int p_line, int p_wrap_index) const {
- return v_scroll->get_value();
-}
-void TextEdit::set_v_scroll(int p_scroll) {
+ if (!is_wrap_enabled() && !is_hiding_enabled())
+ return p_line;
- if (p_scroll < 0) {
- p_scroll = 0;
- }
- if (!scroll_past_end_of_file_enabled) {
- if (p_scroll + get_visible_rows() > get_total_unhidden_rows()) {
- int num_rows = num_lines_from(CLAMP(p_scroll, 0, text.size() - 1), MIN(get_visible_rows(), text.size() - 1 - p_scroll));
- p_scroll = text.size() - num_rows;
+ // count the number of visible lines up to this line
+ double new_line_scroll_pos = 0;
+ int to = CLAMP(p_line, 0, text.size() - 1);
+ for (int i = 0; i < to; i++) {
+ if (!text.is_hidden(i)) {
+ new_line_scroll_pos++;
+ new_line_scroll_pos += times_line_wraps(i);
}
}
+ new_line_scroll_pos += p_wrap_index;
+ return new_line_scroll_pos;
+}
+
+void TextEdit::set_line_as_first_visible(int p_line, int p_wrap_index) {
+
+ set_v_scroll(get_scroll_pos_for_line(p_line, p_wrap_index));
+}
+
+void TextEdit::set_line_as_center_visible(int p_line, int p_wrap_index) {
+
+ int visible_rows = get_visible_rows();
+ int wi;
+ int first_line = p_line - num_lines_from_rows(p_line, p_wrap_index, -visible_rows / 2, wi) + 1;
+
+ set_v_scroll(get_scroll_pos_for_line(first_line, wi));
+}
+
+void TextEdit::set_line_as_last_visible(int p_line, int p_wrap_index) {
+
+ int wi;
+ int first_line = p_line - num_lines_from_rows(p_line, p_wrap_index, -get_visible_rows() - 1, wi) + 1;
+
+ set_v_scroll(get_scroll_pos_for_line(first_line, wi) + get_visible_rows_offset());
+}
+
+int TextEdit::get_first_visible_line() const {
+
+ return CLAMP(cursor.line_ofs, 0, text.size() - 1);
+}
+
+int TextEdit::get_last_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 = CLAMP(last_vis_line, 0, text.size() - 1);
+ return last_vis_line;
+}
+
+int TextEdit::get_last_visible_line_wrap_index() 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;
+ return wi;
+}
+
+double TextEdit::get_visible_rows_offset() const {
+
+ double total = cache.size.height;
+ total -= cache.style_normal->get_minimum_size().height;
+ if (h_scroll->is_visible_in_tree())
+ total -= h_scroll->get_size().height;
+ total /= (double)get_row_height();
+ total = total - floor(total);
+ total = -CLAMP(total, 0.001, 1) + 1;
+ return total;
+}
+
+double TextEdit::get_v_scroll_offset() const {
+
+ double val = get_v_scroll() - floor(get_v_scroll());
+ return CLAMP(val, 0, 1);
+}
+
+double TextEdit::get_v_scroll() const {
+
+ return v_scroll->get_value();
+}
+
+void TextEdit::set_v_scroll(double p_scroll) {
+
v_scroll->set_value(p_scroll);
- cursor.line_ofs = num_lines_from(0, p_scroll);
- line_scroll_pos = p_scroll;
+ int max_v_scroll = v_scroll->get_max() - v_scroll->get_page();
+ if (p_scroll >= max_v_scroll - 1.0)
+ _scroll_moved(v_scroll->get_value());
}
int TextEdit::get_h_scroll() const {
return h_scroll->get_value();
}
+
void TextEdit::set_h_scroll(int p_scroll) {
+ if (p_scroll < 0) {
+ p_scroll = 0;
+ }
h_scroll->set_value(p_scroll);
}
void TextEdit::set_smooth_scroll_enabled(bool p_enable) {
+
v_scroll->set_smooth_scroll_enabled(p_enable);
smooth_scroll_enabled = p_enable;
}
bool TextEdit::is_smooth_scroll_enabled() const {
+
return smooth_scroll_enabled;
}
void TextEdit::set_v_scroll_speed(float p_speed) {
+
v_scroll_speed = p_speed;
}
float TextEdit::get_v_scroll_speed() const {
+
return v_scroll_speed;
}
@@ -5612,7 +5995,7 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_line", "line"), &TextEdit::get_line);
ClassDB::bind_method(D_METHOD("cursor_set_column", "column", "adjust_viewport"), &TextEdit::cursor_set_column, DEFVAL(true));
- ClassDB::bind_method(D_METHOD("cursor_set_line", "line", "adjust_viewport", "can_be_hidden"), &TextEdit::cursor_set_line, DEFVAL(true), DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("cursor_set_line", "line", "adjust_viewport", "can_be_hidden", "wrap_index"), &TextEdit::cursor_set_line, DEFVAL(true), DEFVAL(true), DEFVAL(0));
ClassDB::bind_method(D_METHOD("cursor_get_column"), &TextEdit::cursor_get_column);
ClassDB::bind_method(D_METHOD("cursor_get_line"), &TextEdit::cursor_get_line);
@@ -5629,8 +6012,8 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_readonly", "enable"), &TextEdit::set_readonly);
ClassDB::bind_method(D_METHOD("is_readonly"), &TextEdit::is_readonly);
- ClassDB::bind_method(D_METHOD("set_wrap", "enable"), &TextEdit::set_wrap);
- ClassDB::bind_method(D_METHOD("is_wrapping"), &TextEdit::is_wrapping);
+ ClassDB::bind_method(D_METHOD("set_wrap_enabled", "enable"), &TextEdit::set_wrap_enabled);
+ ClassDB::bind_method(D_METHOD("is_wrap_enabled"), &TextEdit::is_wrap_enabled);
// ClassDB::bind_method(D_METHOD("set_max_chars", "amount"), &TextEdit::set_max_chars);
// ClassDB::bind_method(D_METHOD("get_max_char"), &TextEdit::get_max_chars);
ClassDB::bind_method(D_METHOD("set_context_menu_enabled", "enable"), &TextEdit::set_context_menu_enabled);
@@ -5708,7 +6091,7 @@ void TextEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_scrolling"), "set_smooth_scroll_enable", "is_smooth_scroll_enabled");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_scroll_speed"), "set_v_scroll_speed", "get_v_scroll_speed");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hiding_enabled"), "set_hiding_enabled", "is_hiding_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "wrap_lines"), "set_wrap", "is_wrapping");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "wrap_enabled"), "set_wrap_enabled", "is_wrap_enabled");
// ADD_PROPERTY(PropertyInfo(Variant::BOOL, "max_chars"), "set_max_chars", "get_max_chars");
ADD_GROUP("Caret", "caret_");
@@ -5743,7 +6126,8 @@ TextEdit::TextEdit() {
draw_caret = true;
max_chars = 0;
clear();
- wrap = false;
+ wrap_enabled = false;
+ wrap_right_offset = 10;
set_focus_mode(FOCUS_ALL);
syntax_highlighter = NULL;
_update_caches();
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 60c6ab4929..5c82d1ac20 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -76,6 +76,7 @@ public:
bool marked : 1;
bool breakpoint : 1;
bool hidden : 1;
+ int wrap_amount_cache : 24;
Map<int, ColorRegionInfo> region_info;
String data;
};
@@ -94,6 +95,9 @@ public:
void set_color_regions(const Vector<ColorRegion> *p_regions) { color_regions = p_regions; }
int get_line_width(int p_line) const;
int get_max_width(bool p_exclude_hidden = false) const;
+ int get_char_width(CharType c, CharType next_c, int px) const;
+ void set_line_wrap_amount(int p_line, int p_wrap_amount) const;
+ int get_line_wrap_amount(int p_line) const;
const Map<int, ColorRegionInfo> &get_color_region_info(int p_line) const;
void set(int p_line, const String &p_text);
void set_marked(int p_line, bool p_marked) { text[p_line].marked = p_marked; }
@@ -106,7 +110,8 @@ public:
void remove(int p_at);
int size() const { return text.size(); }
void clear();
- void clear_caches();
+ void clear_width_cache();
+ void clear_wrap_cache();
_FORCE_INLINE_ const String &operator[](int p_line) const { return text[p_line].data; }
Text() { indent_size = 4; }
};
@@ -115,7 +120,7 @@ private:
struct Cursor {
int last_fit_x;
int line, column; ///< cursor
- int x_ofs, line_ofs;
+ int x_ofs, line_ofs, wrap_ofs;
} cursor;
struct Selection {
@@ -263,8 +268,11 @@ private:
bool block_caret;
bool right_click_moves_caret;
+ bool wrap_enabled;
+ int wrap_at;
+ int wrap_right_offset;
+
bool setting_row;
- bool wrap;
bool draw_tabs;
bool override_selected_font_color;
bool cursor_changed_dirty;
@@ -321,19 +329,34 @@ private:
int search_result_line;
int search_result_col;
- double line_scroll_pos;
-
bool context_menu_enabled;
int get_visible_rows() const;
- int get_total_unhidden_rows() const;
- double get_line_scroll_pos(bool p_recalculate = false) const;
- void update_line_scroll_pos();
-
+ int get_total_visible_rows() const;
+
+ void update_cursor_wrap_offset();
+ void update_wrap_at();
+ bool line_wraps(int line) const;
+ int times_line_wraps(int line) const;
+ Vector<String> get_wrap_rows_text(int p_line) const;
+ int get_cursor_wrap_index() const;
+ int get_line_wrap_index_at_col(int p_line, int p_column) const;
int get_char_count();
+ double get_scroll_pos_for_line(int p_line, int p_wrap_index = 0) const;
+ void set_line_as_first_visible(int p_line, int p_wrap_index = 0);
+ 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;
+ double get_visible_rows_offset() const;
+ double get_v_scroll_offset() const;
+
+ int get_char_pos_for_line(int p_px, int p_line, int p_wrap_index = 0) const;
+ int get_column_x_offset_for_line(int p_char, int p_line) const;
int get_char_pos_for(int p_px, String p_str) const;
- int get_column_x_offset(int p_char, String p_str);
+ int get_column_x_offset(int p_char, String p_str) const;
void adjust_viewport_to_cursor();
double get_scroll_line_diff() const;
@@ -455,8 +478,10 @@ public:
bool is_line_hidden(int p_line) const;
void fold_all_lines();
void unhide_all_lines();
- int num_lines_from(int p_line_from, int unhidden_amount) const;
- bool is_last_visible_line(int p_line) const;
+ int num_lines_from(int p_line_from, int visible_amount) const;
+ int num_lines_from_rows(int p_line_from, int p_wrap_index_from, int visible_amount, int &wrap_index) const;
+ int get_last_unhidden_line() const;
+
bool can_fold(int p_line) const;
bool is_folded(int p_line) const;
void fold_line(int p_line);
@@ -493,7 +518,7 @@ public:
void center_viewport_to_cursor();
void cursor_set_column(int p_col, bool p_adjust_viewport = true);
- void cursor_set_line(int p_row, bool p_adjust_viewport = true, bool p_can_be_hidden = true);
+ void cursor_set_line(int p_row, bool p_adjust_viewport = true, bool p_can_be_hidden = true, int p_wrap_index = 0);
int cursor_get_column() const;
int cursor_get_line() const;
@@ -516,8 +541,8 @@ public:
void set_max_chars(int p_max_chars);
int get_max_chars() const;
- void set_wrap(bool p_wrap);
- bool is_wrapping() const;
+ void set_wrap_enabled(bool p_wrap_enabled);
+ bool is_wrap_enabled() const;
void clear();
@@ -578,8 +603,8 @@ public:
Color get_member_color(String p_member) const;
void clear_member_keywords();
- int get_v_scroll() const;
- void set_v_scroll(int p_scroll);
+ double get_v_scroll() const;
+ void set_v_scroll(double p_scroll);
int get_h_scroll() const;
void set_h_scroll(int p_scroll);
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index e6ea4e4b4a..3643aedb85 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -176,6 +176,9 @@ void Node::_propagate_ready() {
data.children[i]->_propagate_ready();
}
data.blocked--;
+
+ notification(NOTIFICATION_POST_ENTER_TREE);
+
if (data.ready_first) {
data.ready_first = false;
notification(NOTIFICATION_READY);
diff --git a/scene/main/node.h b/scene/main/node.h
index 4ff1247e14..540f34cba7 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -237,6 +237,7 @@ public:
NOTIFICATION_TRANSLATION_CHANGED = 24,
NOTIFICATION_INTERNAL_PROCESS = 25,
NOTIFICATION_INTERNAL_PHYSICS_PROCESS = 26,
+ NOTIFICATION_POST_ENTER_TREE = 27,
};
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 295f131db3..f631fd6f3a 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -72,6 +72,9 @@ void ViewportTexture::setup_local_to_scene() {
vp->viewport_textures.insert(this);
VS::get_singleton()->texture_set_proxy(proxy, vp->texture_rid);
+
+ vp->texture_flags = flags;
+ VS::get_singleton()->texture_set_flags(vp->texture_rid, flags);
}
void ViewportTexture::set_viewport_path_in_scene(const NodePath &p_path) {
@@ -122,20 +125,18 @@ Ref<Image> ViewportTexture::get_data() const {
return VS::get_singleton()->texture_get_data(vp->texture_rid);
}
void ViewportTexture::set_flags(uint32_t p_flags) {
+ flags = p_flags;
if (!vp)
return;
- vp->texture_flags = p_flags;
- VS::get_singleton()->texture_set_flags(vp->texture_rid, p_flags);
+ vp->texture_flags = flags;
+ VS::get_singleton()->texture_set_flags(vp->texture_rid, flags);
}
uint32_t ViewportTexture::get_flags() const {
- if (!vp)
- return 0;
-
- return vp->texture_flags;
+ return flags;
}
void ViewportTexture::_bind_methods() {
@@ -149,6 +150,7 @@ void ViewportTexture::_bind_methods() {
ViewportTexture::ViewportTexture() {
vp = NULL;
+ flags = 0;
set_local_to_scene(true);
proxy = VS::get_singleton()->texture_create();
}
@@ -1345,7 +1347,7 @@ void Viewport::_gui_show_tooltip() {
gui.tooltip_label->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -ttp->get_margin(MARGIN_RIGHT));
gui.tooltip_label->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, -ttp->get_margin(MARGIN_BOTTOM));
gui.tooltip_label->set_text(tooltip.strip_edges());
- Rect2 r(gui.tooltip_pos + Point2(10, 10), gui.tooltip_label->get_combined_minimum_size() + ttp->get_minimum_size());
+ Rect2 r(gui.tooltip_pos + Point2(10, 10), gui.tooltip_label->get_minimum_size() + ttp->get_minimum_size());
Rect2 vr = gui.tooltip_label->get_viewport_rect();
if (r.size.x + r.position.x > vr.size.x)
r.position.x = vr.size.x - r.size.x;
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 363414bbad..c1ef58de69 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -58,6 +58,7 @@ class ViewportTexture : public Texture {
friend class Viewport;
Viewport *vp;
+ uint32_t flags;
RID proxy;
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 5ac9344f31..3ea856541e 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -544,6 +544,11 @@ 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
+ Ref<StyleBoxEmpty> empty;
+ empty.instance();
+ theme->set_stylebox("bg", "ScrollContainer", empty);
+
// WindowDialog
theme->set_stylebox("panel", "WindowDialog", sb_expand(make_stylebox(popup_window_png, 10, 26, 10, 8), 8, 24, 8, 6));
diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp
index f41a26a680..05493d5777 100644
--- a/scene/resources/dynamic_font.cpp
+++ b/scene/resources/dynamic_font.cpp
@@ -307,8 +307,6 @@ Size2 DynamicFontAtSize::get_char_size(CharType p_char, CharType p_next, const V
}
ret.x += _get_kerning_advance(font, p_char, p_next);
- // ensures oversampled glyphs will have enough space when this value is used by clipping/wrapping algorithms
- ret.x = Math::ceil(ret.x);
return ret;
}
@@ -1080,6 +1078,11 @@ void DynamicFont::update_oversampling() {
if (E->self()->data_at_size.is_valid()) {
E->self()->data_at_size->update_oversampling();
+
+ if (E->self()->outline_data_at_size.is_valid()) {
+ E->self()->outline_data_at_size->update_oversampling();
+ }
+
changed.push_back(Ref<DynamicFont>(E->self()));
}
E = E->next();
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index d87644381c..b0620d3363 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -222,7 +222,6 @@ Ref<Mesh> Mesh::create_outline(float p_margin) const {
continue;
Array a = surface_get_arrays(i);
- int vcount = 0;
if (i == 0) {
arrays = a;
@@ -230,6 +229,7 @@ Ref<Mesh> Mesh::create_outline(float p_margin) const {
index_accum += v.size();
} else {
+ int vcount = 0;
for (int j = 0; j < arrays.size(); j++) {
if (arrays[j].get_type() == Variant::NIL || a[j].get_type() == Variant::NIL) {
@@ -1194,8 +1194,6 @@ Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texe
for (int j = 0; j < 3; j++) {
- int vertex_idx = gen_vertices[gen_indices[i + j]];
-
SurfaceTool::Vertex v = surfaces[surface].vertices[uv_index[gen_vertices[gen_indices[i + j]]].second];
if (surfaces[surface].format & ARRAY_FORMAT_COLOR) {
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index e0562d9e4a..5b600623b9 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -676,7 +676,7 @@ void CubeMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_subdivide_depth", "divisions"), &CubeMesh::set_subdivide_depth);
ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &CubeMesh::get_subdivide_depth);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1"), "set_subdivide_width", "get_subdivide_width");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_height", PROPERTY_HINT_RANGE, "0,100,1"), "set_subdivide_height", "get_subdivide_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1"), "set_subdivide_depth", "get_subdivide_depth");
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index 7da65ac984..ebad00b068 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -136,8 +136,17 @@ Ref<Texture> StyleBoxTexture::get_normal_map() const {
void StyleBoxTexture::set_margin_size(Margin p_margin, float p_size) {
+ ERR_FAIL_INDEX(p_margin, 4);
+
margin[p_margin] = p_size;
emit_changed();
+ static const char *margin_prop[4] = {
+ "content_margin_left",
+ "content_margin_top",
+ "content_margin_right",
+ "content_margin_bottom",
+ };
+ _change_notify(margin_prop[p_margin]);
}
float StyleBoxTexture::get_margin_size(Margin p_margin) const {
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index c0f6756fd1..54f5aea160 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -76,7 +76,9 @@ void Texture::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_rect_region", "canvas_item", "rect", "src_rect", "modulate", "transpose", "normal_map", "clip_uv"), &Texture::draw_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()), DEFVAL(true));
ClassDB::bind_method(D_METHOD("get_data"), &Texture::get_data);
+ ADD_GROUP("Flags", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Mipmaps,Repeat,Filter,Anisotropic Linear,Convert to Linear,Mirrored Repeat,Video Surface"), "set_flags", "get_flags");
+ ADD_GROUP("", "");
BIND_ENUM_CONSTANT(FLAGS_DEFAULT);
BIND_ENUM_CONSTANT(FLAG_MIPMAPS);
@@ -220,12 +222,15 @@ Image::Format ImageTexture::get_format() const {
return format;
}
-void ImageTexture::load(const String &p_path) {
+Error ImageTexture::load(const String &p_path) {
Ref<Image> img;
img.instance();
- img->load(p_path);
- create_from_image(img);
+ Error err = img->load(p_path);
+ if (err == OK) {
+ create_from_image(img);
+ }
+ return err;
}
void ImageTexture::set_data(const Ref<Image> &p_image) {
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index 93d7ec4ef9..d81fd3b19b 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -124,7 +124,7 @@ public:
void set_flags(uint32_t p_flags);
uint32_t get_flags() const;
Image::Format get_format() const;
- void load(const String &p_path);
+ Error load(const String &p_path);
void set_data(const Ref<Image> &p_image);
Ref<Image> get_data() const;
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 42d64376f5..58057cda0c 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -264,7 +264,7 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::RECT2, pre + "region"));
p_list->push_back(PropertyInfo(Variant::INT, pre + "tile_mode", PROPERTY_HINT_ENUM, "SINGLE_TILE,AUTO_TILE"));
if (tile_get_tile_mode(id) == AUTO_TILE) {
- p_list->push_back(PropertyInfo(Variant::INT, pre + "autotile/bitmask_mode", PROPERTY_HINT_ENUM, "2X2,3X3", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
+ p_list->push_back(PropertyInfo(Variant::INT, pre + "autotile/bitmask_mode", PROPERTY_HINT_ENUM, "2X2,3X3 (minimal),3X3", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/bitmask_flags", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "autotile/icon_coordinate", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "autotile/tile_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
@@ -960,6 +960,7 @@ void TileSet::_bind_methods() {
BIND_VMETHOD(MethodInfo(Variant::VECTOR2, "_forward_subtile_selection", PropertyInfo(Variant::INT, "autotile_id"), PropertyInfo(Variant::INT, "bitmask"), PropertyInfo(Variant::OBJECT, "tilemap", PROPERTY_HINT_NONE, "TileMap"), PropertyInfo(Variant::VECTOR2, "tile_location")));
BIND_ENUM_CONSTANT(BITMASK_2X2);
+ BIND_ENUM_CONSTANT(BITMASK_3X3_MINIMAL);
BIND_ENUM_CONSTANT(BITMASK_3X3);
BIND_ENUM_CONSTANT(BIND_TOPLEFT);
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index d5704ac9a0..ec635ee5cc 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -56,6 +56,7 @@ public:
enum BitmaskMode {
BITMASK_2X2,
+ BITMASK_3X3_MINIMAL,
BITMASK_3X3
};