summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/canvas_item.cpp9
-rw-r--r--scene/2d/collision_object_2d.cpp7
-rw-r--r--scene/2d/cpu_particles_2d.h4
-rw-r--r--scene/2d/navigation_2d.cpp4
-rw-r--r--scene/2d/parallax_layer.cpp3
-rw-r--r--scene/2d/path_2d.cpp2
-rw-r--r--scene/2d/physics_body_2d.cpp14
-rw-r--r--scene/2d/tile_map.cpp1
-rw-r--r--scene/3d/camera.h4
-rw-r--r--scene/3d/collision_object.cpp3
-rw-r--r--scene/3d/collision_polygon.cpp2
-rw-r--r--scene/3d/cpu_particles.h4
-rw-r--r--scene/3d/light.h4
-rw-r--r--scene/3d/mesh_instance.h3
-rw-r--r--scene/3d/multimesh_instance.h4
-rw-r--r--scene/3d/particles.h4
-rw-r--r--scene/3d/physics_body.cpp16
-rw-r--r--scene/3d/physics_body.h2
-rw-r--r--scene/3d/portal.h3
-rw-r--r--scene/3d/ray_cast.cpp2
-rw-r--r--scene/3d/room_instance.h4
-rw-r--r--scene/3d/skeleton.h4
-rw-r--r--scene/3d/spatial.h4
-rw-r--r--scene/3d/sprite_3d.cpp21
-rw-r--r--scene/3d/sprite_3d.h3
-rw-r--r--scene/3d/visual_instance.h4
-rw-r--r--scene/3d/world_environment.h4
-rw-r--r--scene/animation/animation_player.cpp4
-rw-r--r--scene/animation/animation_player.h3
-rw-r--r--scene/animation/animation_tree.cpp1
-rw-r--r--scene/gui/base_button.h3
-rw-r--r--scene/gui/button.cpp289
-rw-r--r--scene/gui/button.h9
-rw-r--r--scene/gui/color_picker.cpp34
-rw-r--r--scene/gui/color_picker.h2
-rw-r--r--scene/gui/control.cpp14
-rw-r--r--scene/gui/control.h3
-rw-r--r--scene/gui/dialogs.h3
-rw-r--r--scene/gui/file_dialog.cpp2
-rw-r--r--scene/gui/file_dialog.h4
-rw-r--r--scene/gui/gradient_edit.cpp10
-rw-r--r--scene/gui/graph_edit.cpp20
-rw-r--r--scene/gui/graph_node.cpp3
-rw-r--r--scene/gui/label.h4
-rw-r--r--scene/gui/line_edit.cpp20
-rw-r--r--scene/gui/line_edit.h3
-rw-r--r--scene/gui/menu_button.h4
-rw-r--r--scene/gui/nine_patch_rect.h4
-rw-r--r--scene/gui/option_button.h4
-rw-r--r--scene/gui/panel.h4
-rw-r--r--scene/gui/popup.cpp3
-rw-r--r--scene/gui/popup.h3
-rw-r--r--scene/gui/popup_menu.h4
-rw-r--r--scene/gui/range.h4
-rw-r--r--scene/gui/rich_text_label.cpp5
-rw-r--r--scene/gui/scroll_bar.h4
-rw-r--r--scene/gui/scroll_container.cpp21
-rw-r--r--scene/gui/separator.h4
-rw-r--r--scene/gui/spin_box.cpp25
-rw-r--r--scene/gui/tab_container.cpp14
-rw-r--r--scene/gui/tab_container.h3
-rw-r--r--scene/gui/text_edit.cpp995
-rw-r--r--scene/gui/text_edit.h24
-rw-r--r--scene/gui/texture_button.cpp16
-rw-r--r--scene/gui/texture_rect.h4
-rw-r--r--scene/gui/tree.cpp29
-rw-r--r--scene/gui/tree.h8
-rw-r--r--scene/gui/viewport_container.cpp1
-rw-r--r--scene/main/http_request.cpp4
-rw-r--r--scene/main/node.cpp35
-rw-r--r--scene/main/node.h7
-rw-r--r--scene/main/scene_tree.cpp40
-rw-r--r--scene/main/scene_tree.h6
-rw-r--r--scene/main/viewport.cpp14
-rw-r--r--scene/main/viewport.h3
-rw-r--r--scene/register_scene_types.cpp4
-rw-r--r--scene/register_scene_types.h4
-rw-r--r--scene/resources/animation.cpp8
-rw-r--r--scene/resources/animation.h4
-rw-r--r--scene/resources/default_theme/default_theme.cpp11
-rw-r--r--scene/resources/default_theme/default_theme.h3
-rw-r--r--scene/resources/dynamic_font.cpp8
-rw-r--r--scene/resources/environment.cpp2
-rw-r--r--scene/resources/font.h3
-rw-r--r--scene/resources/material.cpp11
-rw-r--r--scene/resources/material.h9
-rw-r--r--scene/resources/mesh.h3
-rw-r--r--scene/resources/room.h3
-rw-r--r--scene/resources/style_box.h4
-rw-r--r--scene/resources/texture.h4
-rw-r--r--scene/resources/theme.h3
-rw-r--r--scene/resources/visual_shader.cpp226
-rw-r--r--scene/resources/visual_shader.h59
93 files changed, 1522 insertions, 709 deletions
diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp
index b605be47df..fc5e5cbba2 100644
--- a/scene/2d/canvas_item.cpp
+++ b/scene/2d/canvas_item.cpp
@@ -641,6 +641,9 @@ void CanvasItem::update() {
void CanvasItem::set_modulate(const Color &p_modulate) {
+ if (modulate == p_modulate)
+ return;
+
modulate = p_modulate;
VisualServer::get_singleton()->canvas_item_set_modulate(canvas_item, modulate);
}
@@ -679,6 +682,9 @@ CanvasItem *CanvasItem::get_parent_item() const {
void CanvasItem::set_self_modulate(const Color &p_self_modulate) {
+ if (self_modulate == p_self_modulate)
+ return;
+
self_modulate = p_self_modulate;
VisualServer::get_singleton()->canvas_item_set_self_modulate(canvas_item, self_modulate);
}
@@ -689,6 +695,9 @@ Color CanvasItem::get_self_modulate() const {
void CanvasItem::set_light_mask(int p_light_mask) {
+ if (light_mask == p_light_mask)
+ return;
+
light_mask = p_light_mask;
VS::get_singleton()->canvas_item_set_light_mask(canvas_item, p_light_mask);
}
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index 202c7c9cf2..228b67990c 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -376,11 +376,12 @@ void CollisionObject2D::set_only_update_transform_changes(bool p_enable) {
void CollisionObject2D::_update_pickable() {
if (!is_inside_tree())
return;
- bool pickable = this->pickable && is_inside_tree() && is_visible_in_tree();
+
+ bool is_pickable = pickable && is_visible_in_tree();
if (area)
- Physics2DServer::get_singleton()->area_set_pickable(rid, pickable);
+ Physics2DServer::get_singleton()->area_set_pickable(rid, is_pickable);
else
- Physics2DServer::get_singleton()->body_set_pickable(rid, pickable);
+ Physics2DServer::get_singleton()->body_set_pickable(rid, is_pickable);
}
String CollisionObject2D::get_configuration_warning() const {
diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h
index 1cd22df9e7..da668664b9 100644
--- a/scene/2d/cpu_particles_2d.h
+++ b/scene/2d/cpu_particles_2d.h
@@ -35,10 +35,6 @@
#include "scene/2d/node_2d.h"
#include "scene/resources/texture.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-
class CPUParticles2D : public Node2D {
private:
GDCLASS(CPUParticles2D, Node2D);
diff --git a/scene/2d/navigation_2d.cpp b/scene/2d/navigation_2d.cpp
index f644db462b..5cf28d6c89 100644
--- a/scene/2d/navigation_2d.cpp
+++ b/scene/2d/navigation_2d.cpp
@@ -551,7 +551,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
left_poly = p;
portal_left = apex_point;
portal_right = apex_point;
- if (!path.size() || !Math::is_zero_approx(path[path.size() - 1].distance_to(apex_point)))
+ if (!path.size() || path[path.size() - 1] != apex_point)
path.push_back(apex_point);
skip = true;
}
@@ -569,7 +569,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
right_poly = p;
portal_right = apex_point;
portal_left = apex_point;
- if (!path.size() || !Math::is_zero_approx(path[path.size() - 1].distance_to(apex_point)))
+ if (!path.size() || path[path.size() - 1] != apex_point)
path.push_back(apex_point);
}
}
diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp
index 9a6b63b9a3..0823e09110 100644
--- a/scene/2d/parallax_layer.cpp
+++ b/scene/2d/parallax_layer.cpp
@@ -69,6 +69,9 @@ Size2 ParallaxLayer::get_motion_offset() const {
void ParallaxLayer::_update_mirroring() {
+ if (!is_inside_tree())
+ return;
+
ParallaxBackground *pb = Object::cast_to<ParallaxBackground>(get_parent());
if (pb) {
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index f2f53d4354..55c8c7f229 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -110,7 +110,7 @@ void Path2D::_notification(int p_what) {
real_t frac = j / 8.0;
Vector2 p = curve->interpolate(i, frac);
- draw_line(prev_p, p, color, line_width);
+ draw_line(prev_p, p, color, line_width, true);
prev_p = p;
}
}
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 49da709a47..9b6020e0fd 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -594,7 +594,7 @@ real_t RigidBody2D::get_mass() const {
void RigidBody2D::set_inertia(real_t p_inertia) {
- ERR_FAIL_COND(p_inertia <= 0);
+ ERR_FAIL_COND(p_inertia < 0);
Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_INERTIA, p_inertia);
}
@@ -1266,7 +1266,7 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const
//all is a wall
on_wall = true;
} else {
- if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //floor
+ if (Math::acos(collision.normal.dot(p_floor_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor
on_floor = true;
on_floor_body = collision.collider_rid;
@@ -1281,7 +1281,7 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const
}
}
- } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //ceiling
+ } else if (Math::acos(collision.normal.dot(-p_floor_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling
on_ceiling = true;
} else {
on_wall = true;
@@ -1446,6 +1446,14 @@ void KinematicBody2D::_direct_state_changed(Object *p_state) {
void KinematicBody2D::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
last_valid_transform = get_global_transform();
+
+ // Reset move_and_slide() data.
+ on_floor = false;
+ on_floor_body = RID();
+ on_ceiling = false;
+ on_wall = false;
+ colliders.clear();
+ floor_velocity = Vector2();
}
if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 2cd05b5c50..15423f8c5e 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -1944,6 +1944,7 @@ TileMap::TileMap() {
quadrant_order_dirty = false;
quadrant_size = 16;
cell_size = Size2(64, 64);
+ custom_transform = Transform2D(64, 0, 0, 64, 0, 0);
collision_layer = 1;
collision_mask = 1;
friction = 1;
diff --git a/scene/3d/camera.h b/scene/3d/camera.h
index 6460f17e85..22223880c1 100644
--- a/scene/3d/camera.h
+++ b/scene/3d/camera.h
@@ -35,9 +35,7 @@
#include "scene/3d/spatial_velocity_tracker.h"
#include "scene/main/viewport.h"
#include "scene/resources/environment.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
+
class Camera : public Spatial {
GDCLASS(Camera, Spatial);
diff --git a/scene/3d/collision_object.cpp b/scene/3d/collision_object.cpp
index 63301fc226..735b393171 100644
--- a/scene/3d/collision_object.cpp
+++ b/scene/3d/collision_object.cpp
@@ -105,7 +105,8 @@ void CollisionObject::_mouse_exit() {
void CollisionObject::_update_pickable() {
if (!is_inside_tree())
return;
- bool pickable = ray_pickable && is_inside_tree() && is_visible_in_tree();
+
+ bool pickable = ray_pickable && is_visible_in_tree();
if (area)
PhysicsServer::get_singleton()->area_set_ray_pickable(rid, pickable);
else
diff --git a/scene/3d/collision_polygon.cpp b/scene/3d/collision_polygon.cpp
index db07059b32..37aa95fb43 100644
--- a/scene/3d/collision_polygon.cpp
+++ b/scene/3d/collision_polygon.cpp
@@ -151,6 +151,8 @@ float CollisionPolygon::get_depth() const {
void CollisionPolygon::set_disabled(bool p_disabled) {
disabled = p_disabled;
+ update_gizmo();
+
if (parent) {
parent->shape_owner_set_disabled(owner_id, p_disabled);
}
diff --git a/scene/3d/cpu_particles.h b/scene/3d/cpu_particles.h
index 71de56f59e..66b37f359a 100644
--- a/scene/3d/cpu_particles.h
+++ b/scene/3d/cpu_particles.h
@@ -34,10 +34,6 @@
#include "core/rid.h"
#include "scene/3d/visual_instance.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-
class CPUParticles : public GeometryInstance {
private:
GDCLASS(CPUParticles, GeometryInstance);
diff --git a/scene/3d/light.h b/scene/3d/light.h
index 5d365758b5..cc8675ead1 100644
--- a/scene/3d/light.h
+++ b/scene/3d/light.h
@@ -35,10 +35,6 @@
#include "scene/resources/texture.h"
#include "servers/visual_server.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-
class Light : public VisualInstance {
GDCLASS(Light, VisualInstance);
diff --git a/scene/3d/mesh_instance.h b/scene/3d/mesh_instance.h
index 022ef15aad..8b690b0c21 100644
--- a/scene/3d/mesh_instance.h
+++ b/scene/3d/mesh_instance.h
@@ -34,9 +34,6 @@
#include "scene/3d/visual_instance.h"
#include "scene/resources/mesh.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
class MeshInstance : public GeometryInstance {
GDCLASS(MeshInstance, GeometryInstance);
diff --git a/scene/3d/multimesh_instance.h b/scene/3d/multimesh_instance.h
index 8f41aa8fd2..ca69c73251 100644
--- a/scene/3d/multimesh_instance.h
+++ b/scene/3d/multimesh_instance.h
@@ -34,10 +34,6 @@
#include "scene/3d/visual_instance.h"
#include "scene/resources/multimesh.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-
class MultiMeshInstance : public GeometryInstance {
GDCLASS(MultiMeshInstance, GeometryInstance);
diff --git a/scene/3d/particles.h b/scene/3d/particles.h
index 42c68010db..391491e8b8 100644
--- a/scene/3d/particles.h
+++ b/scene/3d/particles.h
@@ -35,10 +35,6 @@
#include "scene/3d/visual_instance.h"
#include "scene/resources/material.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-
class Particles : public GeometryInstance {
private:
GDCLASS(Particles, GeometryInstance);
diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp
index 19d5f1dd3c..0756be5fc8 100644
--- a/scene/3d/physics_body.cpp
+++ b/scene/3d/physics_body.cpp
@@ -1192,7 +1192,7 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve
//all is a wall
on_wall = true;
} else {
- if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //floor
+ if (Math::acos(collision.normal.dot(p_floor_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor
on_floor = true;
on_floor_body = collision.collider_rid;
@@ -1209,7 +1209,7 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve
is_on_slope = true;
- } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //ceiling
+ } else if (Math::acos(collision.normal.dot(-p_floor_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling
on_ceiling = true;
} else {
on_wall = true;
@@ -1387,6 +1387,18 @@ Ref<KinematicCollision> KinematicBody::_get_slide_collision(int p_bounce) {
return slide_colliders[p_bounce];
}
+void KinematicBody::_notification(int p_what) {
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+ // Reset move_and_slide() data.
+ on_floor = false;
+ on_floor_body = RID();
+ on_ceiling = false;
+ on_wall = false;
+ colliders.clear();
+ floor_velocity = Vector3();
+ }
+}
+
void KinematicBody::_bind_methods() {
ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only"), &KinematicBody::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false));
diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h
index aa6030d44e..0967cb9cd5 100644
--- a/scene/3d/physics_body.h
+++ b/scene/3d/physics_body.h
@@ -162,6 +162,7 @@ protected:
ShapePair(int p_bs, int p_ls) {
body_shape = p_bs;
local_shape = p_ls;
+ tagged = false;
}
};
struct RigidBody_RemoveAction {
@@ -314,6 +315,7 @@ private:
Ref<KinematicCollision> _get_slide_collision(int p_bounce);
protected:
+ void _notification(int p_what);
static void _bind_methods();
public:
diff --git a/scene/3d/portal.h b/scene/3d/portal.h
index f053867917..04af3a750c 100644
--- a/scene/3d/portal.h
+++ b/scene/3d/portal.h
@@ -32,9 +32,6 @@
#define PORTAL_H
#include "scene/3d/visual_instance.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
/* Portal Logic:
If a portal is placed next (very close to) a similar, opposing portal, they automatically connect,
diff --git a/scene/3d/ray_cast.cpp b/scene/3d/ray_cast.cpp
index 10f92058e0..30eed8f1a7 100644
--- a/scene/3d/ray_cast.cpp
+++ b/scene/3d/ray_cast.cpp
@@ -102,6 +102,8 @@ Vector3 RayCast::get_collision_normal() const {
void RayCast::set_enabled(bool p_enabled) {
enabled = p_enabled;
+ update_gizmo();
+
if (is_inside_tree() && !Engine::get_singleton()->is_editor_hint())
set_physics_process_internal(p_enabled);
if (!p_enabled)
diff --git a/scene/3d/room_instance.h b/scene/3d/room_instance.h
index 9ee140d522..01efde53c9 100644
--- a/scene/3d/room_instance.h
+++ b/scene/3d/room_instance.h
@@ -34,10 +34,6 @@
#include "scene/3d/visual_instance.h"
#include "scene/resources/room.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-
/* RoomInstance Logic:
a) Instances that belong to the room are drawn only if the room is visible (seen through portal, or player inside)
b) Instances that don't belong to any room are considered to belong to the root room (RID empty)
diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h
index 5f43b3c6c3..5b55dffbc8 100644
--- a/scene/3d/skeleton.h
+++ b/scene/3d/skeleton.h
@@ -34,10 +34,6 @@
#include "core/rid.h"
#include "scene/3d/spatial.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-
#ifndef _3D_DISABLED
typedef int BoneId;
diff --git a/scene/3d/spatial.h b/scene/3d/spatial.h
index 18a4a5b54d..eea2696767 100644
--- a/scene/3d/spatial.h
+++ b/scene/3d/spatial.h
@@ -34,10 +34,6 @@
#include "scene/main/node.h"
#include "scene/main/scene_tree.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-
class SpatialGizmo : public Reference {
GDCLASS(SpatialGizmo, Reference);
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index fc5523633d..a9dacc442c 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -286,6 +286,18 @@ SpriteBase3D::AlphaCutMode SpriteBase3D::get_alpha_cut_mode() const {
return alpha_cut;
}
+void SpriteBase3D::set_billboard_mode(SpatialMaterial::BillboardMode p_mode) {
+
+ ERR_FAIL_INDEX(p_mode, 3);
+ billboard_mode = p_mode;
+ _queue_update();
+}
+
+SpatialMaterial::BillboardMode SpriteBase3D::get_billboard_mode() const {
+
+ return billboard_mode;
+}
+
void SpriteBase3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_centered", "centered"), &SpriteBase3D::set_centered);
@@ -318,6 +330,9 @@ void SpriteBase3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_alpha_cut_mode", "mode"), &SpriteBase3D::set_alpha_cut_mode);
ClassDB::bind_method(D_METHOD("get_alpha_cut_mode"), &SpriteBase3D::get_alpha_cut_mode);
+ ClassDB::bind_method(D_METHOD("set_billboard_mode", "mode"), &SpriteBase3D::set_billboard_mode);
+ ClassDB::bind_method(D_METHOD("get_billboard_mode"), &SpriteBase3D::get_billboard_mode);
+
ClassDB::bind_method(D_METHOD("get_item_rect"), &SpriteBase3D::get_item_rect);
ClassDB::bind_method(D_METHOD("generate_triangle_mesh"), &SpriteBase3D::generate_triangle_mesh);
@@ -333,6 +348,7 @@ void SpriteBase3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "pixel_size", PROPERTY_HINT_RANGE, "0.0001,128,0.0001"), "set_pixel_size", "get_pixel_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "axis", PROPERTY_HINT_ENUM, "X-Axis,Y-Axis,Z-Axis"), "set_axis", "get_axis");
ADD_GROUP("Flags", "");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "billboard", PROPERTY_HINT_ENUM, "Disabled,Enabled,Y-Billboard"), "set_billboard_mode", "get_billboard_mode");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "transparent"), "set_draw_flag", "get_draw_flag", FLAG_TRANSPARENT);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "shaded"), "set_draw_flag", "get_draw_flag", FLAG_SHADED);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "double_sided"), "set_draw_flag", "get_draw_flag", FLAG_DOUBLE_SIDED);
@@ -361,6 +377,7 @@ SpriteBase3D::SpriteBase3D() {
flags[i] = i == FLAG_TRANSPARENT || i == FLAG_DOUBLE_SIDED;
alpha_cut = ALPHA_CUT_DISABLED;
+ billboard_mode = SpatialMaterial::BILLBOARD_DISABLED;
axis = Vector3::AXIS_Z;
pixel_size = 0.01;
modulate = Color(1, 1, 1, 1);
@@ -463,7 +480,7 @@ void Sprite3D::_draw() {
tangent = Plane(1, 0, 0, 1);
}
- RID mat = SpatialMaterial::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS);
+ RID mat = SpatialMaterial::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == SpatialMaterial::BILLBOARD_ENABLED, get_billboard_mode() == SpatialMaterial::BILLBOARD_FIXED_Y);
VS::get_singleton()->immediate_set_material(immediate, mat);
VS::get_singleton()->immediate_begin(immediate, VS::PRIMITIVE_TRIANGLE_FAN, texture->get_rid());
@@ -788,7 +805,7 @@ void AnimatedSprite3D::_draw() {
tangent = Plane(1, 0, 0, -1);
}
- RID mat = SpatialMaterial::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS);
+ RID mat = SpatialMaterial::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == SpatialMaterial::BILLBOARD_ENABLED, get_billboard_mode() == SpatialMaterial::BILLBOARD_FIXED_Y);
VS::get_singleton()->immediate_set_material(immediate, mat);
diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h
index 97a426b5b9..065931de84 100644
--- a/scene/3d/sprite_3d.h
+++ b/scene/3d/sprite_3d.h
@@ -80,6 +80,7 @@ private:
bool flags[FLAG_MAX];
AlphaCutMode alpha_cut;
+ SpatialMaterial::BillboardMode billboard_mode;
bool pending_update;
void _im_update();
@@ -130,6 +131,8 @@ public:
void set_alpha_cut_mode(AlphaCutMode p_mode);
AlphaCutMode get_alpha_cut_mode() const;
+ void set_billboard_mode(SpatialMaterial::BillboardMode p_mode);
+ SpatialMaterial::BillboardMode get_billboard_mode() const;
virtual Rect2 get_item_rect() const = 0;
diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h
index 3b924e0454..63d15680aa 100644
--- a/scene/3d/visual_instance.h
+++ b/scene/3d/visual_instance.h
@@ -35,9 +35,7 @@
#include "core/rid.h"
#include "scene/3d/spatial.h"
#include "scene/resources/material.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
+
class VisualInstance : public Spatial {
GDCLASS(VisualInstance, Spatial);
diff --git a/scene/3d/world_environment.h b/scene/3d/world_environment.h
index bf36a0a532..656e16371f 100644
--- a/scene/3d/world_environment.h
+++ b/scene/3d/world_environment.h
@@ -33,10 +33,6 @@
#include "scene/3d/spatial.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-
class WorldEnvironment : public Node {
GDCLASS(WorldEnvironment, Node);
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 30aeebfdac..051f832882 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -1200,7 +1200,9 @@ void AnimationPlayer::play(const StringName &p_name, float p_custom_blend, float
}
}
- _stop_playing_caches();
+ if (get_current_animation() != p_name) {
+ _stop_playing_caches();
+ }
c.current.from = &animation_set[name];
diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h
index f3d38110c6..320fd2084c 100644
--- a/scene/animation/animation_player.h
+++ b/scene/animation/animation_player.h
@@ -35,9 +35,6 @@
#include "scene/3d/skeleton.h"
#include "scene/3d/spatial.h"
#include "scene/resources/animation.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
#ifdef TOOLS_ENABLED
// To save/restore animated values
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 6745b57cff..bb7c400cfe 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -1412,6 +1412,7 @@ void AnimationTree::_update_properties_for_node(const String &p_base_path, Ref<A
Vector<Activity> activity;
for (int i = 0; i < node->get_input_count(); i++) {
Activity a;
+ a.activity = 0;
a.last_pass = 0;
activity.push_back(a);
}
diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h
index ffccdd69d6..2773f024df 100644
--- a/scene/gui/base_button.h
+++ b/scene/gui/base_button.h
@@ -32,9 +32,6 @@
#define BASE_BUTTON_H
#include "scene/gui/control.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
class ButtonGroup;
diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp
index 65e9cccd05..6b3e89af6c 100644
--- a/scene/gui/button.cpp
+++ b/scene/gui/button.cpp
@@ -39,158 +39,191 @@ Size2 Button::get_minimum_size() const {
if (clip_text)
minsize.width = 0;
- Ref<Texture> _icon;
- if (icon.is_null() && has_icon("icon"))
- _icon = Control::get_icon("icon");
- else
- _icon = icon;
-
- if (!_icon.is_null()) {
-
- minsize.height = MAX(minsize.height, _icon->get_height());
- minsize.width += _icon->get_width();
- if (xl_text != "")
- minsize.width += get_constant("hseparation");
+ if (!expand_icon) {
+ Ref<Texture> _icon;
+ if (icon.is_null() && has_icon("icon"))
+ _icon = Control::get_icon("icon");
+ else
+ _icon = icon;
+
+ if (!_icon.is_null()) {
+
+ minsize.height = MAX(minsize.height, _icon->get_height());
+ minsize.width += _icon->get_width();
+ if (xl_text != "")
+ minsize.width += get_constant("hseparation");
+ }
}
return get_stylebox("normal")->get_minimum_size() + minsize;
}
void Button::_set_internal_margin(Margin p_margin, float p_value) {
+
_internal_margin[p_margin] = p_value;
}
void Button::_notification(int p_what) {
- if (p_what == NOTIFICATION_TRANSLATION_CHANGED) {
+ switch (p_what) {
+ case NOTIFICATION_TRANSLATION_CHANGED: {
- xl_text = tr(text);
- minimum_size_changed();
- update();
- }
+ xl_text = tr(text);
+ minimum_size_changed();
+ update();
+ } break;
+ case NOTIFICATION_DRAW: {
- if (p_what == NOTIFICATION_DRAW) {
+ RID ci = get_canvas_item();
+ Size2 size = get_size();
+ Color color;
+ Color color_icon(1, 1, 1, 1);
- RID ci = get_canvas_item();
- Size2 size = get_size();
- Color color;
- Color color_icon(1, 1, 1, 1);
+ Ref<StyleBox> style = get_stylebox("normal");
- Ref<StyleBox> style = get_stylebox("normal");
+ switch (get_draw_mode()) {
+ case DRAW_NORMAL: {
- switch (get_draw_mode()) {
-
- case DRAW_NORMAL: {
+ style = get_stylebox("normal");
+ if (!flat)
+ style->draw(ci, Rect2(Point2(0, 0), size));
+ color = get_color("font_color");
+ if (has_color("icon_color_normal"))
+ color_icon = get_color("icon_color_normal");
+ } break;
+ case DRAW_HOVER_PRESSED: {
+
+ if (has_stylebox("hover_pressed") && has_stylebox_override("hover_pressed")) {
+ style = get_stylebox("hover_pressed");
+ if (!flat)
+ style->draw(ci, Rect2(Point2(0, 0), size));
+ if (has_color("font_color_hover_pressed"))
+ color = get_color("font_color_hover_pressed");
+ else
+ color = get_color("font_color");
+ if (has_color("icon_color_hover_pressed"))
+ color_icon = get_color("icon_color_hover_pressed");
+
+ break;
+ }
+ FALLTHROUGH;
+ }
+ case DRAW_PRESSED: {
- style = get_stylebox("normal");
- if (!flat)
- style->draw(ci, Rect2(Point2(0, 0), size));
- color = get_color("font_color");
- if (has_color("icon_color_normal"))
- color_icon = get_color("icon_color_normal");
- } break;
- case DRAW_HOVER_PRESSED: {
- if (has_stylebox("hover_pressed") && has_stylebox_override("hover_pressed")) {
- style = get_stylebox("hover_pressed");
+ style = get_stylebox("pressed");
if (!flat)
style->draw(ci, Rect2(Point2(0, 0), size));
- if (has_color("font_color_hover_pressed"))
- color = get_color("font_color_hover_pressed");
+ if (has_color("font_color_pressed"))
+ color = get_color("font_color_pressed");
else
color = get_color("font_color");
- if (has_color("icon_color_hover_pressed"))
- color_icon = get_color("icon_color_hover_pressed");
+ if (has_color("icon_color_pressed"))
+ color_icon = get_color("icon_color_pressed");
- break;
- }
- FALLTHROUGH;
+ } break;
+ case DRAW_HOVER: {
+
+ style = get_stylebox("hover");
+ if (!flat)
+ style->draw(ci, Rect2(Point2(0, 0), size));
+ color = get_color("font_color_hover");
+ if (has_color("icon_color_hover"))
+ color_icon = get_color("icon_color_hover");
+
+ } break;
+ case DRAW_DISABLED: {
+
+ style = get_stylebox("disabled");
+ if (!flat)
+ style->draw(ci, Rect2(Point2(0, 0), size));
+ color = get_color("font_color_disabled");
+ if (has_color("icon_color_disabled"))
+ color_icon = get_color("icon_color_disabled");
+
+ } break;
}
- case DRAW_PRESSED: {
-
- style = get_stylebox("pressed");
- if (!flat)
- style->draw(ci, Rect2(Point2(0, 0), size));
- if (has_color("font_color_pressed"))
- color = get_color("font_color_pressed");
- else
- color = get_color("font_color");
- if (has_color("icon_color_pressed"))
- color_icon = get_color("icon_color_pressed");
-
- } break;
- case DRAW_HOVER: {
-
- style = get_stylebox("hover");
- if (!flat)
- style->draw(ci, Rect2(Point2(0, 0), size));
- color = get_color("font_color_hover");
- if (has_color("icon_color_hover"))
- color_icon = get_color("icon_color_hover");
-
- } break;
- case DRAW_DISABLED: {
-
- style = get_stylebox("disabled");
- if (!flat)
- style->draw(ci, Rect2(Point2(0, 0), size));
- color = get_color("font_color_disabled");
- if (has_color("icon_color_disabled"))
- color_icon = get_color("icon_color_disabled");
-
- } break;
- }
- if (has_focus()) {
+ if (has_focus()) {
- Ref<StyleBox> style2 = get_stylebox("focus");
- style2->draw(ci, Rect2(Point2(), size));
- }
+ Ref<StyleBox> style2 = get_stylebox("focus");
+ style2->draw(ci, Rect2(Point2(), size));
+ }
- Ref<Font> font = get_font("font");
- Ref<Texture> _icon;
- if (icon.is_null() && has_icon("icon"))
- _icon = Control::get_icon("icon");
- else
- _icon = icon;
+ Ref<Font> font = get_font("font");
+ Ref<Texture> _icon;
+ if (icon.is_null() && has_icon("icon"))
+ _icon = Control::get_icon("icon");
+ else
+ _icon = icon;
+
+ Rect2 icon_region = Rect2();
+ if (!_icon.is_null()) {
- Point2 icon_ofs = (!_icon.is_null()) ? Point2(_icon->get_width() + get_constant("hseparation"), 0) : Point2();
- int text_clip = size.width - style->get_minimum_size().width - icon_ofs.width;
- Point2 text_ofs = (size - style->get_minimum_size() - icon_ofs - font->get_string_size(xl_text) - Point2(_internal_margin[MARGIN_RIGHT] - _internal_margin[MARGIN_LEFT], 0)) / 2.0;
-
- switch (align) {
- case ALIGN_LEFT: {
- text_ofs.x = style->get_margin(MARGIN_LEFT) + icon_ofs.x + _internal_margin[MARGIN_LEFT] + get_constant("hseparation");
- text_ofs.y += style->get_offset().y;
- } break;
- case ALIGN_CENTER: {
- if (text_ofs.x < 0)
- text_ofs.x = 0;
- text_ofs += icon_ofs;
- text_ofs += style->get_offset();
- } break;
- case ALIGN_RIGHT: {
- if (_internal_margin[MARGIN_RIGHT] > 0) {
- text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - font->get_string_size(xl_text).x - _internal_margin[MARGIN_RIGHT] - get_constant("hseparation");
+ int valign = size.height - style->get_minimum_size().y;
+ if (is_disabled()) {
+ color_icon.a = 0.4;
+ }
+
+ float icon_ofs_region = 0;
+ if (_internal_margin[MARGIN_LEFT] > 0) {
+ icon_ofs_region = _internal_margin[MARGIN_LEFT] + get_constant("hseparation");
+ }
+
+ if (expand_icon) {
+ Size2 _size = get_size() - style->get_offset() * 2;
+ _size.width -= get_constant("hseparation") + icon_ofs_region;
+ if (!clip_text)
+ _size.width -= get_font("font")->get_string_size(xl_text).width;
+ float icon_width = icon->get_width() * _size.height / icon->get_height();
+ float icon_height = _size.height;
+
+ if (icon_width > _size.width) {
+ icon_width = _size.width;
+ icon_height = icon->get_height() * icon_width / icon->get_width();
+ }
+
+ icon_region = Rect2(style->get_offset() + Point2(icon_ofs_region, (_size.height - icon_height) / 2), Size2(icon_width, icon_height));
} else {
- text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - font->get_string_size(xl_text).x;
+ icon_region = Rect2(style->get_offset() + Point2(icon_ofs_region, Math::floor((valign - _icon->get_height()) / 2.0)), icon->get_size());
}
- text_ofs.y += style->get_offset().y;
- } break;
- }
+ }
- text_ofs.y += font->get_ascent();
- font->draw(ci, text_ofs.floor(), xl_text, color, clip_text ? text_clip : -1);
- if (!_icon.is_null()) {
+ Point2 icon_ofs = !_icon.is_null() ? Point2(icon_region.size.width + get_constant("hseparation"), 0) : Point2();
+ int text_clip = size.width - style->get_minimum_size().width - icon_ofs.width;
+ Point2 text_ofs = (size - style->get_minimum_size() - icon_ofs - font->get_string_size(xl_text) - Point2(_internal_margin[MARGIN_RIGHT] - _internal_margin[MARGIN_LEFT], 0)) / 2.0;
+
+ switch (align) {
+ case ALIGN_LEFT: {
+ if (_internal_margin[MARGIN_LEFT] > 0) {
+ text_ofs.x = style->get_margin(MARGIN_LEFT) + icon_ofs.x + _internal_margin[MARGIN_LEFT] + get_constant("hseparation");
+ } else {
+ text_ofs.x = style->get_margin(MARGIN_LEFT) + icon_ofs.x;
+ }
+ text_ofs.y += style->get_offset().y;
+ } break;
+ case ALIGN_CENTER: {
+ if (text_ofs.x < 0)
+ text_ofs.x = 0;
+ text_ofs += icon_ofs;
+ text_ofs += style->get_offset();
+ } break;
+ case ALIGN_RIGHT: {
+ if (_internal_margin[MARGIN_RIGHT] > 0) {
+ text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - font->get_string_size(xl_text).x - _internal_margin[MARGIN_RIGHT] - get_constant("hseparation");
+ } else {
+ text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - font->get_string_size(xl_text).x;
+ }
+ text_ofs.y += style->get_offset().y;
+ } break;
+ }
+
+ text_ofs.y += font->get_ascent();
+ font->draw(ci, text_ofs.floor(), xl_text, color, clip_text ? text_clip : -1);
- int valign = size.height - style->get_minimum_size().y;
- if (is_disabled())
- color_icon.a = 0.4;
- if (_internal_margin[MARGIN_LEFT] > 0) {
- _icon->draw(ci, style->get_offset() + Point2(_internal_margin[MARGIN_LEFT] + get_constant("hseparation"), Math::floor((valign - _icon->get_height()) / 2.0)), color_icon);
- } else {
- _icon->draw(ci, style->get_offset() + Point2(0, Math::floor((valign - _icon->get_height()) / 2.0)), color_icon);
+ if (!_icon.is_null() && icon_region.size.width > 0) {
+ draw_texture_rect_region(_icon, icon_region, Rect2(Point2(), icon->get_size()), color_icon);
}
- }
+ } break;
}
}
@@ -224,6 +257,18 @@ Ref<Texture> Button::get_icon() const {
return icon;
}
+void Button::set_expand_icon(bool p_expand_icon) {
+
+ expand_icon = p_expand_icon;
+ update();
+ minimum_size_changed();
+}
+
+bool Button::is_expand_icon() const {
+
+ return expand_icon;
+}
+
void Button::set_flat(bool p_flat) {
flat = p_flat;
@@ -265,6 +310,8 @@ void Button::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_text"), &Button::get_text);
ClassDB::bind_method(D_METHOD("set_button_icon", "texture"), &Button::set_icon);
ClassDB::bind_method(D_METHOD("get_button_icon"), &Button::get_icon);
+ ClassDB::bind_method(D_METHOD("set_expand_icon"), &Button::set_expand_icon);
+ ClassDB::bind_method(D_METHOD("is_expand_icon"), &Button::is_expand_icon);
ClassDB::bind_method(D_METHOD("set_flat", "enabled"), &Button::set_flat);
ClassDB::bind_method(D_METHOD("set_clip_text", "enabled"), &Button::set_clip_text);
ClassDB::bind_method(D_METHOD("get_clip_text"), &Button::get_clip_text);
@@ -281,12 +328,14 @@ void Button::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_text"), "set_clip_text", "get_clip_text");
ADD_PROPERTY(PropertyInfo(Variant::INT, "align", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_text_align", "get_text_align");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand_icon"), "set_expand_icon", "is_expand_icon");
}
Button::Button(const String &p_text) {
flat = false;
clip_text = false;
+ expand_icon = false;
set_mouse_filter(MOUSE_FILTER_STOP);
set_text(p_text);
align = ALIGN_CENTER;
diff --git a/scene/gui/button.h b/scene/gui/button.h
index 6ba3475e5a..1fff2cfda7 100644
--- a/scene/gui/button.h
+++ b/scene/gui/button.h
@@ -32,9 +32,6 @@
#define BUTTON_H
#include "scene/gui/base_button.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
class Button : public BaseButton {
@@ -52,6 +49,7 @@ private:
String text;
String xl_text;
Ref<Texture> icon;
+ bool expand_icon;
bool clip_text;
TextAlign align;
float _internal_margin[4];
@@ -62,8 +60,6 @@ protected:
static void _bind_methods();
public:
- //
-
virtual Size2 get_minimum_size() const;
void set_text(const String &p_text);
@@ -72,6 +68,9 @@ public:
void set_icon(const Ref<Texture> &p_icon);
Ref<Texture> get_icon() const;
+ void set_expand_icon(bool p_expand_icon);
+ bool is_expand_icon() const;
+
void set_flat(bool p_flat);
bool is_flat() const;
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index b197971b61..6dd9e401f6 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -247,15 +247,19 @@ void ColorPicker::_update_color(bool p_update_sliders) {
}
void ColorPicker::_update_presets() {
+ presets_per_row = 10;
Size2 size = bt_add_preset->get_size();
- Size2 preset_size = Size2(size.width * presets.size(), size.height);
+ Size2 preset_size = Size2(MIN(size.width * presets.size(), presets_per_row * size.width), size.height * (Math::ceil((float)presets.size() / presets_per_row)));
preset->set_custom_minimum_size(preset_size);
-
- preset->draw_texture_rect(get_icon("preset_bg", "ColorPicker"), Rect2(Point2(), preset_size), true);
+ preset_container->set_custom_minimum_size(preset_size);
+ preset->draw_rect(Rect2(Point2(), preset_size), Color(1, 1, 1, 0));
for (int i = 0; i < presets.size(); i++) {
- preset->draw_rect(Rect2(Point2(size.width * i, 0), size), presets[i]);
+ int x = (i % presets_per_row) * size.width;
+ int y = (Math::floor((float)i / presets_per_row)) * size.height;
+ preset->draw_rect(Rect2(Point2(x, y), size), presets[i]);
}
+ _notification(NOTIFICATION_VISIBILITY_CHANGED);
}
void ColorPicker::_text_type_toggled() {
@@ -288,8 +292,6 @@ void ColorPicker::add_preset(const Color &p_color) {
presets.push_back(p_color);
}
preset->update();
- if (presets.size() == 10)
- bt_add_preset->hide();
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
@@ -533,14 +535,20 @@ void ColorPicker::_preset_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> bev = p_event;
if (bev.is_valid()) {
-
+ int index = 0;
if (bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) {
- int index = bev->get_position().x / (preset->get_size().x / presets.size());
+ for (int i = 0; i < presets.size(); i++) {
+ int x = (i % presets_per_row) * bt_add_preset->get_size().x;
+ int y = (Math::floor((float)i / presets_per_row)) * bt_add_preset->get_size().y;
+ if (bev->get_position().x > x && bev->get_position().x < x + preset->get_size().x && bev->get_position().y > y && bev->get_position().y < y + preset->get_size().y) {
+ index = i;
+ }
+ }
set_pick_color(presets[index]);
_update_color();
emit_signal("color_changed", color);
} else if (bev->is_pressed() && bev->get_button_index() == BUTTON_RIGHT && presets_enabled) {
- int index = bev->get_position().x / (preset->get_size().x / presets.size());
+ index = bev->get_position().x / (preset->get_size().x / presets.size());
Color clicked_preset = presets[index];
erase_preset(clicked_preset);
emit_signal("preset_removed", clicked_preset);
@@ -841,6 +849,7 @@ ColorPicker::ColorPicker() :
add_child(preset_separator);
preset_container = memnew(HBoxContainer);
+ preset_container->set_h_size_flags(SIZE_EXPAND_FILL);
add_child(preset_container);
preset = memnew(TextureRect);
@@ -848,8 +857,11 @@ ColorPicker::ColorPicker() :
preset->connect("gui_input", this, "_preset_input");
preset->connect("draw", this, "_update_presets");
+ preset_container2 = memnew(HBoxContainer);
+ preset_container2->set_h_size_flags(SIZE_EXPAND_FILL);
+ add_child(preset_container2);
bt_add_preset = memnew(Button);
- preset_container->add_child(bt_add_preset);
+ preset_container2->add_child(bt_add_preset);
bt_add_preset->set_tooltip(TTR("Add current color as a preset."));
bt_add_preset->connect("pressed", this, "_add_preset_pressed");
}
@@ -952,6 +964,7 @@ void ColorPickerButton::_update_picker() {
popup->connect("popup_hide", this, "set_pressed", varray(false));
picker->set_pick_color(color);
picker->set_edit_alpha(edit_alpha);
+ emit_signal("picker_created");
}
}
@@ -968,6 +981,7 @@ void ColorPickerButton::_bind_methods() {
ADD_SIGNAL(MethodInfo("color_changed", PropertyInfo(Variant::COLOR, "color")));
ADD_SIGNAL(MethodInfo("popup_closed"));
+ ADD_SIGNAL(MethodInfo("picker_created"));
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_pick_color", "get_pick_color");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_alpha"), "set_edit_alpha", "is_editing_alpha");
}
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index 3af27a9856..167f7b33b3 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -54,6 +54,7 @@ private:
TextureRect *sample;
TextureRect *preset;
HBoxContainer *preset_container;
+ HBoxContainer *preset_container2;
HSeparator *preset_separator;
Button *bt_add_preset;
List<Color> presets;
@@ -68,6 +69,7 @@ private:
bool edit_alpha;
Size2i ms;
bool text_is_constructor;
+ int presets_per_row;
Color color;
bool raw_mode_enabled;
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 9b9fc863dd..034e9266f6 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -2918,17 +2918,21 @@ void Control::_bind_methods() {
BIND_VMETHOD(MethodInfo("_gui_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
BIND_VMETHOD(MethodInfo(Variant::VECTOR2, "_get_minimum_size"));
- BIND_VMETHOD(MethodInfo(Variant::OBJECT, "get_drag_data", PropertyInfo(Variant::VECTOR2, "position")));
+
+ MethodInfo get_drag_data = MethodInfo("get_drag_data", PropertyInfo(Variant::VECTOR2, "position"));
+ get_drag_data.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+ BIND_VMETHOD(get_drag_data);
+
BIND_VMETHOD(MethodInfo(Variant::BOOL, "can_drop_data", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::NIL, "data")));
BIND_VMETHOD(MethodInfo("drop_data", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::NIL, "data")));
BIND_VMETHOD(MethodInfo(Variant::OBJECT, "_make_custom_tooltip", PropertyInfo(Variant::STRING, "for_text")));
BIND_VMETHOD(MethodInfo(Variant::BOOL, "_clips_input"));
ADD_GROUP("Anchor", "anchor_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_left", PROPERTY_HINT_RANGE, "0,1,0.01,or_lesser,or_greater"), "_set_anchor", "get_anchor", MARGIN_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_top", PROPERTY_HINT_RANGE, "0,1,0.01,or_lesser,or_greater"), "_set_anchor", "get_anchor", MARGIN_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_right", PROPERTY_HINT_RANGE, "0,1,0.01,or_lesser,or_greater"), "_set_anchor", "get_anchor", MARGIN_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_bottom", PROPERTY_HINT_RANGE, "0,1,0.01,or_lesser,or_greater"), "_set_anchor", "get_anchor", MARGIN_BOTTOM);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_left", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", MARGIN_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_top", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", MARGIN_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_right", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", MARGIN_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_bottom", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", MARGIN_BOTTOM);
ADD_GROUP("Margin", "margin_");
ADD_PROPERTYI(PropertyInfo(Variant::INT, "margin_left", PROPERTY_HINT_RANGE, "-4096,4096"), "set_margin", "get_margin", MARGIN_LEFT);
diff --git a/scene/gui/control.h b/scene/gui/control.h
index eae889a667..7305b3ce93 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -38,9 +38,6 @@
#include "scene/main/node.h"
#include "scene/main/timer.h"
#include "scene/resources/theme.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
class Viewport;
class Label;
diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h
index c1a7f26a85..1a0350ba18 100644
--- a/scene/gui/dialogs.h
+++ b/scene/gui/dialogs.h
@@ -37,9 +37,6 @@
#include "scene/gui/panel.h"
#include "scene/gui/popup.h"
#include "scene/gui/texture_button.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
class WindowDialog : public Popup {
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index f1bdbb5ff5..9bc593ea3b 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -400,6 +400,7 @@ void FileDialog::update_file_list() {
TreeItem *root = tree->create_item();
Ref<Texture> folder = get_icon("folder");
+ const Color folder_color = get_color("folder_icon_modulate");
List<String> files;
List<String> dirs;
@@ -429,6 +430,7 @@ void FileDialog::update_file_list() {
TreeItem *ti = tree->create_item(root);
ti->set_text(0, dir_name);
ti->set_icon(0, folder);
+ ti->set_icon_modulate(0, folder_color);
Dictionary d;
d["name"] = dir_name;
diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h
index 191af5fef3..4fd6d0d13c 100644
--- a/scene/gui/file_dialog.h
+++ b/scene/gui/file_dialog.h
@@ -38,9 +38,7 @@
#include "scene/gui/option_button.h"
#include "scene/gui/tool_button.h"
#include "scene/gui/tree.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
+
class FileDialog : public ConfirmationDialog {
GDCLASS(FileDialog, ConfirmationDialog);
diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp
index 75f5f79873..09ef6f26bf 100644
--- a/scene/gui/gradient_edit.cpp
+++ b/scene/gui/gradient_edit.cpp
@@ -241,9 +241,13 @@ void GradientEdit::_gui_input(const Ref<InputEvent> &p_event) {
float newofs = CLAMP(x / float(total_w), 0, 1);
- //Snap to nearest point if holding shift
- if (mm->get_shift()) {
- float snap_threshold = 0.03;
+ // Snap to "round" coordinates if holding Ctrl.
+ // Be more precise if holding Shift as well
+ if (mm->get_control()) {
+ newofs = Math::stepify(newofs, mm->get_shift() ? 0.025 : 0.1);
+ } else if (mm->get_shift()) {
+ // Snap to nearest point if holding just Shift
+ const float snap_threshold = 0.03;
float smallest_ofs = snap_threshold;
bool found = false;
int nearest_point = 0;
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 38005f1322..7827c66841 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -276,6 +276,11 @@ void GraphEdit::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
port_grab_distance_horizontal = get_constant("port_grab_distance_horizontal");
port_grab_distance_vertical = get_constant("port_grab_distance_vertical");
+
+ zoom_minus->set_icon(get_icon("minus"));
+ zoom_reset->set_icon(get_icon("reset"));
+ zoom_plus->set_icon(get_icon("more"));
+ snap_button->set_icon(get_icon("snap"));
}
if (p_what == NOTIFICATION_READY) {
Size2 hmin = h_scroll->get_combined_minimum_size();
@@ -290,11 +295,6 @@ void GraphEdit::_notification(int p_what) {
h_scroll->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 0);
h_scroll->set_anchor_and_margin(MARGIN_TOP, ANCHOR_END, -hmin.height);
h_scroll->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, 0);
-
- zoom_minus->set_icon(get_icon("minus"));
- zoom_reset->set_icon(get_icon("reset"));
- zoom_plus->set_icon(get_icon("more"));
- snap_button->set_icon(get_icon("snap"));
}
if (p_what == NOTIFICATION_DRAW) {
@@ -776,10 +776,16 @@ void GraphEdit::_top_layer_draw() {
_draw_cos_line(top_layer, pos, topos, col, col);
}
- if (box_selecting)
+ if (box_selecting) {
top_layer->draw_rect(
box_selecting_rect,
- get_color("accent_color", "Editor") * Color(1, 1, 1, 0.375));
+ get_color("box_selection_fill_color", "Editor"));
+
+ top_layer->draw_rect(
+ box_selecting_rect,
+ get_color("box_selection_stroke_color", "Editor"),
+ false);
+ }
}
void GraphEdit::set_selected(Node *p_child) {
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index f7bef4ed39..5b2f8812d5 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -210,6 +210,7 @@ void GraphNode::_notification(int p_what) {
int close_offset = get_constant("close_offset");
int close_h_offset = get_constant("close_h_offset");
Color close_color = get_color("close_color");
+ Color resizer_color = get_color("resizer_color");
Ref<Font> title_font = get_font("title_font");
int title_offset = get_constant("title_offset");
int title_h_offset = get_constant("title_h_offset");
@@ -274,7 +275,7 @@ void GraphNode::_notification(int p_what) {
}
if (resizable) {
- draw_texture(resizer, get_size() - resizer->get_size());
+ draw_texture(resizer, get_size() - resizer->get_size(), resizer_color);
}
} break;
diff --git a/scene/gui/label.h b/scene/gui/label.h
index 561c42ef9e..2cc55a47ef 100644
--- a/scene/gui/label.h
+++ b/scene/gui/label.h
@@ -32,9 +32,7 @@
#define LABEL_H
#include "scene/gui/control.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
+
class Label : public Control {
GDCLASS(Label, Control);
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 60a74066a4..4a763844f8 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -1368,18 +1368,28 @@ void LineEdit::set_editable(bool p_editable) {
// Reorganize context menu.
menu->clear();
- if (editable)
+
+ if (editable) {
+ menu->add_item(RTR("Undo"), MENU_UNDO, KEY_MASK_CMD | KEY_Z);
+ menu->add_item(RTR("Redo"), MENU_REDO, KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z);
+ }
+
+ if (editable) {
+ menu->add_separator();
menu->add_item(RTR("Cut"), MENU_CUT, KEY_MASK_CMD | KEY_X);
+ }
+
menu->add_item(RTR("Copy"), MENU_COPY, KEY_MASK_CMD | KEY_C);
- if (editable)
+
+ if (editable) {
menu->add_item(RTR("Paste"), MENU_PASTE, KEY_MASK_CMD | KEY_V);
+ }
+
menu->add_separator();
menu->add_item(RTR("Select All"), MENU_SELECT_ALL, KEY_MASK_CMD | KEY_A);
+
if (editable) {
menu->add_item(RTR("Clear"), MENU_CLEAR);
- menu->add_separator();
- menu->add_item(RTR("Undo"), MENU_UNDO, KEY_MASK_CMD | KEY_Z);
- menu->add_item(RTR("Redo"), MENU_REDO, KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z);
}
update();
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index 3002f6f637..1d33f7d4ce 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -34,9 +34,6 @@
#include "scene/gui/control.h"
#include "scene/gui/popup_menu.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
class LineEdit : public Control {
GDCLASS(LineEdit, Control);
diff --git a/scene/gui/menu_button.h b/scene/gui/menu_button.h
index 42e909d991..5448ff13f2 100644
--- a/scene/gui/menu_button.h
+++ b/scene/gui/menu_button.h
@@ -33,9 +33,7 @@
#include "scene/gui/button.h"
#include "scene/gui/popup_menu.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
+
class MenuButton : public Button {
GDCLASS(MenuButton, Button);
diff --git a/scene/gui/nine_patch_rect.h b/scene/gui/nine_patch_rect.h
index ac17e52fc1..f31a09a482 100644
--- a/scene/gui/nine_patch_rect.h
+++ b/scene/gui/nine_patch_rect.h
@@ -32,9 +32,7 @@
#define NINE_PATCH_RECT_H
#include "scene/gui/control.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
+
class NinePatchRect : public Control {
GDCLASS(NinePatchRect, Control);
diff --git a/scene/gui/option_button.h b/scene/gui/option_button.h
index 51d5fd6947..7210708042 100644
--- a/scene/gui/option_button.h
+++ b/scene/gui/option_button.h
@@ -33,9 +33,7 @@
#include "scene/gui/button.h"
#include "scene/gui/popup_menu.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
+
class OptionButton : public Button {
GDCLASS(OptionButton, Button);
diff --git a/scene/gui/panel.h b/scene/gui/panel.h
index f8d15e4261..84bf6e75f5 100644
--- a/scene/gui/panel.h
+++ b/scene/gui/panel.h
@@ -32,9 +32,7 @@
#define PANEL_H
#include "scene/gui/control.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
+
class Panel : public Control {
GDCLASS(Panel, Control);
diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp
index 3e003af396..32380b6457 100644
--- a/scene/gui/popup.cpp
+++ b/scene/gui/popup.cpp
@@ -74,7 +74,7 @@ void Popup::_fix_size() {
Point2 pos = get_global_position();
Size2 size = get_size() * get_scale();
- Point2 window_size = get_viewport_rect().size;
+ Point2 window_size = get_viewport_rect().size - get_viewport_transform().get_origin();
if (pos.x + size.width > window_size.width)
pos.x = window_size.width - size.width;
@@ -207,6 +207,7 @@ bool Popup::is_exclusive() const {
void Popup::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_as_minsize"), &Popup::set_as_minsize);
ClassDB::bind_method(D_METHOD("popup_centered", "size"), &Popup::popup_centered, DEFVAL(Size2()));
ClassDB::bind_method(D_METHOD("popup_centered_ratio", "ratio"), &Popup::popup_centered_ratio, DEFVAL(0.75));
ClassDB::bind_method(D_METHOD("popup_centered_minsize", "minsize"), &Popup::popup_centered_minsize, DEFVAL(Size2()));
diff --git a/scene/gui/popup.h b/scene/gui/popup.h
index d6d96dfe64..925760984e 100644
--- a/scene/gui/popup.h
+++ b/scene/gui/popup.h
@@ -33,9 +33,6 @@
#include "scene/gui/control.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
class Popup : public Control {
GDCLASS(Popup, Control);
diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h
index babdd21281..8bfe8fc607 100644
--- a/scene/gui/popup_menu.h
+++ b/scene/gui/popup_menu.h
@@ -33,10 +33,6 @@
#include "scene/gui/popup.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-
class PopupMenu : public Popup {
GDCLASS(PopupMenu, Popup);
diff --git a/scene/gui/range.h b/scene/gui/range.h
index cf0add8c89..8ce450f8fc 100644
--- a/scene/gui/range.h
+++ b/scene/gui/range.h
@@ -32,9 +32,7 @@
#define RANGE_H
#include "scene/gui/control.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
+
class Range : public Control {
GDCLASS(Range, Control);
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 8223ea6d1e..1aed858c94 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -916,9 +916,12 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item
Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const {
- if (!underline_meta || selection.click)
+ if (!underline_meta)
return CURSOR_ARROW;
+ if (selection.click)
+ return CURSOR_IBEAM;
+
if (main->first_invalid_line < main->lines.size())
return CURSOR_ARROW; //invalid
diff --git a/scene/gui/scroll_bar.h b/scene/gui/scroll_bar.h
index 5ceabfc06b..cbcee1dae3 100644
--- a/scene/gui/scroll_bar.h
+++ b/scene/gui/scroll_bar.h
@@ -33,10 +33,6 @@
#include "scene/gui/range.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-
class ScrollBar : public Range {
GDCLASS(ScrollBar, Range);
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index 461281a4ed..a840e3fec1 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -382,7 +382,10 @@ void ScrollContainer::update_scrollbars() {
Size2 min = child_max_size;
- if (!scroll_v || min.height <= size.height - hmin.height) {
+ bool hide_scroll_v = !scroll_v || min.height <= size.height - hmin.height;
+ bool hide_scroll_h = !scroll_h || min.width <= size.width - vmin.width;
+
+ if (hide_scroll_v) {
v_scroll->hide();
v_scroll->set_max(0);
@@ -391,11 +394,16 @@ void ScrollContainer::update_scrollbars() {
v_scroll->show();
v_scroll->set_max(min.height);
- v_scroll->set_page(size.height - hmin.height);
+ if (hide_scroll_h) {
+ v_scroll->set_page(size.height);
+ } else {
+ v_scroll->set_page(size.height - hmin.height);
+ }
+
scroll.y = v_scroll->get_value();
}
- if (!scroll_h || min.width <= size.width - vmin.width) {
+ if (hide_scroll_h) {
h_scroll->hide();
h_scroll->set_max(0);
@@ -404,7 +412,12 @@ void ScrollContainer::update_scrollbars() {
h_scroll->show();
h_scroll->set_max(min.width);
- h_scroll->set_page(size.width - vmin.width);
+ if (hide_scroll_v) {
+ h_scroll->set_page(size.width);
+ } else {
+ h_scroll->set_page(size.width - vmin.width);
+ }
+
scroll.x = h_scroll->get_value();
}
}
diff --git a/scene/gui/separator.h b/scene/gui/separator.h
index 54ad9b5bb5..89039f3112 100644
--- a/scene/gui/separator.h
+++ b/scene/gui/separator.h
@@ -31,10 +31,6 @@
#ifndef SEPARATOR_H
#define SEPARATOR_H
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-
#include "scene/gui/control.h"
class Separator : public Control {
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index db277d3705..172c366c41 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "spin_box.h"
+#include "core/math/expression.h"
#include "core/os/input.h"
Size2 SpinBox::get_minimum_size() const {
@@ -50,15 +51,19 @@ void SpinBox::_value_changed(double) {
void SpinBox::_text_entered(const String &p_string) {
- /*
- if (!p_string.is_numeric())
+ Ref<Expression> expr;
+ expr.instance();
+ // Ignore the prefix and suffix in the expression
+ Error err = expr->parse(p_string.trim_prefix(prefix + " ").trim_suffix(" " + suffix));
+ if (err != OK) {
return;
- */
- String value = p_string;
- if (prefix != "" && p_string.begins_with(prefix))
- value = p_string.substr(prefix.length(), p_string.length() - prefix.length());
- set_value(value.to_double());
- _value_changed(0);
+ }
+
+ Variant value = expr->execute(Array(), NULL, false);
+ if (value.get_type() != Variant::NIL) {
+ set_value(value);
+ _value_changed(0);
+ }
}
LineEdit *SpinBox::get_line_edit() {
@@ -170,6 +175,10 @@ void SpinBox::_gui_input(const Ref<InputEvent> &p_event) {
void SpinBox::_line_edit_focus_exit() {
+ // discontinue because the focus_exit was caused by right-click context menu
+ if (line_edit->get_menu()->is_visible())
+ return;
+
_text_entered(line_edit->get_text());
}
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index be8f1cf36e..292d80be9d 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -840,7 +840,7 @@ Size2 TabContainer::get_minimum_size() const {
Control *c = tabs[i];
- if (!c->is_visible_in_tree())
+ if (!c->is_visible_in_tree() && !use_hidden_tabs_for_min_size)
continue;
Size2 cms = c->get_combined_minimum_size();
@@ -887,6 +887,13 @@ int TabContainer::get_tabs_rearrange_group() const {
return tabs_rearrange_group;
}
+void TabContainer::set_use_hidden_tabs_for_min_size(bool p_use_hidden_tabs) {
+ use_hidden_tabs_for_min_size = p_use_hidden_tabs;
+}
+
+bool TabContainer::get_use_hidden_tabs_for_min_size() const {
+ return use_hidden_tabs_for_min_size;
+}
void TabContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("_gui_input"), &TabContainer::_gui_input);
@@ -913,6 +920,9 @@ void TabContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_tabs_rearrange_group", "group_id"), &TabContainer::set_tabs_rearrange_group);
ClassDB::bind_method(D_METHOD("get_tabs_rearrange_group"), &TabContainer::get_tabs_rearrange_group);
+ ClassDB::bind_method(D_METHOD("set_use_hidden_tabs_for_min_size", "enabled"), &TabContainer::set_use_hidden_tabs_for_min_size);
+ ClassDB::bind_method(D_METHOD("get_use_hidden_tabs_for_min_size"), &TabContainer::get_use_hidden_tabs_for_min_size);
+
ClassDB::bind_method(D_METHOD("_child_renamed_callback"), &TabContainer::_child_renamed_callback);
ClassDB::bind_method(D_METHOD("_on_theme_changed"), &TabContainer::_on_theme_changed);
ClassDB::bind_method(D_METHOD("_update_current_tab"), &TabContainer::_update_current_tab);
@@ -925,6 +935,7 @@ void TabContainer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE, "-1,4096,1", PROPERTY_USAGE_EDITOR), "set_current_tab", "get_current_tab");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tabs_visible"), "set_tabs_visible", "are_tabs_visible");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_to_rearrange_enabled"), "set_drag_to_rearrange_enabled", "get_drag_to_rearrange_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hidden_tabs_for_min_size"), "set_use_hidden_tabs_for_min_size", "get_use_hidden_tabs_for_min_size");
BIND_ENUM_CONSTANT(ALIGN_LEFT);
BIND_ENUM_CONSTANT(ALIGN_CENTER);
@@ -945,4 +956,5 @@ TabContainer::TabContainer() {
popup = NULL;
drag_to_rearrange_enabled = false;
tabs_rearrange_group = -1;
+ use_hidden_tabs_for_min_size = false;
}
diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h
index f7a9fb64fd..0314f86837 100644
--- a/scene/gui/tab_container.h
+++ b/scene/gui/tab_container.h
@@ -59,6 +59,7 @@ private:
int _get_top_margin() const;
Popup *popup;
bool drag_to_rearrange_enabled;
+ bool use_hidden_tabs_for_min_size;
int tabs_rearrange_group;
Vector<Control *> _get_tabs() const;
@@ -118,6 +119,8 @@ public:
bool get_drag_to_rearrange_enabled() const;
void set_tabs_rearrange_group(int p_group_id);
int get_tabs_rearrange_group() const;
+ void set_use_hidden_tabs_for_min_size(bool p_use_hidden_tabs);
+ bool get_use_hidden_tabs_for_min_size() const;
TabContainer();
};
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index ff0c723141..0464cc1ac8 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -129,7 +129,7 @@ void TextEdit::Text::_update_line_cache(int p_line) const {
int len = text[p_line].data.length();
const CharType *str = text[p_line].data.c_str();
- //update width
+ // Update width.
for (int i = 0; i < len; i++) {
w += get_char_width(str[i], str[i + 1], w);
@@ -139,7 +139,7 @@ void TextEdit::Text::_update_line_cache(int p_line) const {
text.write[p_line].wrap_amount_cache = -1;
- //update regions
+ // Update regions.
text.write[p_line].region_info.clear();
@@ -148,7 +148,7 @@ void TextEdit::Text::_update_line_cache(int p_line) const {
if (!_is_symbol(str[i]))
continue;
if (str[i] == '\\') {
- i++; //skip quoted anything
+ i++; // Skip quoted anything.
continue;
}
@@ -275,7 +275,7 @@ void TextEdit::Text::clear() {
}
int TextEdit::Text::get_max_width(bool p_exclude_hidden) const {
- //quite some work.. but should be fast enough.
+ // Quite some work, but should be fast enough.
int max = 0;
for (int i = 0; i < text.size(); i++) {
@@ -323,7 +323,7 @@ int TextEdit::Text::get_char_width(CharType c, CharType next_c, int px) const {
if (left == 0)
w = tab_w;
else
- w = tab_w - px % tab_w; // is right...
+ w = tab_w - px % tab_w; // Is right.
} else {
w = font->get_char_size(c, next_c).width;
@@ -367,23 +367,25 @@ void TextEdit::_update_scrollbars() {
total_width += cache.fold_gutter_width;
}
+ if (draw_minimap) {
+ total_width += cache.minimap_width;
+ }
+
bool use_hscroll = true;
bool use_vscroll = true;
+ // Thanks yessopie for this clever bit of logic.
if (total_rows <= visible_rows && total_width <= visible_width) {
- //thanks yessopie for this clever bit of logic
+
use_hscroll = false;
use_vscroll = false;
-
} else {
if (total_rows > visible_rows && total_width <= visible_width) {
- //thanks yessopie for this clever bit of logic
use_hscroll = false;
}
if (total_rows <= visible_rows && total_width > visible_width) {
- //thanks yessopie for this clever bit of logic
use_vscroll = false;
}
}
@@ -459,6 +461,7 @@ void TextEdit::_click_selection_held() {
}
void TextEdit::_update_selection_mode_pointer() {
+ dragging_selection = true;
Point2 mp = get_local_mouse_position();
int row, col;
@@ -474,6 +477,7 @@ void TextEdit::_update_selection_mode_pointer() {
}
void TextEdit::_update_selection_mode_word() {
+ dragging_selection = true;
Point2 mp = get_local_mouse_position();
int row, col;
@@ -481,7 +485,7 @@ void TextEdit::_update_selection_mode_word() {
String line = text[row];
int beg = CLAMP(col, 0, line.length());
- // if its the first selection and on whitespace make sure we grab the word instead..
+ // If its the first selection and on whitespace make sure we grab the word instead.
if (!selection.active) {
while (beg > 0 && line[beg] <= 32) {
beg--;
@@ -490,7 +494,7 @@ void TextEdit::_update_selection_mode_word() {
int end = beg;
bool symbol = beg < line.length() && _is_symbol(line[beg]);
- // get the word end and begin points
+ // Get the word end and begin points.
while (beg > 0 && line[beg - 1] > 32 && (symbol == _is_symbol(line[beg - 1]))) {
beg--;
}
@@ -501,7 +505,7 @@ void TextEdit::_update_selection_mode_word() {
end += 1;
}
- // initial selection
+ // Initial selection.
if (!selection.active) {
select(row, beg, row, end);
selection.selecting_column = beg;
@@ -530,6 +534,7 @@ void TextEdit::_update_selection_mode_word() {
}
void TextEdit::_update_selection_mode_line() {
+ dragging_selection = true;
Point2 mp = get_local_mouse_position();
int row, col;
@@ -537,11 +542,11 @@ void TextEdit::_update_selection_mode_line() {
col = 0;
if (row < selection.selecting_line) {
- // cursor is above us
+ // Cursor is above us.
cursor_set_line(row - 1, false);
selection.selecting_column = text[selection.selecting_line].length();
} else {
- // cursor is below us
+ // Cursor is below us.
cursor_set_line(row + 1, false);
selection.selecting_column = 0;
col = text[row].length();
@@ -554,11 +559,58 @@ void TextEdit::_update_selection_mode_line() {
click_select_held->start();
}
+void TextEdit::_update_minimap_click() {
+ Point2 mp = get_local_mouse_position();
+
+ int xmargin_end = get_size().width - cache.style_normal->get_margin(MARGIN_RIGHT);
+ if (!dragging_minimap && (mp.x < xmargin_end - minimap_width || mp.y > xmargin_end)) {
+ minimap_clicked = false;
+ return;
+ }
+ minimap_clicked = true;
+ dragging_minimap = true;
+
+ int row;
+ _get_minimap_mouse_row(Point2i(mp.x, mp.y), row);
+
+ if (row >= get_first_visible_line() && (row < get_last_visible_line() || row >= (text.size() - 1))) {
+ minimap_scroll_ratio = v_scroll->get_as_ratio();
+ minimap_scroll_click_pos = mp.y;
+ can_drag_minimap = true;
+ return;
+ }
+
+ int wi;
+ int first_line = row - num_lines_from_rows(row, 0, -get_visible_rows() / 2, wi) + 1;
+ double delta = get_scroll_pos_for_line(first_line, wi) - get_v_scroll();
+ if (delta < 0) {
+ _scroll_up(-delta);
+ } else {
+ _scroll_down(delta);
+ }
+}
+
+void TextEdit::_update_minimap_drag() {
+
+ if (!can_drag_minimap) {
+ return;
+ }
+
+ int control_height = _get_control_height();
+ int scroll_height = v_scroll->get_max() * (minimap_char_size.y + minimap_line_spacing);
+ if (control_height > scroll_height) {
+ control_height = scroll_height;
+ }
+
+ Point2 mp = get_local_mouse_position();
+ double diff = (mp.y - minimap_scroll_click_pos) / control_height;
+ v_scroll->set_as_ratio(minimap_scroll_ratio + diff);
+}
+
void TextEdit::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
-
_update_caches();
if (cursor_changed_dirty)
MessageQueue::get_singleton()->push_call(this, "_cursor_changed_emit");
@@ -567,14 +619,19 @@ void TextEdit::_notification(int p_what) {
_update_wrap_at();
} break;
case NOTIFICATION_RESIZED: {
-
_update_scrollbars();
- call_deferred("_update_wrap_at");
+ _update_wrap_at();
+ } break;
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ if (is_visible()) {
+ call_deferred("_update_scrollbars");
+ call_deferred("_update_wrap_at");
+ }
} break;
case NOTIFICATION_THEME_CHANGED: {
-
_update_caches();
_update_wrap_at();
+ syntax_highlighting_cache.clear();
} break;
case MainLoop::NOTIFICATION_WM_FOCUS_IN: {
window_has_focus = true;
@@ -590,24 +647,26 @@ void TextEdit::_notification(int p_what) {
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();
+ // To ensure minimap is responsive overide the speed setting.
+ double vel = ((target_y / dist) * ((minimap_clicked) ? 3000 : v_scroll_speed)) * get_physics_process_delta_time();
if (Math::abs(vel) >= dist) {
set_v_scroll(target_v_scroll);
scrolling = false;
+ minimap_clicked = false;
set_physics_process_internal(false);
} else {
set_v_scroll(get_v_scroll() + vel);
}
} else {
scrolling = false;
+ minimap_clicked = false;
set_physics_process_internal(false);
}
} break;
case NOTIFICATION_DRAW: {
-
if (first_draw) {
- //size may not be the final one, so attempts to ensure cursor was visible may have failed
+ // Size may not be the final one, so attempts to ensure cursor was visible may have failed.
adjust_viewport_to_cursor();
first_draw = false;
}
@@ -637,6 +696,11 @@ void TextEdit::_notification(int p_what) {
cache.fold_gutter_width = 0;
}
+ cache.minimap_width = 0;
+ if (draw_minimap) {
+ cache.minimap_width = minimap_width;
+ }
+
int line_number_char_count = 0;
{
@@ -660,8 +724,9 @@ void TextEdit::_notification(int p_what) {
RID ci = get_canvas_item();
VisualServer::get_singleton()->canvas_item_set_clip(get_canvas_item(), true);
int xmargin_beg = cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width + cache.info_gutter_width;
- int xmargin_end = size.width - cache.style_normal->get_margin(MARGIN_RIGHT);
- //let's do it easy for now:
+
+ int xmargin_end = size.width - cache.style_normal->get_margin(MARGIN_RIGHT) - cache.minimap_width;
+ // Let's do it easy for now.
cache.style_normal->draw(ci, Rect2(Point2(), size));
if (readonly) {
cache.style_readonly->draw(ci, Rect2(Point2(), size));
@@ -701,7 +766,7 @@ void TextEdit::_notification(int p_what) {
if (brace_matching_enabled && cursor.line >= 0 && cursor.line < text.size() && cursor.column >= 0) {
if (cursor.column < text[cursor.line].length()) {
- //check for open
+ // Check for open.
CharType c = text[cursor.line][cursor.column];
CharType closec = 0;
@@ -723,7 +788,7 @@ void TextEdit::_notification(int p_what) {
for (int j = from; j < text[i].length(); j++) {
CharType cc = text[i][j];
- //ignore any brackets inside a string
+ // Ignore any brackets inside a string.
if (cc == '"' || cc == '\'') {
CharType quotation = cc;
do {
@@ -732,7 +797,7 @@ void TextEdit::_notification(int p_what) {
break;
}
cc = text[i][j];
- //skip over escaped quotation marks inside strings
+ // Skip over escaped quotation marks inside strings.
if (cc == '\\') {
bool escaped = true;
while (j + 1 < text[i].length() && text[i][j + 1] == '\\') {
@@ -789,7 +854,7 @@ void TextEdit::_notification(int p_what) {
for (int j = from; j >= 0; j--) {
CharType cc = text[i][j];
- //ignore any brackets inside a string
+ // Ignore any brackets inside a string.
if (cc == '"' || cc == '\'') {
CharType quotation = cc;
do {
@@ -798,7 +863,7 @@ void TextEdit::_notification(int p_what) {
break;
}
cc = text[i][j];
- //skip over escaped quotation marks inside strings
+ // Skip over escaped quotation marks inside strings.
if (cc == quotation) {
bool escaped = false;
while (j - 1 >= 0 && text[i][j - 1] == '\\') {
@@ -837,10 +902,10 @@ void TextEdit::_notification(int p_what) {
Point2 cursor_pos;
int cursor_insert_offset_y = 0;
- // get the highlighted words
+ // Get the highlighted words.
String highlighted_text = get_selection_text();
- // check if highlighted words contains only whitespaces (tabs or spaces)
+ // Check if highlighted words contains only whitespaces (tabs or spaces).
bool only_whitespaces_highlighted = highlighted_text.strip_edges() == String();
String line_num_padding = line_numbers_zero_padded ? "0" : " ";
@@ -849,9 +914,156 @@ void TextEdit::_notification(int p_what) {
FontDrawer drawer(cache.font, Color(1, 1, 1));
- int line = get_first_visible_line() - 1;
+ int first_visible_line = get_first_visible_line() - 1;
int draw_amount = visible_rows + (smooth_scroll_enabled ? 1 : 0);
- draw_amount += times_line_wraps(line + 1);
+ draw_amount += times_line_wraps(first_visible_line + 1);
+
+ // minimap
+ if (draw_minimap) {
+ int minimap_visible_lines = _get_minimap_visible_rows();
+ int minimap_line_height = (minimap_char_size.y + minimap_line_spacing);
+ int minimap_tab_size = minimap_char_size.x * indent_size;
+
+ // calculate viewport size and y offset
+ int viewport_height = (draw_amount - 1) * minimap_line_height;
+ int control_height = _get_control_height() - viewport_height;
+ int viewport_offset_y = round(get_scroll_pos_for_line(first_visible_line) * control_height) / ((v_scroll->get_max() <= minimap_visible_lines) ? (minimap_visible_lines - draw_amount) : (v_scroll->get_max() - draw_amount));
+
+ // calculate the first line.
+ int num_lines_before = round((viewport_offset_y) / minimap_line_height);
+ int wi;
+ int minimap_line = (v_scroll->get_max() <= minimap_visible_lines) ? -1 : first_visible_line;
+ if (minimap_line >= 0) {
+ minimap_line -= num_lines_from_rows(first_visible_line, 0, -num_lines_before, wi);
+ minimap_line -= (smooth_scroll_enabled ? 1 : 0);
+ }
+ int minimap_draw_amount = minimap_visible_lines + times_line_wraps(minimap_line + 1);
+
+ // draw the minimap
+ Color viewport_color = (cache.background_color.get_v() < 0.5) ? Color(1, 1, 1, 0.1) : Color(0, 0, 0, 0.1);
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2((xmargin_end + 2), viewport_offset_y, cache.minimap_width, viewport_height), viewport_color);
+ for (int i = 0; i < minimap_draw_amount; i++) {
+
+ minimap_line++;
+
+ if (minimap_line < 0 || minimap_line >= (int)text.size()) {
+ break;
+ }
+
+ while (is_line_hidden(minimap_line)) {
+ minimap_line++;
+ if (minimap_line < 0 || minimap_line >= (int)text.size()) {
+ break;
+ }
+ }
+
+ Map<int, HighlighterInfo> color_map;
+ if (syntax_coloring) {
+ color_map = _get_line_syntax_highlighting(minimap_line);
+ }
+
+ Color current_color = cache.font_color;
+ if (readonly) {
+ current_color = cache.font_color_readonly;
+ }
+
+ Vector<String> wrap_rows = get_wrap_rows_text(minimap_line);
+ int line_wrap_amount = times_line_wraps(minimap_line);
+ int last_wrap_column = 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 >= minimap_draw_amount)
+ break;
+ }
+
+ const String &str = wrap_rows[line_wrap_index];
+ int indent_px = line_wrap_index != 0 ? get_indent_level(minimap_line) : 0;
+ if (indent_px >= wrap_at) {
+ indent_px = 0;
+ }
+ indent_px = minimap_char_size.x * indent_px;
+
+ if (line_wrap_index > 0) {
+ last_wrap_column += wrap_rows[line_wrap_index - 1].length();
+ }
+
+ if (minimap_line == cursor.line && cursor_wrap_index == line_wrap_index && highlight_current_line) {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2((xmargin_end + 2), i * 3, cache.minimap_width, 2), cache.current_line_color);
+ }
+
+ Color previous_color;
+ int characters = 0;
+ int tabs = 0;
+ for (int j = 0; j < str.length(); j++) {
+ 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 = cache.font_color_readonly.a;
+ }
+ }
+ color = current_color;
+ }
+
+ if (j == 0) {
+ previous_color = color;
+ }
+
+ int xpos = indent_px + ((xmargin_end + minimap_char_size.x) + (minimap_char_size.x * j)) + tabs;
+ bool out_of_bounds = (xpos >= xmargin_end + cache.minimap_width);
+
+ bool is_whitespace = _is_whitespace(str[j]);
+ if (!is_whitespace) {
+ characters++;
+
+ if (j < str.length() - 1 && color == previous_color && !out_of_bounds) {
+ continue;
+ }
+
+ // If we've changed colour we are at the start of a new section, therefore we need to go back to the end
+ // of the previous section to draw it, we'll also add the character back on.
+ if (color != previous_color) {
+ characters--;
+ j--;
+
+ if (str[j] == '\t') {
+ tabs -= minimap_tab_size;
+ }
+ }
+ }
+
+ if (characters > 0) {
+ previous_color.a *= 0.6;
+ // take one for zero indexing, and if we hit whitespace / the end of a word.
+ int chars = MAX(0, (j - (characters - 1)) - (is_whitespace ? 1 : 0)) + 1;
+ int char_x_ofs = indent_px + ((xmargin_end + minimap_char_size.x) + (minimap_char_size.x * chars)) + tabs;
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(char_x_ofs, minimap_line_height * i), Point2(minimap_char_size.x * characters, minimap_char_size.y)), previous_color);
+ }
+
+ if (out_of_bounds) {
+ break;
+ }
+
+ // re-adjust if we went backwards.
+ if (color != previous_color && !is_whitespace) {
+ characters++;
+ }
+
+ if (str[j] == '\t') {
+ tabs += minimap_tab_size;
+ }
+
+ previous_color = color;
+ characters = 0;
+ }
+ }
+ }
+ }
+
+ // draw main text
+ int line = first_visible_line;
for (int i = 0; i < draw_amount; i++) {
line++;
@@ -875,7 +1087,7 @@ void TextEdit::_notification(int p_what) {
if (syntax_coloring) {
color_map = _get_line_syntax_highlighting(line);
}
- // ensure we at least use the font color
+ // Ensure we at least use the font color.
Color current_color = readonly ? cache.font_color_readonly : cache.font_color;
bool underlined = false;
@@ -916,7 +1128,7 @@ void TextEdit::_notification(int p_what) {
if (smooth_scroll_enabled)
ofs_y += (-get_v_scroll_offset()) * get_row_height();
- // check if line contains highlighted word
+ // Check if line contains highlighted word.
int highlighted_text_col = -1;
int search_text_col = -1;
int highlighted_word_col = -1;
@@ -938,25 +1150,25 @@ void TextEdit::_notification(int p_what) {
}
if (str.length() == 0) {
- // draw line background if empty as we won't loop at at all
+ // 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
+ // 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 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);
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(0, ofs_y, xmargin_beg + ofs_x, get_row_height()), cache.current_line_color);
}
}
if (line_wrap_index == 0) {
- // only do these if we are on the first wrapped part of a line
+ // 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
@@ -966,7 +1178,7 @@ void TextEdit::_notification(int p_what) {
#endif
}
- // draw bookmark marker
+ // Draw bookmark marker.
if (text.is_bookmark(line)) {
if (draw_bookmark_gutter) {
int vertical_gap = (get_row_height() * 40) / 100;
@@ -976,26 +1188,26 @@ void TextEdit::_notification(int p_what) {
}
}
- // draw breakpoint marker
+ // 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
+ // 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 info icons
+ // Draw info icons.
if (draw_info_gutter && text.has_info_icon(line)) {
int vertical_gap = (get_row_height() * 40) / 100;
int horizontal_gap = (cache.info_gutter_width * 30) / 100;
int gutter_left = cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width;
Ref<Texture> info_icon = text.get_info_icon(line);
- // ensure the icon fits the gutter size
+ // Ensure the icon fits the gutter size.
Size2i icon_size = info_icon->get_size();
if (icon_size.width > cache.info_gutter_width - horizontal_gap) {
icon_size.width = cache.info_gutter_width - horizontal_gap;
@@ -1013,7 +1225,7 @@ void TextEdit::_notification(int p_what) {
draw_texture_rect(info_icon, Rect2(icon_pos, icon_size));
}
- // draw execution marker
+ // Draw execution marker.
if (executing_line == line) {
if (draw_breakpoint_gutter) {
int icon_extra_size = 4;
@@ -1031,7 +1243,7 @@ void TextEdit::_notification(int p_what) {
}
}
- // draw fold markers
+ // 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 + cache.info_gutter_width;
@@ -1046,7 +1258,7 @@ void TextEdit::_notification(int p_what) {
}
}
- // draw line numbers
+ // Draw line numbers.
if (cache.line_number_w) {
int yofs = ofs_y + (get_row_height() - cache.font->get_height()) / 2;
String fc = String::num(line + 1);
@@ -1058,32 +1270,35 @@ void TextEdit::_notification(int p_what) {
}
}
- //loop through characters in one line
+ // Loop through characters in one line.
for (int j = 0; j < str.length(); j++) {
if (syntax_coloring) {
if (color_map.has(last_wrap_column + j)) {
- current_color = readonly ? cache.font_color_readonly : color_map[last_wrap_column + j].color;
+ current_color = color_map[last_wrap_column + j].color;
+ if (readonly && current_color.a > cache.font_color_readonly.a) {
+ current_color.a = cache.font_color_readonly.a;
+ }
}
color = current_color;
}
int char_w;
- //handle tabulator
+ // 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;
- // line highlighting handle horizontal clipping
+ // 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
+ // 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
+ // 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);
}
}
@@ -1097,7 +1312,7 @@ void TextEdit::_notification(int p_what) {
bool in_search_result = false;
if (search_text_col != -1) {
- // if we are at the end check for new search result on same line
+ // 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);
@@ -1108,19 +1323,19 @@ void TextEdit::_notification(int p_what) {
}
}
- //current line highlighting
+ // 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));
if (line == cursor.line && cursor_wrap_index == line_wrap_index && highlight_current_line) {
- // draw the wrap indent offset highlight
+ // 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, indent_px, get_row_height()), cache.current_line_color);
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(char_ofs + char_margin + ofs_x - indent_px, ofs_y, indent_px, get_row_height()), cache.current_line_color);
}
- // if its the last char draw to end of the 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);
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(char_ofs + char_margin + char_w + ofs_x, ofs_y, xmargin_end - (char_ofs + char_margin + char_w), get_row_height()), cache.current_line_color);
}
- // actual text
+ // 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);
}
@@ -1145,14 +1360,14 @@ void TextEdit::_notification(int p_what) {
if (highlight_all_occurrences && !only_whitespaces_highlighted) {
if (highlighted_text_col != -1) {
- // if we are at the end check for new word on same line
+ // 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 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;
}
@@ -1349,7 +1564,7 @@ void TextEdit::_notification(int p_what) {
bool completion_below = false;
if (completion_active) {
- // code completion box
+ // Code completion box.
Ref<StyleBox> csb = get_stylebox("completion");
int maxlines = get_constant("completion_lines");
int cmax_width = get_constant("completion_max_width") * cache.font->get_char_size('x').x;
@@ -1371,7 +1586,7 @@ void TextEdit::_notification(int p_what) {
w = cmax_width;
}
- // Add space for completion icons
+ // Add space for completion icons.
const int icon_hsep = get_constant("hseparation", "ItemList");
Size2 icon_area_size(get_row_height(), get_row_height());
w += icon_area_size.width + icon_hsep;
@@ -1403,7 +1618,7 @@ void TextEdit::_notification(int p_what) {
}
int line_from = CLAMP(completion_index - lines / 2, 0, completion_options.size() - lines);
VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(completion_rect.position.x, completion_rect.position.y + (completion_index - line_from) * get_row_height()), Size2(completion_rect.size.width, get_row_height())), cache.completion_selected_color);
- draw_rect(Rect2(completion_rect.position + Vector2(icon_area_size.x + icon_hsep, 0), Size2(nofs, completion_rect.size.height)), cache.completion_existing_color);
+ draw_rect(Rect2(completion_rect.position + Vector2(icon_area_size.x + icon_hsep, 0), Size2(MIN(nofs, completion_rect.size.width - (icon_area_size.x + icon_hsep)), completion_rect.size.height)), cache.completion_existing_color);
for (int i = 0; i < lines; i++) {
@@ -1418,7 +1633,7 @@ void TextEdit::_notification(int p_what) {
int yofs = (get_row_height() - cache.font->get_height()) / 2;
Point2 title_pos(completion_rect.position.x, completion_rect.position.y + i * get_row_height() + cache.font->get_ascent() + yofs);
- //draw completion icon if it is valid
+ // Draw completion icon if it is valid.
Ref<Texture> icon = completion_options[l].icon;
Rect2 icon_area(completion_rect.position.x, completion_rect.position.y + i * get_row_height(), icon_area_size.width, icon_area_size.height);
if (icon.is_valid()) {
@@ -1430,11 +1645,11 @@ void TextEdit::_notification(int p_what) {
}
title_pos.x = icon_area.position.x + icon_area.size.width + icon_hsep;
- draw_string(cache.font, title_pos, completion_options[l].display, text_color, completion_rect.size.width);
+ draw_string(cache.font, title_pos, completion_options[l].display, text_color, completion_rect.size.width - (icon_area_size.x + icon_hsep));
}
if (scrollw) {
- //draw a small scroll rectangle to show a position in the options
+ // Draw a small scroll rectangle to show a position in the options.
float r = maxlines / (float)completion_options.size();
float o = line_from / (float)completion_options.size();
draw_rect(Rect2(completion_rect.position.x + completion_rect.size.width, completion_rect.position.y + o * completion_rect.size.y, scrollw, completion_rect.size.y * r), scrollc);
@@ -1443,7 +1658,7 @@ void TextEdit::_notification(int p_what) {
completion_line_ofs = line_from;
}
- // check to see if the hint should be drawn
+ // Check to see if the hint should be drawn.
bool show_hint = false;
if (completion_hint != "") {
if (completion_active) {
@@ -1520,7 +1735,6 @@ void TextEdit::_notification(int p_what) {
OS::get_singleton()->set_ime_active(true);
OS::get_singleton()->set_ime_position(get_global_position() + cursor_pos + Point2(0, get_row_height()));
}
-
} break;
case NOTIFICATION_FOCUS_ENTER: {
@@ -1662,9 +1876,9 @@ void TextEdit::backspace_at_cursor() {
_is_pair_left_symbol(text[cursor.line][cursor.column - 1])) {
_consume_backspace_for_pair_symbol(prev_line, prev_column);
} else {
- // handle space indentation
+ // Handle space indentation.
if (cursor.column != 0 && indent_using_spaces) {
- // check if there are no other chars before cursor, just indentation
+ // Check if there are no other chars before cursor, just indentation.
bool unindent = true;
int i = 0;
while (i < cursor.column && i < text[cursor.line].length()) {
@@ -1675,10 +1889,9 @@ void TextEdit::backspace_at_cursor() {
i++;
}
- // then we can remove all spaces as a single character.
+ // Then we can remove all spaces as a single character.
if (unindent) {
- // we want to remove spaces up to closest indent
- // or whole indent if cursor is pointing at it
+ // We want to remove spaces up to closest indent, or whole indent if cursor is pointing at it.
int spaces_to_delete = _calculate_spaces_till_next_left_indent(cursor.column);
prev_column = cursor.column - spaces_to_delete;
_remove_text(cursor.line, prev_column, cursor.line, cursor.column);
@@ -1699,8 +1912,8 @@ void TextEdit::indent_right() {
int start_line;
int end_line;
- // this value informs us by how much we changed selection position by indenting right
- // default is 1 for tab indentation
+ // This value informs us by how much we changed selection position by indenting right.
+ // Default is 1 for tab indentation.
int selection_offset = 1;
begin_complex_operation();
@@ -1712,7 +1925,7 @@ void TextEdit::indent_right() {
end_line = start_line;
}
- // ignore if the cursor is not past the first column
+ // Ignore if the cursor is not past the first column.
if (is_selection_active() && get_selection_to_column() == 0) {
end_line--;
}
@@ -1720,10 +1933,10 @@ void TextEdit::indent_right() {
for (int i = start_line; i <= end_line; i++) {
String line_text = get_line(i);
if (indent_using_spaces) {
- // we don't really care where selection is - we just need to know indentation level at the beginning of the line
+ // We don't really care where selection is - we just need to know indentation level at the beginning of the line.
int left = _find_first_non_whitespace_column_of_line(line_text);
int spaces_to_add = _calculate_spaces_till_next_right_indent(left);
- // since we will add this much spaces we want move whole selection and cursor by this much
+ // Since we will add this much spaces we want move whole selection and cursor by this much.
selection_offset = spaces_to_add;
for (int j = 0; j < spaces_to_add; j++)
line_text = ' ' + line_text;
@@ -1733,7 +1946,7 @@ void TextEdit::indent_right() {
set_line(i, line_text);
}
- // fix selection and cursor being off after shifting selection right
+ // Fix selection and cursor being off after shifting selection right.
if (is_selection_active()) {
select(selection.from_line, selection.from_column + selection_offset, selection.to_line, selection.to_column + selection_offset);
}
@@ -1747,10 +1960,9 @@ void TextEdit::indent_left() {
int start_line;
int end_line;
- // moving cursor and selection after unindenting can get tricky
- // because changing content of line can move cursor and selection on it's own (if new line ends before previous position of either)
- // therefore we just remember initial values
- // and at the end of the operation offset them by number of removed characters
+ // Moving cursor and selection after unindenting can get tricky because
+ // changing content of line can move cursor and selection on it's own (if new line ends before previous position of either),
+ // therefore we just remember initial values and at the end of the operation offset them by number of removed characters.
int removed_characters = 0;
int initial_selection_end_column = selection.to_column;
int initial_cursor_column = cursor.column;
@@ -1765,7 +1977,7 @@ void TextEdit::indent_left() {
end_line = start_line;
}
- // ignore if the cursor is not past the first column
+ // Ignore if the cursor is not past the first column.
if (is_selection_active() && get_selection_to_column() == 0) {
end_line--;
}
@@ -1779,12 +1991,12 @@ void TextEdit::indent_left() {
set_line(i, line_text);
removed_characters = 1;
} else if (line_text.begins_with(" ")) {
- // when unindenting we aim to remove spaces before line that has selection no matter what is selected
+ // When unindenting we aim to remove spaces before line that has selection no matter what is selected,
// so we start of by finding first non whitespace character of line
int left = _find_first_non_whitespace_column_of_line(line_text);
- // here we remove only enough spaces to align text to nearest full multiple of indentation_size
- // in case where selection begins at the start of indentation_size multiple we remove whole indentation level
+ // Here we remove only enough spaces to align text to nearest full multiple of indentation_size.
+ // In case where selection begins at the start of indentation_size multiple we remove whole indentation level.
int spaces_to_remove = _calculate_spaces_till_next_left_indent(left);
line_text = line_text.substr(spaces_to_remove, line_text.length());
@@ -1793,7 +2005,7 @@ void TextEdit::indent_left() {
}
}
- // fix selection and cursor being off by one on the last line
+ // Fix selection and cursor being off by one on the last line.
if (is_selection_active() && last_line_text != get_line(end_line)) {
select(selection.from_line, selection.from_column - removed_characters,
selection.to_line, initial_selection_end_column - removed_characters);
@@ -1834,7 +2046,7 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co
}
if (row < 0)
- row = 0; //todo
+ row = 0; // TODO.
int col = 0;
@@ -1848,7 +2060,7 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co
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
+ // Move back one if we are at the end of the row.
Vector<String> rows2 = get_wrap_rows_text(row);
int row_end_col = 0;
for (int i = 0; i < wrap_index + 1; i++) {
@@ -1863,6 +2075,61 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co
r_col = col;
}
+void TextEdit::_get_minimap_mouse_row(const Point2i &p_mouse, int &r_row) const {
+
+ float rows = p_mouse.y;
+ rows -= cache.style_normal->get_margin(MARGIN_TOP);
+ rows /= (minimap_char_size.y + minimap_line_spacing);
+ rows += get_v_scroll_offset();
+
+ // calculate visible lines
+ int minimap_visible_lines = _get_minimap_visible_rows();
+ int visible_rows = get_visible_rows() + 1;
+ int first_visible_line = get_first_visible_line() - 1;
+ int draw_amount = visible_rows + (smooth_scroll_enabled ? 1 : 0);
+ draw_amount += times_line_wraps(first_visible_line + 1);
+ int minimap_line_height = (minimap_char_size.y + minimap_line_spacing);
+
+ // calculate viewport size and y offset
+ int viewport_height = (draw_amount - 1) * minimap_line_height;
+ int control_height = _get_control_height() - viewport_height;
+ int viewport_offset_y = round(get_scroll_pos_for_line(first_visible_line) * control_height) / ((v_scroll->get_max() <= minimap_visible_lines) ? (minimap_visible_lines - draw_amount) : (v_scroll->get_max() - draw_amount));
+
+ // calculate the first line.
+ int num_lines_before = round((viewport_offset_y) / minimap_line_height);
+ int wi;
+ int minimap_line = (v_scroll->get_max() <= minimap_visible_lines) ? -1 : first_visible_line;
+ if (first_visible_line > 0 && minimap_line >= 0) {
+ minimap_line -= num_lines_from_rows(first_visible_line, 0, -num_lines_before, wi);
+ minimap_line -= (smooth_scroll_enabled ? 1 : 0);
+ } else {
+ minimap_line = 0;
+ }
+
+ int row = minimap_line + Math::floor(rows);
+ int wrap_index = 0;
+
+ if (is_wrap_enabled() || is_hiding_enabled()) {
+
+ int f_ofs = num_lines_from_rows(minimap_line, cursor.wrap_ofs, rows + (1 * SGN(rows)), wrap_index) - 1;
+ if (rows < 0) {
+ row = minimap_line - f_ofs;
+ } else {
+ row = minimap_line + f_ofs;
+ }
+ }
+
+ if (row < 0) {
+ row = 0;
+ }
+
+ if (row >= text.size()) {
+ row = text.size() - 1;
+ }
+
+ r_row = row;
+}
+
void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
double prev_v_scroll = v_scroll->get_value();
@@ -1936,13 +2203,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
int row, col;
_get_mouse_pos(Point2i(mb->get_position().x, mb->get_position().y), row, col);
- if (mb->get_command() && highlighted_word != String()) {
-
- emit_signal("symbol_lookup", highlighted_word, row, col);
- return;
- }
-
- // toggle breakpoint on gutter click
+ // Toggle breakpoint on gutter click.
if (draw_breakpoint_gutter) {
int gutter = cache.style_normal->get_margin(MARGIN_LEFT);
if (mb->get_position().x > gutter - 6 && mb->get_position().x <= gutter + cache.breakpoint_gutter_width - 3) {
@@ -1952,7 +2213,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
}
- // emit info clicked
+ // Emit info clicked.
if (draw_info_gutter && text.has_info_icon(row)) {
int left_margin = cache.style_normal->get_margin(MARGIN_LEFT);
int gutter_left = left_margin + cache.breakpoint_gutter_width;
@@ -1962,7 +2223,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
}
- // toggle fold on gutter click if can
+ // Toggle fold on gutter click if can.
if (draw_fold_gutter) {
int left_margin = cache.style_normal->get_margin(MARGIN_LEFT);
@@ -1977,7 +2238,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
}
- // unfold on folded icon click
+ // Unfold on folded icon click.
if (is_folded(row)) {
int line_width = text.get_line_width(row);
line_width += cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.info_gutter_width + cache.fold_gutter_width - cursor.x_ofs;
@@ -1987,6 +2248,14 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
}
+ // minimap
+ if (draw_minimap) {
+ _update_minimap_click();
+ if (dragging_minimap) {
+ return;
+ }
+ }
+
int prev_col = cursor.column;
int prev_line = cursor.line;
@@ -2044,9 +2313,6 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
} else {
- //if sel active and dblick last time < something
-
- //else
selection.active = false;
selection.selecting_mode = Selection::MODE_POINTER;
selection.selecting_line = row;
@@ -2054,14 +2320,14 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
if (!mb->is_doubleclick() && (OS::get_singleton()->get_ticks_msec() - last_dblclk) < 600 && cursor.line == prev_line) {
- //tripleclick select line
+
+ // Triple-click select line.
selection.selecting_mode = Selection::MODE_LINE;
_update_selection_mode_line();
last_dblclk = 0;
-
} else if (mb->is_doubleclick() && text[cursor.line].length()) {
- //doubleclick select word
+ // Double-click select word.
selection.selecting_mode = Selection::MODE_WORD;
_update_selection_mode_word();
last_dblclk = OS::get_singleton()->get_ticks_msec();
@@ -2086,7 +2352,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
int to_column = get_selection_to_column();
if (row < from_line || row > to_line || (row == from_line && col < from_column) || (row == to_line && col > to_column)) {
- // Right click is outside the selected text
+ // Right click is outside the selected text.
deselect();
}
}
@@ -2104,10 +2370,22 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
} else {
- if (mb->get_button_index() == BUTTON_LEFT)
+ if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_command() && highlighted_word != String()) {
+ int row, col;
+ _get_mouse_pos(Point2i(mb->get_position().x, mb->get_position().y), row, col);
+
+ emit_signal("symbol_lookup", highlighted_word, row, col);
+ return;
+ }
+
+ dragging_minimap = false;
+ dragging_selection = false;
+ can_drag_minimap = false;
click_select_held->stop();
+ }
- // notify to show soft keyboard
+ // Notify to show soft keyboard.
notification(NOTIFICATION_FOCUS_ENTER);
}
}
@@ -2123,7 +2401,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
h_scroll->set_value(h_scroll->get_value() + pan_gesture->get_delta().x * 100);
if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll)
- accept_event(); //accept event if scroll changed
+ accept_event(); // Accept event if scroll changed.
return;
}
@@ -2148,34 +2426,40 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
}
- if (mm->get_button_mask() & BUTTON_MASK_LEFT && get_viewport()->gui_get_drag_data() == Variant()) { //ignore if dragging
+ if (mm->get_button_mask() & BUTTON_MASK_LEFT && get_viewport()->gui_get_drag_data() == Variant()) { // Ignore if dragging.
_reset_caret_blink_timer();
- switch (selection.selecting_mode) {
- case Selection::MODE_POINTER: {
- _update_selection_mode_pointer();
- } break;
- case Selection::MODE_WORD: {
- _update_selection_mode_word();
- } break;
- case Selection::MODE_LINE: {
- _update_selection_mode_line();
- } break;
- default: {
- break;
+ if (draw_minimap && !dragging_selection) {
+ _update_minimap_drag();
+ }
+
+ if (!dragging_minimap) {
+ switch (selection.selecting_mode) {
+ case Selection::MODE_POINTER: {
+ _update_selection_mode_pointer();
+ } break;
+ case Selection::MODE_WORD: {
+ _update_selection_mode_word();
+ } break;
+ case Selection::MODE_LINE: {
+ _update_selection_mode_line();
+ } break;
+ default: {
+ break;
+ }
}
}
}
}
if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll)
- accept_event(); //accept event if scroll changed
+ accept_event(); // Accept event if scroll changed.
Ref<InputEventKey> k = p_gui_input;
if (k.is_valid()) {
- k = k->duplicate(); //it will be modified later on
+ k = k->duplicate(); // It will be modified later on.
#ifdef OSX_ENABLED
if (k->get_scancode() == KEY_META) {
@@ -2311,11 +2595,11 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
_consume_pair_symbol(chr[0]);
} else {
- // remove the old character if in insert mode
+ // Remove the old character if in insert mode.
if (insert_mode) {
begin_complex_operation();
- // make sure we don't try and remove empty space
+ // Make sure we don't try and remove empty space.
if (cursor.column < get_line(cursor.line).length()) {
_remove_text(cursor.line, cursor.column, cursor.line, cursor.column + 1);
}
@@ -2337,9 +2621,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
_cancel_completion();
}
- /* TEST CONTROL FIRST!! */
+ /* TEST CONTROL FIRST! */
- // some remaps for duplicate functions..
+ // Some remaps for duplicate functions.
if (k->get_command() && !k->get_shift() && !k->get_alt() && !k->get_metakey() && k->get_scancode() == KEY_INSERT) {
k->set_scancode(KEY_C);
@@ -2383,10 +2667,10 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
_reset_caret_blink_timer();
- // save here for insert mode, just in case it is cleared in the following section
+ // Save here for insert mode, just in case it is cleared in the following section.
bool had_selection = selection.active;
- // stuff to do when selection is active..
+ // Stuff to do when selection is active.
if (!readonly && selection.active) {
bool clear = false;
@@ -2406,7 +2690,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
} break;
case KEY_X:
case KEY_C:
- //special keys often used with control, wait...
+ // Special keys often used with control, wait.
clear = (!k->get_command() || k->get_shift() || k->get_alt());
break;
case KEY_DELETE:
@@ -2431,7 +2715,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
case KEY_PAGEDOWN:
case KEY_HOME:
case KEY_END:
- // ignore arrows if any modifiers are held (shift = selecting, others may be used for editor hotkeys)
+ // Ignore arrows if any modifiers are held (shift = selecting, others may be used for editor hotkeys).
if (k->get_command() || k->get_shift() || k->get_alt())
break;
unselect = true;
@@ -2469,7 +2753,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
bool scancode_handled = true;
- // special scancode test...
+ // Special scancode test.
switch (k->get_scancode()) {
@@ -2481,7 +2765,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
String ins = "\n";
- //keep indentation
+ // Keep indentation.
int space_count = 0;
for (int i = 0; i < cursor.column; i++) {
if (text[cursor.line][i] == '\t') {
@@ -2512,10 +2796,10 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
bool brace_indent = false;
- // no need to indent if we are going upwards.
+ // No need to indent if we are going upwards.
if (auto_indent && !(k->get_command() && k->get_shift())) {
- // indent once again if previous line will end with ':' or '{' and the line is not a comment
- // (i.e. colon/brace precedes current cursor position)
+ // Indent once again if previous line will end with ':' or '{' and the line is not a comment
+ // (i.e. colon/brace precedes current cursor position).
if (cursor.column > 0 && (text[cursor.line][cursor.column - 1] == ':' || text[cursor.line][cursor.column - 1] == '{') && !is_line_comment(cursor.line)) {
if (indent_using_spaces) {
ins += space_indent;
@@ -2523,7 +2807,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
ins += "\t";
}
- // no need to move the brace below if we are not taking the text with us.
+ // No need to move the brace below if we are not taking the text with us.
if (text[cursor.line][cursor.column] == '}' && !k->get_command()) {
brace_indent = true;
ins += "\n" + ins.substr(1, ins.length() - 2);
@@ -2565,7 +2849,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
} break;
case KEY_TAB: {
- if (k->get_command()) break; // avoid tab when command
+ if (k->get_command()) break; // Avoid tab when command.
if (readonly)
break;
@@ -2579,7 +2863,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
} else {
if (k->get_shift()) {
- // simple unindent
+ // Simple unindent.
int cc = cursor.column;
const String &line = text[cursor.line];
@@ -2591,17 +2875,17 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (cc > 0 && cc <= text[cursor.line].length()) {
if (text[cursor.line][cc - 1] == '\t') {
- // tabs unindentation
+ // Tabs unindentation.
_remove_text(cursor.line, cc - 1, cursor.line, cc);
if (cursor.column >= left)
cursor_set_column(MAX(0, cursor.column - 1));
update();
} else {
- // spaces unindentation
+ // Spaces unindentation.
int spaces_to_remove = _calculate_spaces_till_next_left_indent(cc);
if (spaces_to_remove > 0) {
_remove_text(cursor.line, cc - spaces_to_remove, cursor.line, cc);
- if (cursor.column > left - spaces_to_remove) // inside text?
+ if (cursor.column > left - spaces_to_remove) // Inside text?
cursor_set_column(MAX(0, cursor.column - spaces_to_remove));
update();
}
@@ -2611,9 +2895,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
update();
}
} else {
- // simple indent
+ // Simple indent.
if (indent_using_spaces) {
- // insert only as much spaces as needed till next indentation level
+ // Insert only as much spaces as needed till next indentation level.
int spaces_to_add = _calculate_spaces_till_next_right_indent(cursor.column);
String indent_to_insert = String();
for (int i = 0; i < spaces_to_add; i++)
@@ -2641,20 +2925,20 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
int line = cursor.line;
int column = cursor.column;
- // check if we are removing a single whitespace, if so remove it and the next char type
- // else we just remove the whitespace
+ // Check if we are removing a single whitespace, if so remove it and the next char type,
+ // else we just remove the whitespace.
bool only_whitespace = false;
if (_is_whitespace(text[line][column - 1]) && _is_whitespace(text[line][column - 2])) {
only_whitespace = true;
} else if (_is_whitespace(text[line][column - 1])) {
- // remove the single whitespace
+ // Remove the single whitespace.
column--;
}
- // check if its a text char
+ // Check if its a text char.
bool only_char = (_is_text_char(text[line][column - 1]) && !only_whitespace);
- // if its not whitespace or char then symbol.
+ // If its not whitespace or char then symbol.
bool only_symbols = !(only_whitespace || only_char);
while (column > 0) {
@@ -2940,7 +3224,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
int curline_len = text[cursor.line].length();
if (cursor.line == text.size() - 1 && cursor.column == curline_len)
- break; //nothing to do
+ break; // Nothing to do.
int next_line = cursor.column < curline_len ? cursor.line : cursor.line + 1;
int next_column;
@@ -2957,20 +3241,20 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
int line = cursor.line;
int column = cursor.column;
- // check if we are removing a single whitespace, if so remove it and the next char type
- // else we just remove the whitespace
+ // Check if we are removing a single whitespace, if so remove it and the next char type,
+ // else we just remove the whitespace.
bool only_whitespace = false;
if (_is_whitespace(text[line][column]) && _is_whitespace(text[line][column + 1])) {
only_whitespace = true;
} else if (_is_whitespace(text[line][column])) {
- // remove the single whitespace
+ // Remove the single whitespace.
column++;
}
- // check if its a text char
+ // Check if its a text char.
bool only_char = (_is_text_char(text[line][column]) && !only_whitespace);
- // if its not whitespace or char then symbol.
+ // If its not whitespace or char then symbol.
bool only_symbols = !(only_whitespace || only_char);
while (column < curline_len) {
@@ -3029,7 +3313,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
cursor_set_column(0);
} else {
- // move cursor column to start of wrapped row and then to start of text
+ // 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;
@@ -3037,7 +3321,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
row_start_col += rows[i].length();
}
if (cursor.column == row_start_col || wi == 0) {
- // compute whitespace symbols seq length
+ // 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];
@@ -3088,7 +3372,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (k->get_command())
cursor_set_line(get_last_unhidden_line(), true, false, 9999);
- // move cursor column to end of wrapped row and then to end of text
+ // 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;
@@ -3241,6 +3525,10 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
} break;
case KEY_Z: {
+ if (readonly) {
+ break;
+ }
+
if (!k->get_command()) {
scancode_handled = false;
break;
@@ -3253,6 +3541,10 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
} break;
case KEY_Y: {
+ if (readonly) {
+ break;
+ }
+
if (!k->get_command()) {
scancode_handled = false;
break;
@@ -3274,7 +3566,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
} break;
case KEY_SPACE: {
#ifdef OSX_ENABLED
- if (completion_enabled && k->get_metakey()) { //cmd-space is spotlight shortcut in OSX
+ if (completion_enabled && k->get_metakey()) { // cmd-space is spotlight shortcut in OSX
#else
if (completion_enabled && k->get_command()) {
#endif
@@ -3302,18 +3594,18 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
return;
}
- if (!scancode_handled && !k->get_command()) { //for German kbds
+ if (!scancode_handled && !k->get_command()) { // For German keyboards.
if (k->get_unicode() >= 32) {
if (readonly)
return;
- // remove the old character if in insert mode and no selection
+ // Remove the old character if in insert mode and no selection.
if (insert_mode && !had_selection) {
begin_complex_operation();
- // make sure we don't try and remove empty space
+ // Make sure we don't try and remove empty space.
if (cursor.column < get_line(cursor.line).length()) {
_remove_text(cursor.line, cursor.column, cursor.line, cursor.column + 1);
}
@@ -3347,8 +3639,10 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
void TextEdit::_scroll_up(real_t p_delta) {
- if (scrolling && smooth_scroll_enabled && SGN(target_v_scroll - v_scroll->get_value()) != SGN(-p_delta))
+ if (scrolling && smooth_scroll_enabled && SGN(target_v_scroll - v_scroll->get_value()) != SGN(-p_delta)) {
scrolling = false;
+ minimap_clicked = false;
+ }
if (scrolling) {
target_v_scroll = (target_v_scroll - p_delta);
@@ -3373,8 +3667,10 @@ void TextEdit::_scroll_up(real_t p_delta) {
void TextEdit::_scroll_down(real_t p_delta) {
- if (scrolling && smooth_scroll_enabled && SGN(target_v_scroll - v_scroll->get_value()) != SGN(p_delta))
+ if (scrolling && smooth_scroll_enabled && SGN(target_v_scroll - v_scroll->get_value()) != SGN(p_delta)) {
scrolling = false;
+ minimap_clicked = false;
+ }
if (scrolling) {
target_v_scroll = (target_v_scroll + p_delta);
@@ -3423,11 +3719,12 @@ void TextEdit::_post_shift_selection() {
void TextEdit::_scroll_lines_up() {
scrolling = false;
+ minimap_clicked = false;
- // adjust the vertical scroll
+ // Adjust the vertical scroll.
set_v_scroll(get_v_scroll() - 1);
- // adjust the cursor to viewport
+ // Adjust the cursor to viewport.
if (!selection.active) {
int cur_line = cursor.line;
int cur_wrap = get_cursor_wrap_index();
@@ -3442,11 +3739,12 @@ void TextEdit::_scroll_lines_up() {
void TextEdit::_scroll_lines_down() {
scrolling = false;
+ minimap_clicked = false;
- // adjust the vertical scroll
+ // Adjust the vertical scroll.
set_v_scroll(get_v_scroll() + 1);
- // adjust the cursor to viewport
+ // Adjust the cursor to viewport.
if (!selection.active) {
int cur_line = cursor.line;
int cur_wrap = get_cursor_wrap_index();
@@ -3463,15 +3761,15 @@ void TextEdit::_scroll_lines_down() {
void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, int &r_end_line, int &r_end_column) {
- //save for undo...
+ // Save for undo.
ERR_FAIL_INDEX(p_line, text.size());
ERR_FAIL_COND(p_char < 0);
- /* STEP 1 remove \r from source text and separate in substrings */
+ /* STEP 1: Remove \r from source text and separate in substrings. */
Vector<String> substrings = p_text.replace("\r", "").split("\n");
- /* STEP 2 fire breakpoint_toggled signals */
+ /* STEP 2: Fire breakpoint_toggled signals. */
// Is this just a new empty line?
bool shift_first_line = p_char == 0 && p_text.replace("\r", "") == "\n";
@@ -3487,19 +3785,19 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i
}
}
- /* STEP 3 add spaces if the char is greater than the end of the line */
+ /* STEP 3: Add spaces if the char is greater than the end of the line. */
while (p_char > text[p_line].length()) {
text.set(p_line, text[p_line] + String::chr(' '));
}
- /* STEP 4 separate dest string in pre and post text */
+ /* STEP 4: Separate dest string in pre and post text. */
String preinsert_text = text[p_line].substr(0, p_char);
String postinsert_text = text[p_line].substr(p_char, text[p_line].size());
for (int j = 0; j < substrings.size(); j++) {
- //insert the substrings
+ // Insert the substrings.
if (j == 0) {
@@ -3544,8 +3842,8 @@ String TextEdit::_base_get_text(int p_from_line, int p_from_column, int p_to_lin
ERR_FAIL_INDEX_V(p_from_column, text[p_from_line].length() + 1, String());
ERR_FAIL_INDEX_V(p_to_line, text.size(), String());
ERR_FAIL_INDEX_V(p_to_column, text[p_to_line].length() + 1, String());
- ERR_FAIL_COND_V(p_to_line < p_from_line, String()); // from > to
- ERR_FAIL_COND_V(p_to_line == p_from_line && p_to_column < p_from_column, String()); // from > to
+ ERR_FAIL_COND_V(p_to_line < p_from_line, String()); // 'from > to'.
+ ERR_FAIL_COND_V(p_to_line == p_from_line && p_to_column < p_from_column, String()); // 'from > to'.
String ret;
@@ -3568,8 +3866,8 @@ void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_li
ERR_FAIL_INDEX(p_from_column, text[p_from_line].length() + 1);
ERR_FAIL_INDEX(p_to_line, text.size());
ERR_FAIL_INDEX(p_to_column, text[p_to_line].length() + 1);
- ERR_FAIL_COND(p_to_line < p_from_line); // from > to
- ERR_FAIL_COND(p_to_line == p_from_line && p_to_column < p_from_column); // from > to
+ ERR_FAIL_COND(p_to_line < p_from_line); // 'from > to'.
+ ERR_FAIL_COND(p_to_line == p_from_line && p_to_column < p_from_column); // 'from > to'.
String pre_text = text[p_from_line].substr(0, p_from_column);
String post_text = text[p_to_line].substr(p_to_column, text[p_to_line].length());
@@ -3631,22 +3929,22 @@ void TextEdit::_insert_text(int p_line, int p_char, const String &p_text, int *r
op.chain_forward = false;
op.chain_backward = false;
- //see if it should just be set as current op
+ // See if it should just be set as current op.
if (current_op.type != op.type) {
op.prev_version = get_version();
_push_current_op();
current_op = op;
- return; //set as current op, return
+ return; // Set as current op, return.
}
- //see if it can be merged
+ // See if it can be merged.
if (current_op.to_line != p_line || current_op.to_column != p_char) {
op.prev_version = get_version();
_push_current_op();
current_op = op;
- return; //set as current op, return
+ return; // Set as current op, return.
}
- //merge current op
+ // Merge current op.
current_op.text += p_text;
current_op.to_column = retchar;
@@ -3670,7 +3968,7 @@ void TextEdit::_remove_text(int p_from_line, int p_from_column, int p_to_line, i
if (!undo_enabled)
return;
- /* UNDO!! */
+ /* UNDO! */
TextOperation op;
op.type = TextOperation::TYPE_REMOVE;
op.from_line = p_from_line;
@@ -3682,27 +3980,20 @@ void TextEdit::_remove_text(int p_from_line, int p_from_column, int p_to_line, i
op.chain_forward = false;
op.chain_backward = false;
- //see if it should just be set as current op
+ // See if it should just be set as current op.
if (current_op.type != op.type) {
op.prev_version = get_version();
_push_current_op();
current_op = op;
- return; //set as current op, return
+ return; // Set as current op, return.
}
- //see if it can be merged
+ // See if it can be merged.
if (current_op.from_line == p_to_line && current_op.from_column == p_to_column) {
- //basckace or similar
+ // Backspace or similar.
current_op.text = text + current_op.text;
current_op.from_line = p_from_line;
current_op.from_column = p_from_column;
- return; //update current op
- }
- if (current_op.from_line == p_from_line && current_op.from_column == p_from_column) {
-
- //current_op.text=text+current_op.text;
- //current_op.from_line=p_from_line;
- //current_op.from_column=p_from_column;
- //return; //update current op
+ return; // Update current op.
}
op.prev_version = get_version();
@@ -3725,6 +4016,15 @@ void TextEdit::_line_edited_from(int p_line) {
for (int i = p_line; i < cache_size; i++) {
color_region_cache.erase(i);
}
+
+ if (syntax_highlighting_cache.size() > 0) {
+ cache_size = syntax_highlighting_cache.back()->key();
+ for (int i = p_line - 1; i <= cache_size; i++) {
+ if (syntax_highlighting_cache.has(i)) {
+ syntax_highlighting_cache.erase(i);
+ }
+ }
+ }
}
int TextEdit::get_char_count() {
@@ -3734,11 +4034,11 @@ int TextEdit::get_char_count() {
for (int i = 0; i < text.size(); i++) {
if (i > 0)
- totalsize++; // incliude \n
+ totalsize++; // Include \n.
totalsize += text[i].length();
}
- return totalsize; // omit last \n
+ return totalsize; // Omit last \n.
}
Size2 TextEdit::get_minimum_size() const {
@@ -3746,19 +4046,26 @@ Size2 TextEdit::get_minimum_size() const {
return cache.style_normal->get_minimum_size();
}
+int TextEdit::_get_control_height() const {
+ int control_height = get_size().height;
+ control_height -= cache.style_normal->get_minimum_size().height;
+ if (h_scroll->is_visible_in_tree()) {
+ control_height -= h_scroll->get_size().height;
+ }
+ return control_height;
+}
+
int TextEdit::get_visible_rows() const {
+ return _get_control_height() / get_row_height();
+}
- int total = get_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_minimap_visible_rows() const {
+ return _get_control_height() / (minimap_char_size.y + minimap_line_spacing);
}
int TextEdit::get_total_visible_rows() const {
- // returns the total amount of rows we need in the editor.
+ // 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();
@@ -3775,12 +4082,12 @@ int TextEdit::get_total_visible_rows() const {
void TextEdit::_update_wrap_at() {
- wrap_at = get_size().width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width - cache.info_gutter_width - wrap_right_offset;
+ wrap_at = get_size().width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width - cache.info_gutter_width - cache.minimap_width - wrap_right_offset;
update_cursor_wrap_offset();
text.clear_wrap_cache();
for (int i = 0; i < text.size(); i++) {
- // update all values that wrap
+ // Update all values that wrap.
if (!line_wraps(i))
continue;
Vector<String> rows = get_wrap_rows_text(i);
@@ -3790,8 +4097,9 @@ void TextEdit::_update_wrap_at() {
void TextEdit::adjust_viewport_to_cursor() {
- // make sure cursor is visible on the screen
+ // Make sure cursor is visible on the screen.
scrolling = false;
+ minimap_clicked = false;
int cur_line = cursor.line;
int cur_wrap = get_cursor_wrap_index();
@@ -3802,20 +4110,20 @@ void TextEdit::adjust_viewport_to_cursor() {
int last_vis_wrap = get_last_visible_line_wrap_index();
if (cur_line < first_vis_line || (cur_line == first_vis_line && cur_wrap < first_vis_wrap)) {
- // cursor is above screen
+ // 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
+ // Cursor is below screen.
set_line_as_last_visible(cur_line, cur_wrap);
}
- int visible_width = get_size().width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width - cache.info_gutter_width;
+ int visible_width = get_size().width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width - cache.info_gutter_width - cache.minimap_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
+ visible_width -= 20; // Give it a little more space.
if (!is_wrap_enabled()) {
- // adjust x offset
+ // Adjust x offset.
int cursor_x = get_column_x_offset(cursor.column, text[cursor.line]);
if (cursor_x > (cursor.x_ofs + visible_width))
@@ -3833,20 +4141,21 @@ void TextEdit::adjust_viewport_to_cursor() {
void TextEdit::center_viewport_to_cursor() {
- // move viewport so the cursor is in the center of the screen
+ // Move viewport so the cursor is in the center of the screen.
scrolling = false;
+ minimap_clicked = 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 = get_size().width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width - cache.info_gutter_width;
+ int visible_width = get_size().width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width - cache.info_gutter_width - cache.minimap_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
+ visible_width -= 20; // Give it a little more space.
if (is_wrap_enabled()) {
- // center x offset
+ // Center x offset.
int cursor_x = get_column_x_offset_for_line(cursor.column, cursor.line);
if (cursor_x > (cursor.x_ofs + visible_width))
@@ -3888,7 +4197,7 @@ int TextEdit::times_line_wraps(int line) const {
int wrap_amount = text.get_line_wrap_amount(line);
if (wrap_amount == -1) {
- // update the value
+ // Update the value.
Vector<String> rows = get_wrap_rows_text(line);
wrap_amount = rows.size() - 1;
text.set_line_wrap_amount(line, wrap_amount);
@@ -3928,7 +4237,7 @@ Vector<String> TextEdit::get_wrap_rows_text(int p_line) const {
int indent_ofs = (cur_wrap_index != 0 ? tab_offset_px : 0);
if (indent_ofs + word_px + w > wrap_at) {
- // not enough space to add this char; start next line
+ // Not enough space to add this char; start next line.
wrap_substring += word_str;
lines.push_back(wrap_substring);
cur_wrap_index++;
@@ -3942,7 +4251,7 @@ Vector<String> TextEdit::get_wrap_rows_text(int p_line) const {
word_str += c;
word_px += w;
if (c == ' ') {
- // end of a word; add this word to the substring
+ // End of a word; add this word to the substring.
wrap_substring += word_str;
px += word_px;
word_str = "";
@@ -3950,9 +4259,9 @@ Vector<String> TextEdit::get_wrap_rows_text(int p_line) const {
}
if (indent_ofs + px + word_px > wrap_at) {
- // this word will be moved to the next line
+ // This word will be moved to the next line.
lines.push_back(wrap_substring);
- // reset for next wrap
+ // Reset for next wrap.
cur_wrap_index++;
wrap_substring = "";
px = 0;
@@ -3960,11 +4269,11 @@ Vector<String> TextEdit::get_wrap_rows_text(int p_line) const {
}
col++;
}
- // line ends before hit wrap_at; add this word to the substring
+ // Line ends before hit wrap_at; add this word to the substring.
wrap_substring += word_str;
lines.push_back(wrap_substring);
- // update cache
+ // Update cache.
text.set_line_wrap_amount(p_line, lines.size() - 1);
return lines;
@@ -3982,7 +4291,7 @@ int TextEdit::get_line_wrap_index_at_col(int p_line, int p_column) const {
if (!line_wraps(p_line))
return 0;
- // loop through wraps in the line text until we get to the column
+ // 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);
@@ -4123,6 +4432,7 @@ bool TextEdit::is_right_click_moving_caret() const {
void TextEdit::_v_scroll_input() {
scrolling = false;
+ minimap_clicked = false;
}
void TextEdit::_scroll_moved(double p_to_val) {
@@ -4134,7 +4444,7 @@ void TextEdit::_scroll_moved(double p_to_val) {
cursor.x_ofs = h_scroll->get_value();
if (v_scroll->is_visible_in_tree()) {
- // set line ofs and wrap ofs
+ // Set line ofs and wrap ofs.
int v_scroll_i = floor(get_v_scroll());
int sc = 0;
int n_line;
@@ -4289,12 +4599,12 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const {
_get_mouse_pos(p_pos, row, col);
int left_margin = cache.style_normal->get_margin(MARGIN_LEFT);
- // breakpoint icon
+ // Breakpoint icon.
if (draw_breakpoint_gutter && p_pos.x > left_margin - 6 && p_pos.x <= left_margin + cache.breakpoint_gutter_width - 3) {
return CURSOR_POINTING_HAND;
}
- // info icons
+ // Info icons.
int gutter_left = left_margin + cache.breakpoint_gutter_width + cache.info_gutter_width;
if (draw_info_gutter && p_pos.x > left_margin + cache.breakpoint_gutter_width - 6 && p_pos.x <= gutter_left - 3) {
if (text.has_info_icon(row)) {
@@ -4303,7 +4613,7 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const {
return CURSOR_ARROW;
}
- // fold icon
+ // Fold icon.
if (draw_fold_gutter && p_pos.x > gutter_left + cache.line_number_w - 6 && p_pos.x <= gutter_left + cache.line_number_w + cache.fold_gutter_width - 3) {
if (is_folded(row) || can_fold(row))
return CURSOR_POINTING_HAND;
@@ -4313,9 +4623,14 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const {
return CURSOR_ARROW;
} else {
+ int xmargin_end = get_size().width - cache.style_normal->get_margin(MARGIN_RIGHT);
+ if (draw_minimap && p_pos.x > xmargin_end - minimap_width && p_pos.x <= xmargin_end) {
+ return CURSOR_ARROW;
+ }
+
int row, col;
_get_mouse_pos(p_pos, row, col);
- // eol fold icon
+ // EOL fold icon.
if (is_folded(row)) {
int line_width = text.get_line_width(row);
line_width += cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width + cache.info_gutter_width - cursor.x_ofs;
@@ -4349,8 +4664,6 @@ void TextEdit::set_text(String p_text) {
update();
setting_text = false;
-
- //get_range()->set(0);
};
String TextEdit::get_text() {
@@ -4377,7 +4690,7 @@ String TextEdit::get_text_for_lookup_completion() {
if (i == row) {
longthing += text[i].substr(0, col);
- longthing += String::chr(0xFFFF); //not unicode, represents the cursor
+ longthing += String::chr(0xFFFF); // Not unicode, represents the cursor.
longthing += text[i].substr(col, text[i].size());
} else {
@@ -4399,7 +4712,7 @@ String TextEdit::get_text_for_completion() {
if (i == cursor.line) {
longthing += text[i].substr(0, cursor.column);
- longthing += String::chr(0xFFFF); //not unicode, represents the cursor
+ longthing += String::chr(0xFFFF); // Not unicode, represents the cursor.
longthing += text[i].substr(cursor.column, text[i].size());
} else {
@@ -4450,18 +4763,28 @@ void TextEdit::set_readonly(bool p_readonly) {
// Reorganize context menu.
menu->clear();
- if (!readonly)
+
+ if (!readonly) {
+ menu->add_item(RTR("Undo"), MENU_UNDO, KEY_MASK_CMD | KEY_Z);
+ menu->add_item(RTR("Redo"), MENU_REDO, KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z);
+ }
+
+ if (!readonly) {
+ menu->add_separator();
menu->add_item(RTR("Cut"), MENU_CUT, KEY_MASK_CMD | KEY_X);
+ }
+
menu->add_item(RTR("Copy"), MENU_COPY, KEY_MASK_CMD | KEY_C);
- if (!readonly)
+
+ if (!readonly) {
menu->add_item(RTR("Paste"), MENU_PASTE, KEY_MASK_CMD | KEY_V);
+ }
+
menu->add_separator();
menu->add_item(RTR("Select All"), MENU_SELECT_ALL, KEY_MASK_CMD | KEY_A);
+
if (!readonly) {
menu->add_item(RTR("Clear"), MENU_CLEAR);
- menu->add_separator();
- menu->add_item(RTR("Undo"), MENU_UNDO, KEY_MASK_CMD | KEY_Z);
- menu->add_item(RTR("Redo"), MENU_REDO, KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z);
}
update();
@@ -4572,17 +4895,18 @@ void TextEdit::_set_syntax_highlighting(SyntaxHighlighter *p_syntax_highlighter)
syntax_highlighter->set_text_editor(this);
syntax_highlighter->_update_cache();
}
+ syntax_highlighting_cache.clear();
update();
}
int TextEdit::_is_line_in_region(int p_line) {
- // do we have in cache?
+ // Do we have in cache?
if (color_region_cache.has(p_line)) {
return color_region_cache[p_line];
}
- // if not find the closest line we have
+ // If not find the closest line we have.
int previous_line = p_line - 1;
for (; previous_line > -1; previous_line--) {
if (color_region_cache.has(p_line)) {
@@ -4590,7 +4914,7 @@ int TextEdit::_is_line_in_region(int p_line) {
}
}
- // calculate up to line we need and update the cache along the way.
+ // Calculate up to line we need and update the cache along the way.
int in_region = color_region_cache[previous_line];
if (previous_line == -1) {
in_region = -1;
@@ -4638,6 +4962,7 @@ void TextEdit::clear_colors() {
keywords.clear();
color_regions.clear();
color_region_cache.clear();
+ syntax_highlighting_cache.clear();
text.clear_width_cache();
}
@@ -4718,7 +5043,7 @@ void TextEdit::cut() {
OS::get_singleton()->set_clipboard(clipboard);
_remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
- cursor_set_line(selection.from_line); // set afterwards else it causes the view to be offset
+ cursor_set_line(selection.from_line); // Set afterwards else it causes the view to be offset.
cursor_set_column(selection.from_column);
selection.active = false;
@@ -4947,7 +5272,7 @@ int TextEdit::_get_column_pos_of_word(const String &p_key, const String &p_searc
col = p_search.findn(p_key, p_from_column);
}
- // whole words only
+ // Whole words only.
if (col != -1 && p_search_flags & SEARCH_WHOLE_WORDS) {
p_from_column = col;
@@ -4987,14 +5312,12 @@ bool TextEdit::search(const String &p_key, uint32_t p_search_flags, int p_from_l
ERR_FAIL_INDEX_V(p_from_line, text.size(), false);
ERR_FAIL_INDEX_V(p_from_column, text[p_from_line].length() + 1, false);
- //search through the whole document, but start by current line
+ // Search through the whole document, but start by current line.
int line = p_from_line;
int pos = -1;
for (int i = 0; i < text.size() + 1; i++) {
- //backwards is broken...
- //int idx=(p_search_flags&SEARCH_BACKWARDS)?(text.size()-i):i; //do backwards seearch
if (line < 0) {
line = text.size() - 1;
@@ -5008,7 +5331,7 @@ bool TextEdit::search(const String &p_key, uint32_t p_search_flags, int p_from_l
if (line == p_from_line) {
if (i == text.size()) {
- //wrapped
+ // Wrapped.
if (p_search_flags & SEARCH_BACKWARDS) {
from_column = text_line.length();
@@ -5042,6 +5365,9 @@ bool TextEdit::search(const String &p_key, uint32_t p_search_flags, int p_from_l
break;
}
pos_from = last_pos - p_key.length();
+ if (pos_from < 0) {
+ break;
+ }
}
} else {
while ((last_pos = (p_search_flags & SEARCH_MATCH_CASE) ? text_line.find(p_key, pos_from) : text_line.findn(p_key, pos_from)) != -1) {
@@ -5056,7 +5382,7 @@ bool TextEdit::search(const String &p_key, uint32_t p_search_flags, int p_from_l
bool is_match = true;
if (pos != -1 && (p_search_flags & SEARCH_WHOLE_WORDS)) {
- //validate for whole words
+ // Validate for whole words.
if (pos > 0 && _is_text_char(text_line[pos - 1]))
is_match = false;
else if (pos + p_key.length() < text_line.length() && _is_text_char(text_line[pos + p_key.length()]))
@@ -5254,7 +5580,7 @@ void TextEdit::unhide_all_lines() {
int TextEdit::num_lines_from(int p_line_from, int visible_amount) const {
- // returns the number of lines (hidden and unhidden) from p_line_from to (p_line_from + visible_amount of unhidden lines)
+ // 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())
@@ -5287,8 +5613,8 @@ int TextEdit::num_lines_from(int p_line_from, int visible_amount) const {
int TextEdit::num_lines_from_rows(int p_line_from, int p_wrap_index_from, int visible_amount, int &wrap_index) const {
- // 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
+ // 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));
@@ -5334,7 +5660,7 @@ int TextEdit::num_lines_from_rows(int p_line_from, int p_wrap_index_from, int vi
int TextEdit::get_last_unhidden_line() const {
- // returns the last line in the text that is not hidden
+ // Returns the last line in the text that is not hidden.
if (!is_hiding_enabled())
return text.size() - 1;
@@ -5351,7 +5677,7 @@ int TextEdit::get_indent_level(int p_line) const {
ERR_FAIL_INDEX_V(p_line, text.size(), 0);
- // counts number of tabs and spaces before line starts
+ // Counts number of tabs and spaces before line starts.
int tab_count = 0;
int whitespace_count = 0;
int line_length = text[p_line].size();
@@ -5369,7 +5695,7 @@ int TextEdit::get_indent_level(int p_line) const {
bool TextEdit::is_line_comment(int p_line) const {
- // checks to see if this line is the start of a comment
+ // Checks to see if this line is the start of a comment.
ERR_FAIL_INDEX_V(p_line, text.size(), false);
const Map<int, Text::ColorRegionInfo> &cri_map = text.get_color_region_info(p_line);
@@ -5449,7 +5775,7 @@ void TextEdit::fold_line(int p_line) {
if (!can_fold(p_line))
return;
- // hide lines below this one
+ // Hide lines below this one.
int start_indent = get_indent_level(p_line);
int last_line = start_indent;
for (int i = p_line + 1; i < text.size(); i++) {
@@ -5467,7 +5793,7 @@ void TextEdit::fold_line(int p_line) {
set_line_as_hidden(i, true);
}
- // fix selection
+ // Fix selection.
if (is_selection_active()) {
if (is_line_hidden(selection.from_line) && is_line_hidden(selection.to_line)) {
deselect();
@@ -5478,7 +5804,7 @@ void TextEdit::fold_line(int p_line) {
}
}
- // reset cursor
+ // Reset cursor.
if (is_line_hidden(cursor.line)) {
cursor_set_line(p_line, false, false);
cursor_set_column(get_line(p_line).length(), false);
@@ -5539,8 +5865,8 @@ void TextEdit::_do_text_op(const TextOperation &p_op, bool p_reverse) {
int check_line;
int check_column;
_base_insert_text(p_op.from_line, p_op.from_column, p_op.text, check_line, check_column);
- ERR_FAIL_COND(check_line != p_op.to_line); // BUG
- ERR_FAIL_COND(check_column != p_op.to_column); // BUG
+ ERR_FAIL_COND(check_line != p_op.to_line); // BUG.
+ ERR_FAIL_COND(check_column != p_op.to_column); // BUG.
} else {
_base_remove_text(p_op.from_line, p_op.from_column, p_op.to_line, p_op.to_column);
@@ -5550,7 +5876,7 @@ void TextEdit::_do_text_op(const TextOperation &p_op, bool p_reverse) {
void TextEdit::_clear_redo() {
if (undo_stack_pos == NULL)
- return; //nothing to clear
+ return; // Nothing to clear.
_push_current_op();
@@ -5568,12 +5894,12 @@ void TextEdit::undo() {
if (undo_stack_pos == NULL) {
if (!undo_stack.size())
- return; //nothing to undo
+ return; // Nothing to undo.
undo_stack_pos = undo_stack.back();
} else if (undo_stack_pos == undo_stack.front())
- return; // at the bottom of the undo stack
+ return; // At the bottom of the undo stack.
else
undo_stack_pos = undo_stack_pos->prev();
@@ -5614,7 +5940,7 @@ void TextEdit::redo() {
_push_current_op();
if (undo_stack_pos == NULL)
- return; //nothing to do.
+ return; // Nothing to do.
deselect();
@@ -5668,7 +5994,7 @@ void TextEdit::end_complex_operation() {
void TextEdit::_push_current_op() {
if (current_op.type == TextOperation::TYPE_NONE)
- return; // do nothing
+ return; // Nothing to do.
if (next_operation_is_complex) {
current_op.chain_forward = true;
@@ -5768,7 +6094,7 @@ double TextEdit::get_scroll_pos_for_line(int p_line, int p_wrap_index) const {
if (!is_wrap_enabled() && !is_hiding_enabled())
return p_line;
- // count the number of visible lines up to this line
+ // 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++) {
@@ -5828,10 +6154,7 @@ int TextEdit::get_last_visible_line_wrap_index() const {
double TextEdit::get_visible_rows_offset() const {
- double total = get_size().height;
- total -= cache.style_normal->get_minimum_size().height;
- if (h_scroll->is_visible_in_tree())
- total -= h_scroll->get_size().height;
+ double total = _get_control_height();
total /= (double)get_row_height();
total = total - floor(total);
total = -CLAMP(total, 0.001, 1) + 1;
@@ -5969,7 +6292,7 @@ void TextEdit::_update_completion_candidates() {
String s;
- //look for keywords first
+ // Look for keywords first.
bool inquote = false;
int first_quote = -1;
@@ -5994,7 +6317,7 @@ void TextEdit::_update_completion_candidates() {
bool cancel = false;
if (!inquote && first_quote == cofs - 1) {
- //no completion here
+ // No completion here.
cancel = true;
} else if (inquote && first_quote != -1) {
@@ -6032,11 +6355,12 @@ void TextEdit::_update_completion_candidates() {
bool prev_is_prefix = false;
if (cofs > 0 && completion_prefixes.has(String::chr(l[cofs - 1])))
prev_is_prefix = true;
- if (cofs > 1 && l[cofs - 1] == ' ' && completion_prefixes.has(String::chr(l[cofs - 2]))) //check with one space before prefix, to allow indent
+ // Check with one space before prefix, to allow indent.
+ if (cofs > 1 && l[cofs - 1] == ' ' && completion_prefixes.has(String::chr(l[cofs - 2])))
prev_is_prefix = true;
if (cancel || (!pre_keyword && s == "" && (cofs == 0 || !prev_is_prefix))) {
- //none to complete, cancel
+ // None to complete, cancel.
_cancel_completion();
return;
}
@@ -6086,18 +6410,18 @@ void TextEdit::_update_completion_candidates() {
}
if (completion_options.size() == 0) {
- //no options to complete, cancel
+ // No options to complete, cancel.
_cancel_completion();
return;
}
if (completion_options.size() == 1 && s == completion_options[0].display) {
- // A perfect match, stop completion
+ // A perfect match, stop completion.
_cancel_completion();
return;
}
- // The top of the list is the best match
+ // The top of the list is the best match.
completion_current = completion_options[0];
completion_enabled = true;
}
@@ -6116,10 +6440,30 @@ void TextEdit::query_code_comple() {
c--;
}
- if (ofs > 0 && (inquote || _is_completable(l[ofs - 1]) || completion_prefixes.has(String::chr(l[ofs - 1]))))
- emit_signal("request_completion");
- else if (ofs > 1 && l[ofs - 1] == ' ' && completion_prefixes.has(String::chr(l[ofs - 2]))) //make it work with a space too, it's good enough
- emit_signal("request_completion");
+ bool ignored = completion_active && !completion_options.empty();
+ if (ignored) {
+ ScriptCodeCompletionOption::Kind kind = ScriptCodeCompletionOption::KIND_PLAIN_TEXT;
+ const ScriptCodeCompletionOption *previous_option = NULL;
+ for (int i = 0; i < completion_options.size(); i++) {
+ const ScriptCodeCompletionOption &current_option = completion_options[i];
+ if (!previous_option) {
+ previous_option = &current_option;
+ kind = current_option.kind;
+ }
+ if (previous_option->kind != current_option.kind) {
+ ignored = false;
+ break;
+ }
+ }
+ ignored = ignored && (kind == ScriptCodeCompletionOption::KIND_FILE_PATH || kind == ScriptCodeCompletionOption::KIND_NODE_PATH || kind == ScriptCodeCompletionOption::KIND_SIGNAL);
+ }
+
+ if (!ignored) {
+ if (ofs > 0 && (inquote || _is_completable(l[ofs - 1]) || completion_prefixes.has(String::chr(l[ofs - 1]))))
+ emit_signal("request_completion");
+ else if (ofs > 1 && l[ofs - 1] == ' ' && completion_prefixes.has(String::chr(l[ofs - 2]))) // Make it work with a space too, it's good enough.
+ emit_signal("request_completion");
+ }
}
void TextEdit::set_code_hint(const String &p_hint) {
@@ -6220,9 +6564,21 @@ void TextEdit::set_line(int line, String new_text) {
}
void TextEdit::insert_at(const String &p_text, int at) {
- cursor_set_column(0);
- cursor_set_line(at, false, true);
_insert_text(at, 0, p_text + "\n");
+ if (cursor.line >= at) {
+ // offset cursor when located after inserted line
+ ++cursor.line;
+ }
+ if (is_selection_active()) {
+ if (selection.from_line >= at) {
+ // offset selection when located after inserted line
+ ++selection.from_line;
+ ++selection.to_line;
+ } else if (selection.to_line >= at) {
+ // extend selection that includes inserted line
+ ++selection.to_line;
+ }
+ }
}
void TextEdit::set_show_line_numbers(bool p_show) {
@@ -6314,6 +6670,24 @@ int TextEdit::get_info_gutter_width() const {
return info_gutter_width;
}
+void TextEdit::set_draw_minimap(bool p_draw) {
+ draw_minimap = p_draw;
+ update();
+}
+
+bool TextEdit::is_drawing_minimap() const {
+ return draw_minimap;
+}
+
+void TextEdit::set_minimap_width(int p_minimap_width) {
+ minimap_width = p_minimap_width;
+ update();
+}
+
+int TextEdit::get_minimap_width() const {
+ return minimap_width;
+}
+
void TextEdit::set_hiding_enabled(bool p_enabled) {
if (!p_enabled)
unhide_all_lines();
@@ -6443,8 +6817,6 @@ void TextEdit::_bind_methods() {
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);
ClassDB::bind_method(D_METHOD("is_context_menu_enabled"), &TextEdit::is_context_menu_enabled);
@@ -6520,6 +6892,11 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_breakpoints"), &TextEdit::get_breakpoints_array);
ClassDB::bind_method(D_METHOD("remove_breakpoints"), &TextEdit::remove_breakpoints);
+ ClassDB::bind_method(D_METHOD("draw_minimap", "draw"), &TextEdit::set_draw_minimap);
+ ClassDB::bind_method(D_METHOD("is_drawing_minimap"), &TextEdit::is_drawing_minimap);
+ ClassDB::bind_method(D_METHOD("set_minimap_width", "width"), &TextEdit::set_minimap_width);
+ ClassDB::bind_method(D_METHOD("get_minimap_width"), &TextEdit::get_minimap_width);
+
ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT), "set_text", "get_text");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "readonly"), "set_readonly", "is_readonly");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_current_line"), "set_highlight_current_line", "is_highlight_current_line_enabled");
@@ -6536,7 +6913,10 @@ void TextEdit::_bind_methods() {
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_enabled"), "set_wrap_enabled", "is_wrap_enabled");
- // ADD_PROPERTY(PropertyInfo(Variant::BOOL, "max_chars"), "set_max_chars", "get_max_chars");
+
+ ADD_GROUP("Minimap", "minimap_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "minimap_draw"), "draw_minimap", "is_drawing_minimap");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "minimap_width"), "set_minimap_width", "get_minimap_width");
ADD_GROUP("Caret", "caret_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_block_mode"), "cursor_set_block_mode", "cursor_is_block_mode");
@@ -6561,7 +6941,7 @@ void TextEdit::_bind_methods() {
BIND_ENUM_CONSTANT(MENU_MAX);
GLOBAL_DEF("gui/timers/text_edit_idle_detect_sec", 3);
- ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/text_edit_idle_detect_sec", PropertyInfo(Variant::REAL, "gui/timers/text_edit_idle_detect_sec", PROPERTY_HINT_RANGE, "0,10,0.01,or_greater")); // No negative numbers
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/text_edit_idle_detect_sec", PropertyInfo(Variant::REAL, "gui/timers/text_edit_idle_detect_sec", PROPERTY_HINT_RANGE, "0,10,0.01,or_greater")); // No negative numbers.
}
TextEdit::TextEdit() {
@@ -6592,8 +6972,6 @@ TextEdit::TextEdit() {
indent_size = 4;
text.set_indent_size(indent_size);
text.clear();
- //text.insert(1,"Mongolia...");
- //text.insert(2,"PAIS GENEROSO!!");
text.set_color_regions(&color_regions);
h_scroll = memnew(HScrollBar);
@@ -6676,13 +7054,23 @@ TextEdit::TextEdit() {
select_identifiers_enabled = false;
smooth_scroll_enabled = false;
scrolling = false;
+ minimap_clicked = false;
+ dragging_minimap = false;
+ can_drag_minimap = false;
+ minimap_scroll_ratio = 0;
+ minimap_scroll_click_pos = 0;
+ dragging_selection = false;
target_v_scroll = 0;
v_scroll_speed = 80;
+ draw_minimap = false;
+ minimap_width = 80;
+ minimap_char_size = Point2(1, 2);
+ minimap_line_spacing = 1;
context_menu_enabled = true;
menu = memnew(PopupMenu);
add_child(menu);
- readonly = true; // initialise to opposite first, so we get past the early-out in set_readonly
+ readonly = true; // Initialise to opposite first, so we get past the early-out in set_readonly.
set_readonly(false);
menu->connect("id_pressed", this, "menu_option");
first_draw = true;
@@ -6696,8 +7084,14 @@ TextEdit::~TextEdit() {
///////////////////////////////////////////////////////////////////////////////
Map<int, TextEdit::HighlighterInfo> TextEdit::_get_line_syntax_highlighting(int p_line) {
+ if (syntax_highlighting_cache.has(p_line)) {
+ return syntax_highlighting_cache[p_line];
+ }
+
if (syntax_highlighter != NULL) {
- return syntax_highlighter->_get_line_syntax_highlighting(p_line);
+ Map<int, HighlighterInfo> color_map = syntax_highlighter->_get_line_syntax_highlighting(p_line);
+ syntax_highlighting_cache[p_line] = color_map;
+ return color_map;
}
Map<int, HighlighterInfo> color_map;
@@ -6743,14 +7137,14 @@ Map<int, TextEdit::HighlighterInfo> TextEdit::_get_line_syntax_highlighting(int
bool is_symbol = _is_symbol(str[j]);
bool is_number = _is_number(str[j]);
- // allow ABCDEF in hex notation
+ // Allow ABCDEF in hex notation.
if (is_hex_notation && (_is_hex_symbol(str[j]) || is_number)) {
is_number = true;
} else {
is_hex_notation = false;
}
- // check for dot or underscore or 'x' for hex notation in floating point number or 'e' for scientific notation
+ // Check for dot or underscore or 'x' for hex notation in floating point number or 'e' for scientific notation.
if ((str[j] == '.' || str[j] == 'x' || str[j] == '_' || str[j] == 'f' || str[j] == 'e') && !in_word && prev_is_number && !is_number) {
is_number = true;
is_symbol = false;
@@ -6780,7 +7174,7 @@ Map<int, TextEdit::HighlighterInfo> TextEdit::_get_line_syntax_highlighting(int
if (!cri.end) {
in_region = cri.region;
}
- } else if (in_region == cri.region && !color_regions[cri.region].line_only) { //ignore otherwise
+ } else if (in_region == cri.region && !color_regions[cri.region].line_only) { // Ignore otherwise.
if (cri.end || color_regions[cri.region].eq) {
deregion = color_regions[cri.region].eq ? color_regions[cri.region].begin_key.length() : color_regions[cri.region].end_key.length();
}
@@ -6808,7 +7202,7 @@ Map<int, TextEdit::HighlighterInfo> TextEdit::_get_line_syntax_highlighting(int
if (col) {
for (int k = j - 1; k >= 0; k--) {
if (str[k] == '.') {
- col = NULL; //member indexing not allowed
+ col = NULL; // Member indexing not allowed.
break;
} else if (str[k] > 32) {
break;
@@ -6830,7 +7224,7 @@ Map<int, TextEdit::HighlighterInfo> TextEdit::_get_line_syntax_highlighting(int
k++;
}
- // check for space between name and bracket
+ // Check for space between name and bracket.
while (k < str.length() && (str[k] == '\t' || str[k] == ' ')) {
k++;
}
@@ -6879,6 +7273,7 @@ Map<int, TextEdit::HighlighterInfo> TextEdit::_get_line_syntax_highlighting(int
}
}
+ syntax_highlighting_cache[p_line] = color_map;
return color_map;
}
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index b47dac0902..9c568acd93 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -211,9 +211,11 @@ private:
int breakpoint_gutter_width;
int fold_gutter_width;
int info_gutter_width;
+ int minimap_width;
} cache;
Map<int, int> color_region_cache;
+ Map<int, Map<int, HighlighterInfo> > syntax_highlighting_cache;
struct TextOperation {
@@ -313,6 +315,10 @@ private:
bool hiding_enabled;
bool draw_info_gutter;
int info_gutter_width;
+ bool draw_minimap;
+ int minimap_width;
+ Point2 minimap_char_size;
+ int minimap_line_spacing;
bool highlight_all_occurrences;
bool scroll_past_end_of_file_enabled;
@@ -326,6 +332,12 @@ private:
bool smooth_scroll_enabled;
bool scrolling;
+ bool dragging_selection;
+ bool dragging_minimap;
+ bool can_drag_minimap;
+ bool minimap_clicked;
+ double minimap_scroll_ratio;
+ double minimap_scroll_click_pos;
float target_v_scroll;
float v_scroll_speed;
@@ -360,6 +372,8 @@ private:
int get_visible_rows() const;
int get_total_visible_rows() const;
+ int _get_minimap_visible_rows() const;
+
void update_cursor_wrap_offset();
void _update_wrap_at();
bool line_wraps(int line) const;
@@ -395,6 +409,8 @@ private:
void _update_selection_mode_word();
void _update_selection_mode_line();
+ void _update_minimap_click();
+ void _update_minimap_drag();
void _scroll_up(real_t p_delta);
void _scroll_down(real_t p_delta);
@@ -406,6 +422,7 @@ private:
//void mouse_motion(const Point& p_pos, const Point& p_rel, int p_button_mask);
Size2 get_minimum_size() const;
+ int _get_control_height() const;
int get_row_height() const;
@@ -484,6 +501,7 @@ public:
virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const;
void _get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) const;
+ void _get_minimap_mouse_row(const Point2i &p_mouse, int &r_row) const;
//void delete_char();
//void delete_line();
@@ -697,6 +715,12 @@ public:
void set_info_gutter_width(int p_gutter_width);
int get_info_gutter_width() const;
+ void set_draw_minimap(bool p_draw);
+ bool is_drawing_minimap() const;
+
+ void set_minimap_width(int p_minimap_width);
+ int get_minimap_width() const;
+
void set_hiding_enabled(bool p_enabled);
bool is_hiding_enabled() const;
diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp
index b5f949aeb7..e9b0bd8f38 100644
--- a/scene/gui/texture_button.cpp
+++ b/scene/gui/texture_button.cpp
@@ -205,24 +205,26 @@ void TextureButton::_notification(int p_what) {
case STRETCH_KEEP_ASPECT_COVERED: {
size = get_size();
Size2 tex_size = texdraw->get_size();
- Size2 scaleSize(size.width / tex_size.width, size.height / tex_size.height);
- float scale = scaleSize.width > scaleSize.height ? scaleSize.width : scaleSize.height;
- Size2 scaledTexSize = tex_size * scale;
- Point2 ofs2 = ((scaledTexSize - size) / scale).abs() / 2.0f;
+ Size2 scale_size(size.width / tex_size.width, size.height / tex_size.height);
+ float scale = scale_size.width > scale_size.height ? scale_size.width : scale_size.height;
+ Size2 scaled_tex_size = tex_size * scale;
+ Point2 ofs2 = ((scaled_tex_size - size) / scale).abs() / 2.0f;
_texture_region = Rect2(ofs2, size / scale);
} break;
}
}
+
_position_rect = Rect2(ofs, size);
- if (_tile)
+ if (_tile) {
draw_texture_rect(texdraw, _position_rect, _tile);
- else
+ } else {
draw_texture_rect_region(texdraw, _position_rect, _texture_region);
+ }
} else {
_position_rect = Rect2();
}
- if (has_focus() && focused.is_valid()) {
+ if (has_focus() && focused.is_valid()) {
draw_texture_rect(focused, _position_rect, false);
};
} break;
diff --git a/scene/gui/texture_rect.h b/scene/gui/texture_rect.h
index 3ab35324e5..1c5bd9d99c 100644
--- a/scene/gui/texture_rect.h
+++ b/scene/gui/texture_rect.h
@@ -32,9 +32,7 @@
#define TEXTURE_FRAME_H
#include "scene/gui/control.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
+
class TextureRect : public Control {
GDCLASS(TextureRect, Control);
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 146f090041..2a18436a5e 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -224,14 +224,14 @@ Rect2 TreeItem::get_icon_region(int p_column) const {
return cells[p_column].icon_region;
}
-void TreeItem::set_icon_color(int p_column, const Color &p_icon_color) {
+void TreeItem::set_icon_modulate(int p_column, const Color &p_modulate) {
ERR_FAIL_INDEX(p_column, cells.size());
- cells.write[p_column].icon_color = p_icon_color;
+ cells.write[p_column].icon_color = p_modulate;
_changed_notify(p_column);
}
-Color TreeItem::get_icon_color(int p_column) const {
+Color TreeItem::get_icon_modulate(int p_column) const {
ERR_FAIL_INDEX_V(p_column, cells.size(), Color());
return cells[p_column].icon_color;
@@ -744,6 +744,9 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_icon_max_width", "column", "width"), &TreeItem::set_icon_max_width);
ClassDB::bind_method(D_METHOD("get_icon_max_width", "column"), &TreeItem::get_icon_max_width);
+ ClassDB::bind_method(D_METHOD("set_icon_modulate", "column", "modulate"), &TreeItem::set_icon_modulate);
+ ClassDB::bind_method(D_METHOD("get_icon_modulate", "column"), &TreeItem::get_icon_modulate);
+
ClassDB::bind_method(D_METHOD("set_range", "column", "value"), &TreeItem::set_range);
ClassDB::bind_method(D_METHOD("get_range", "column"), &TreeItem::get_range);
ClassDB::bind_method(D_METHOD("set_range_config", "column", "min", "max", "step", "expr"), &TreeItem::set_range_config, DEFVAL(false));
@@ -1258,10 +1261,9 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
check_ofs.y += Math::floor((real_t)(item_rect.size.y - checked->get_height()) / 2);
if (p_item->cells[i].checked) {
-
- checked->draw(ci, check_ofs, icon_col);
+ checked->draw(ci, check_ofs);
} else {
- unchecked->draw(ci, check_ofs, icon_col);
+ unchecked->draw(ci, check_ofs);
}
int check_w = checked->get_width() + cache.hseparation;
@@ -1273,8 +1275,6 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
draw_item_rect(p_item->cells[i], item_rect, col, icon_col);
- //font->draw( ci, text_pos, p_item->cells[i].text, col,item_rect.size.x-check_w );
-
} break;
case TreeItem::CELL_MODE_RANGE: {
if (p_item->cells[i].text != "") {
@@ -1304,18 +1304,16 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
font->draw(ci, text_pos, s, col, item_rect.size.x - downarrow->get_width());
- //?
Point2i arrow_pos = item_rect.position;
arrow_pos.x += item_rect.size.x - downarrow->get_width();
arrow_pos.y += Math::floor(((item_rect.size.y - downarrow->get_height())) / 2.0);
- downarrow->draw(ci, arrow_pos, icon_col);
+ downarrow->draw(ci, arrow_pos);
} else {
Ref<Texture> updown = cache.updown;
String valtext = String::num(p_item->cells[i].val, Math::range_step_decimals(p_item->cells[i].step));
- //String valtext = rtos( p_item->cells[i].val );
if (p_item->cells[i].suffix != String())
valtext += " " + p_item->cells[i].suffix;
@@ -1329,7 +1327,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
updown_pos.x += item_rect.size.x - updown->get_width();
updown_pos.y += Math::floor(((item_rect.size.y - updown->get_height())) / 2.0);
- updown->draw(ci, updown_pos, icon_col);
+ updown->draw(ci, updown_pos);
}
} break;
@@ -1347,13 +1345,10 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
icon_ofs += item_rect.position;
draw_texture_rect(p_item->cells[i].icon, Rect2(icon_ofs, icon_size), false, icon_col);
- //p_item->cells[i].icon->draw(ci, icon_ofs);
} break;
case TreeItem::CELL_MODE_CUSTOM: {
- //int option = (int)p_item->cells[i].val;
-
if (p_item->cells[i].custom_draw_obj) {
Object *cdo = ObjectDB::get_instance(p_item->cells[i].custom_draw_obj);
@@ -1428,10 +1423,6 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
arrow->draw(ci, p_pos + p_draw_ofs + Point2i(0, (label_h - arrow->get_height()) / 2) - cache.offset);
}
- //separator
- //get_painter()->draw_fill_rect( Point2i(0,pos.y),Size2i(get_size().width,1),color( COLOR_TREE_GRID) );
-
- //pos=p_pos; //reset pos
}
Point2 children_pos = p_pos;
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index b6cdab766f..fdc6da5055 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -37,10 +37,6 @@
#include "scene/gui/scroll_bar.h"
#include "scene/gui/slider.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-
class Tree;
class TreeItem : public Object {
@@ -197,8 +193,8 @@ public:
void set_icon_region(int p_column, const Rect2 &p_icon_region);
Rect2 get_icon_region(int p_column) const;
- void set_icon_color(int p_column, const Color &p_icon_color);
- Color get_icon_color(int p_column) const;
+ void set_icon_modulate(int p_column, const Color &p_modulate);
+ Color get_icon_modulate(int p_column) const;
void set_icon_max_width(int p_column, int p_max);
int get_icon_max_width(int p_column) const;
diff --git a/scene/gui/viewport_container.cpp b/scene/gui/viewport_container.cpp
index 3f7a110c1b..35696a0459 100644
--- a/scene/gui/viewport_container.cpp
+++ b/scene/gui/viewport_container.cpp
@@ -211,4 +211,5 @@ ViewportContainer::ViewportContainer() {
stretch = false;
shrink = 1;
set_process_input(true);
+ set_process_unhandled_input(true);
}
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index e21e47f8a8..6c922adbd2 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -60,10 +60,10 @@ Error HTTPRequest::_parse_url(const String &p_url) {
use_ssl = true;
port = 443;
} else {
- ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Malformed URL.");
+ ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Malformed URL: " + url + ".");
}
- ERR_FAIL_COND_V_MSG(url.length() < 1, ERR_INVALID_PARAMETER, "URL too short.");
+ ERR_FAIL_COND_V_MSG(url.length() < 1, ERR_INVALID_PARAMETER, "URL too short: " + url + ".");
int slash_pos = url.find("/");
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 0aaba5491a..bd01ca2886 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -1716,14 +1716,17 @@ void Node::get_groups(List<GroupInfo> *p_groups) const {
}
}
-bool Node::has_persistent_groups() const {
+int Node::get_persistent_group_count() const {
+
+ int count = 0;
for (const Map<StringName, GroupData>::Element *E = data.grouped.front(); E; E = E->next()) {
- if (E->get().persistent)
- return true;
+ if (E->get().persistent) {
+ count += 1;
+ }
}
- return false;
+ return count;
}
void Node::_print_tree_pretty(const String &prefix, const bool last) {
@@ -1872,6 +1875,19 @@ String Node::get_filename() const {
return data.filename;
}
+void Node::set_editor_description(const String &p_editor_description) {
+
+ set_meta("_editor_description_", p_editor_description);
+}
+String Node::get_editor_description() const {
+
+ if (has_meta("_editor_description_")) {
+ return get_meta("_editor_description_");
+ } else {
+ return "";
+ }
+}
+
void Node::set_editable_instance(Node *p_node, bool p_editable) {
ERR_FAIL_NULL(p_node);
@@ -2785,6 +2801,10 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("rpc_config", "method", "mode"), &Node::rpc_config);
ClassDB::bind_method(D_METHOD("rset_config", "property", "mode"), &Node::rset_config);
+ ClassDB::bind_method(D_METHOD("_set_editor_description", "editor_description"), &Node::set_editor_description);
+ ClassDB::bind_method(D_METHOD("_get_editor_description"), &Node::get_editor_description);
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "editor_description", PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_editor_description", "_get_editor_description");
+
ClassDB::bind_method(D_METHOD("_set_import_path", "import_path"), &Node::set_import_path);
ClassDB::bind_method(D_METHOD("_get_import_path"), &Node::get_import_path);
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "_import_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_import_path", "_get_import_path");
@@ -2857,10 +2877,6 @@ void Node::_bind_methods() {
ADD_SIGNAL(MethodInfo("tree_exiting"));
ADD_SIGNAL(MethodInfo("tree_exited"));
- //ADD_PROPERTY( PropertyInfo( Variant::BOOL, "process/process" ),"set_process","is_processing") ;
- //ADD_PROPERTY( PropertyInfo( Variant::BOOL, "process/physics_process" ), "set_physics_process","is_physics_processing") ;
- //ADD_PROPERTY( PropertyInfo( Variant::BOOL, "process/input" ), "set_process_input","is_processing_input" ) ;
- //ADD_PROPERTY( PropertyInfo( Variant::BOOL, "process/unhandled_input" ), "set_process_unhandled_input","is_processing_unhandled_input" ) ;
ADD_GROUP("Pause", "pause_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "pause_mode", PROPERTY_HINT_ENUM, "Inherit,Stop,Process"), "set_pause_mode", "get_pause_mode");
@@ -2884,9 +2900,6 @@ void Node::_bind_methods() {
BIND_VMETHOD(MethodInfo("_unhandled_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
BIND_VMETHOD(MethodInfo("_unhandled_key_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEventKey")));
BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_configuration_warning"));
-
- //ClassDB::bind_method(D_METHOD("get_child",&Node::get_child,PH("index")));
- //ClassDB::bind_method(D_METHOD("get_node",&Node::get_node,PH("path")));
}
String Node::_get_name_num_separator() {
diff --git a/scene/main/node.h b/scene/main/node.h
index 982bfcd620..51a1436014 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -300,7 +300,7 @@ public:
};
void get_groups(List<GroupInfo> *p_groups) const;
- bool has_persistent_groups() const;
+ int get_persistent_group_count() const;
void move_child(Node *p_child, int p_pos);
void raise();
@@ -318,6 +318,9 @@ public:
void set_filename(const String &p_filename);
String get_filename() const;
+ void set_editor_description(const String &p_editor_description);
+ String get_editor_description() const;
+
void set_editable_instance(Node *p_node, bool p_editable);
bool is_editable_instance(const Node *p_node) const;
void set_editable_instances(const HashMap<NodePath, int> &p_editable_instances);
@@ -363,8 +366,6 @@ public:
Node *duplicate_from_editor(Map<const Node *, Node *> &r_duplimap) const;
#endif
- //Node *clone_tree() const;
-
// used by editors, to save what has changed only
void set_scene_instance_state(const Ref<SceneState> &p_state);
Ref<SceneState> get_scene_instance_state() const;
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 98d63650d3..6c89016ea3 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -33,6 +33,7 @@
#include "core/io/marshalls.h"
#include "core/io/resource_loader.h"
#include "core/message_queue.h"
+#include "core/os/dir_access.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/print_string.h"
@@ -1673,6 +1674,12 @@ void SceneTree::drop_files(const Vector<String> &p_files, int p_from_screen) {
MainLoop::drop_files(p_files, p_from_screen);
}
+void SceneTree::global_menu_action(const Variant &p_id, const Variant &p_meta) {
+
+ emit_signal("global_menu_action", p_id, p_meta);
+ MainLoop::global_menu_action(p_id, p_meta);
+}
+
Ref<SceneTreeTimer> SceneTree::create_timer(float p_delay_sec, bool p_process_pause) {
Ref<SceneTreeTimer> stt;
@@ -1894,6 +1901,7 @@ void SceneTree::_bind_methods() {
ADD_SIGNAL(MethodInfo("physics_frame"));
ADD_SIGNAL(MethodInfo("files_dropped", PropertyInfo(Variant::POOL_STRING_ARRAY, "files"), PropertyInfo(Variant::INT, "screen")));
+ ADD_SIGNAL(MethodInfo("global_menu_action", PropertyInfo(Variant::NIL, "id"), PropertyInfo(Variant::NIL, "meta")));
ADD_SIGNAL(MethodInfo("network_peer_connected", PropertyInfo(Variant::INT, "id")));
ADD_SIGNAL(MethodInfo("network_peer_disconnected", PropertyInfo(Variant::INT, "id")));
ADD_SIGNAL(MethodInfo("connected_to_server"));
@@ -1946,6 +1954,38 @@ bool SceneTree::is_using_font_oversampling() const {
return use_font_oversampling;
}
+void SceneTree::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
+
+ if (p_function == "change_scene") {
+ DirAccessRef dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ List<String> directories;
+ directories.push_back(dir_access->get_current_dir());
+
+ while (!directories.empty()) {
+ dir_access->change_dir(directories.back()->get());
+ directories.pop_back();
+
+ dir_access->list_dir_begin();
+ String filename = dir_access->get_next();
+
+ while (filename != "") {
+ if (filename == "." || filename == "..") {
+ filename = dir_access->get_next();
+ continue;
+ }
+
+ if (dir_access->dir_exists(filename)) {
+ directories.push_back(dir_access->get_current_dir().plus_file(filename));
+ } else if (filename.ends_with(".tscn") || filename.ends_with(".scn")) {
+ r_options->push_back("\"" + dir_access->get_current_dir().plus_file(filename) + "\"");
+ }
+
+ filename = dir_access->get_next();
+ }
+ }
+ }
+}
+
SceneTree::SceneTree() {
if (singleton == NULL) singleton = this;
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index 98f2fe5e35..d387886d61 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -39,10 +39,6 @@
#include "scene/resources/world.h"
#include "scene/resources/world_2d.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-
class PackedScene;
class Node;
class Viewport;
@@ -411,6 +407,8 @@ public:
static SceneTree *get_singleton() { return singleton; }
void drop_files(const Vector<String> &p_files, int p_from_screen = 0);
+ void global_menu_action(const Variant &p_id, const Variant &p_meta);
+ void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const;
//network API
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 93eea2ad0b..b5c82ce4e3 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -2289,32 +2289,34 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (from && p_event->is_pressed()) {
Control *next = NULL;
- if (p_event->is_action_pressed("ui_focus_next")) {
+ Input *input = Input::get_singleton();
+
+ if (p_event->is_action_pressed("ui_focus_next") && input->is_action_just_pressed("ui_focus_next")) {
next = from->find_next_valid_focus();
}
- if (p_event->is_action_pressed("ui_focus_prev")) {
+ if (p_event->is_action_pressed("ui_focus_prev") && input->is_action_just_pressed("ui_focus_prev")) {
next = from->find_prev_valid_focus();
}
- if (!mods && p_event->is_action_pressed("ui_up")) {
+ if (!mods && p_event->is_action_pressed("ui_up") && input->is_action_just_pressed("ui_up")) {
next = from->_get_focus_neighbour(MARGIN_TOP);
}
- if (!mods && p_event->is_action_pressed("ui_left")) {
+ if (!mods && p_event->is_action_pressed("ui_left") && input->is_action_just_pressed("ui_left")) {
next = from->_get_focus_neighbour(MARGIN_LEFT);
}
- if (!mods && p_event->is_action_pressed("ui_right")) {
+ if (!mods && p_event->is_action_pressed("ui_right") && input->is_action_just_pressed("ui_right")) {
next = from->_get_focus_neighbour(MARGIN_RIGHT);
}
- if (!mods && p_event->is_action_pressed("ui_down")) {
+ if (!mods && p_event->is_action_pressed("ui_down") && input->is_action_just_pressed("ui_down")) {
next = from->_get_focus_neighbour(MARGIN_BOTTOM);
}
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index b7160d5139..6393785b22 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -36,9 +36,6 @@
#include "scene/resources/texture.h"
#include "scene/resources/world_2d.h"
#include "servers/visual_server.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
class Camera;
class Camera2D;
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index fd7cd3c17b..06d84302a3 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -304,6 +304,7 @@ void register_scene_types() {
ClassDB::register_class<TextureRect>();
ClassDB::register_class<ColorRect>();
ClassDB::register_class<NinePatchRect>();
+ ClassDB::register_class<ReferenceRect>();
ClassDB::register_class<TabContainer>();
ClassDB::register_class<Tabs>();
ClassDB::register_virtual_class<Separator>();
@@ -339,7 +340,6 @@ void register_scene_types() {
ClassDB::register_virtual_class<TreeItem>();
ClassDB::register_class<OptionButton>();
ClassDB::register_class<SpinBox>();
- ClassDB::register_class<ReferenceRect>();
ClassDB::register_class<ColorPicker>();
ClassDB::register_class<ColorPickerButton>();
ClassDB::register_class<RichTextLabel>();
@@ -475,6 +475,7 @@ void register_scene_types() {
ClassDB::register_class<Shader>();
ClassDB::register_class<VisualShader>();
ClassDB::register_virtual_class<VisualShaderNode>();
+ ClassDB::register_class<VisualShaderNodeCustom>();
ClassDB::register_class<VisualShaderNodeInput>();
ClassDB::register_virtual_class<VisualShaderNodeOutput>();
ClassDB::register_class<VisualShaderNodeGroupBase>();
@@ -529,6 +530,7 @@ void register_scene_types() {
ClassDB::register_class<VisualShaderNodeSwitch>();
ClassDB::register_class<VisualShaderNodeFresnel>();
ClassDB::register_class<VisualShaderNodeExpression>();
+ ClassDB::register_class<VisualShaderNodeGlobalExpression>();
ClassDB::register_class<VisualShaderNodeIs>();
ClassDB::register_class<VisualShaderNodeCompare>();
diff --git a/scene/register_scene_types.h b/scene/register_scene_types.h
index 3645f88807..b551ad2ac4 100644
--- a/scene/register_scene_types.h
+++ b/scene/register_scene_types.h
@@ -31,10 +31,6 @@
#ifndef REGISTER_SCENE_TYPES_H
#define REGISTER_SCENE_TYPES_H
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-
void register_scene_types();
void unregister_scene_types();
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 8c8552ac54..985b38f913 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -2870,9 +2870,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons
const Vector3 &v1 = t1.value.loc;
const Vector3 &v2 = t2.value.loc;
- if (Math::is_zero_approx(v0.distance_to(v2))) {
+ if (v0 == v2) {
//0 and 2 are close, let's see if 1 is close
- if (!Math::is_zero_approx(v0.distance_to(v1))) {
+ if (v0 != v1) {
//not close, not optimizable
return false;
}
@@ -2959,9 +2959,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons
const Vector3 &v1 = t1.value.scale;
const Vector3 &v2 = t2.value.scale;
- if (Math::is_zero_approx(v0.distance_to(v2))) {
+ if (v0 == v2) {
//0 and 2 are close, let's see if 1 is close
- if (!Math::is_zero_approx(v0.distance_to(v1))) {
+ if (v0 != v1) {
//not close, not optimizable
return false;
}
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index 6fff77d746..d59dfab2c8 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -32,9 +32,7 @@
#define ANIMATION_H
#include "core/resource.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
+
class Animation : public Resource {
GDCLASS(Animation, Resource);
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index fb0fb4f8e3..d761eb01fe 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -611,6 +611,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_font("title_font", "GraphNode", default_font);
theme->set_color("title_color", "GraphNode", Color(0, 0, 0, 1));
theme->set_color("close_color", "GraphNode", Color(0, 0, 0, 1));
+ theme->set_color("resizer_color", "GraphNode", Color(0, 0, 0, 1));
theme->set_constant("title_offset", "GraphNode", 20 * scale);
theme->set_constant("close_offset", "GraphNode", 18 * scale);
theme->set_constant("port_offset", "GraphNode", 3 * scale);
@@ -760,6 +761,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// FileDialog
theme->set_icon("folder", "FileDialog", make_icon(icon_folder_png));
+ theme->set_color("folder_icon_modulate", "FileDialog", Color(1, 1, 1));
theme->set_color("files_disabled", "FileDialog", Color(0, 0, 0, 0.7));
// colorPicker
@@ -892,8 +894,9 @@ void make_default_theme(bool p_hidpi, Ref<Font> p_font) {
void clear_default_theme() {
- Theme::set_default(Ref<Theme>());
- Theme::set_default_icon(Ref<Texture>());
- Theme::set_default_style(Ref<StyleBox>());
- Theme::set_default_font(Ref<Font>());
+ Theme::set_project_default(NULL);
+ Theme::set_default(NULL);
+ Theme::set_default_icon(NULL);
+ Theme::set_default_style(NULL);
+ Theme::set_default_font(NULL);
}
diff --git a/scene/resources/default_theme/default_theme.h b/scene/resources/default_theme/default_theme.h
index cbf0cc1b79..e7d80ffb3d 100644
--- a/scene/resources/default_theme/default_theme.h
+++ b/scene/resources/default_theme/default_theme.h
@@ -32,9 +32,6 @@
#define DEFAULT_THEME_H
#include "scene/resources/theme.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<Font> &large_font, Ref<Texture> &default_icon, Ref<StyleBox> &default_style, float p_scale);
void make_default_theme(bool p_hidpi, Ref<Font> p_font);
diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp
index df8d4a7fed..2364a4a8a3 100644
--- a/scene/resources/dynamic_font.cpp
+++ b/scene/resources/dynamic_font.cpp
@@ -193,14 +193,6 @@ Error DynamicFontAtSize::_load() {
ERR_FAIL_COND_V(error, ERR_FILE_CANT_OPEN);
- /*error = FT_Set_Char_Size(face,0,64*size,512,512);
-
- if ( error ) {
- FT_Done_FreeType( library );
- ERR_EXPLAIN(TTR("Invalid font size."));
- ERR_FAIL_COND_V( error, ERR_INVALID_PARAMETER );
- }*/
-
if (FT_HAS_COLOR(face)) {
int best_match = 0;
int diff = ABS(id.size - ((int64_t)face->available_sizes[0].width));
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index 0f0974114f..afb7f1102b 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -1399,7 +1399,7 @@ Environment::Environment() :
fog_depth_enabled = true;
fog_depth_begin = 10;
- fog_depth_end = 0;
+ fog_depth_end = 100;
fog_depth_curve = 1;
fog_transmit_enabled = false;
diff --git a/scene/resources/font.h b/scene/resources/font.h
index 436ed43c42..9b99b85d22 100644
--- a/scene/resources/font.h
+++ b/scene/resources/font.h
@@ -34,9 +34,6 @@
#include "core/map.h"
#include "core/resource.h"
#include "scene/resources/texture.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
class Font : public Resource {
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index daa51aabd7..0de462d616 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -1772,7 +1772,7 @@ SpatialMaterial::TextureChannel SpatialMaterial::get_refraction_texture_channel(
return refraction_texture_channel;
}
-RID SpatialMaterial::get_material_rid_for_2d(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass) {
+RID SpatialMaterial::get_material_rid_for_2d(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass, bool p_billboard, bool p_billboard_y) {
int version = 0;
if (p_shaded)
@@ -1785,6 +1785,10 @@ RID SpatialMaterial::get_material_rid_for_2d(bool p_shaded, bool p_transparent,
version |= 8;
if (p_double_sided)
version |= 16;
+ if (p_billboard)
+ version |= 32;
+ if (p_billboard_y)
+ version |= 64;
if (materials_for_2d[version].is_valid()) {
return materials_for_2d[version]->get_rid();
@@ -1800,6 +1804,11 @@ RID SpatialMaterial::get_material_rid_for_2d(bool p_shaded, bool p_transparent,
material->set_flag(FLAG_SRGB_VERTEX_COLOR, true);
material->set_flag(FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
material->set_flag(FLAG_USE_ALPHA_SCISSOR, p_cut_alpha);
+ if (p_billboard) {
+ material->set_billboard_mode(BILLBOARD_ENABLED);
+ } else if (p_billboard_y) {
+ material->set_billboard_mode(BILLBOARD_FIXED_Y);
+ }
materials_for_2d[version] = material;
diff --git a/scene/resources/material.h b/scene/resources/material.h
index 17e52527b3..2423d6d48b 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -37,9 +37,6 @@
#include "scene/resources/texture.h"
#include "servers/visual/shader_language.h"
#include "servers/visual_server.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
class Material : public Resource {
@@ -440,9 +437,7 @@ private:
_FORCE_INLINE_ void _validate_feature(const String &text, Feature feature, PropertyInfo &property) const;
- enum {
- MAX_MATERIALS_FOR_2D = 32
- };
+ static const int MAX_MATERIALS_FOR_2D = 128;
static Ref<SpatialMaterial> materials_for_2d[MAX_MATERIALS_FOR_2D]; //used by Sprite3D and other stuff
@@ -629,7 +624,7 @@ public:
static void finish_shaders();
static void flush_changes();
- static RID get_material_rid_for_2d(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass);
+ static RID get_material_rid_for_2d(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass, bool p_billboard = false, bool p_billboard_y = false);
RID get_shader_rid() const;
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index b38791b9a6..6b6ee8a209 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -37,9 +37,6 @@
#include "scene/resources/material.h"
#include "scene/resources/shape.h"
#include "servers/visual_server.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
class Mesh : public Resource {
GDCLASS(Mesh, Resource);
diff --git a/scene/resources/room.h b/scene/resources/room.h
index 8990056f46..2c53ea1aed 100644
--- a/scene/resources/room.h
+++ b/scene/resources/room.h
@@ -33,9 +33,6 @@
#include "core/math/bsp_tree.h"
#include "core/resource.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
// FIXME: left for reference but will be removed when portals are reimplemented using Area
#if 0
diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h
index c3965fe076..d02e107480 100644
--- a/scene/resources/style_box.h
+++ b/scene/resources/style_box.h
@@ -34,9 +34,7 @@
#include "core/resource.h"
#include "scene/resources/texture.h"
#include "servers/visual_server.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
+
class CanvasItem;
class StyleBox : public Resource {
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index eb7a9ff25c..e535f7544a 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -42,10 +42,6 @@
#include "servers/camera_server.h"
#include "servers/visual_server.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-
class Texture : public Resource {
GDCLASS(Texture, Resource);
diff --git a/scene/resources/theme.h b/scene/resources/theme.h
index d27180e9eb..187694de65 100644
--- a/scene/resources/theme.h
+++ b/scene/resources/theme.h
@@ -38,9 +38,6 @@
#include "scene/resources/style_box.h"
#include "scene/resources/texture.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
class Theme : public Resource {
GDCLASS(Theme, Resource);
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index cd0c1b5b07..e85609468b 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -117,6 +117,12 @@ void VisualShaderNode::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "output_port_for_preview"), "set_output_port_for_preview", "get_output_port_for_preview");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "default_input_values", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_default_input_values", "_get_default_input_values");
ADD_SIGNAL(MethodInfo("editor_refresh_request"));
+
+ BIND_ENUM_CONSTANT(PORT_TYPE_SCALAR);
+ BIND_ENUM_CONSTANT(PORT_TYPE_VECTOR);
+ BIND_ENUM_CONSTANT(PORT_TYPE_BOOLEAN);
+ BIND_ENUM_CONSTANT(PORT_TYPE_TRANSFORM);
+ BIND_ENUM_CONSTANT(PORT_TYPE_ICON_COLOR);
}
VisualShaderNode::VisualShaderNode() {
@@ -125,6 +131,147 @@ VisualShaderNode::VisualShaderNode() {
/////////////////////////////////////////////////////////
+void VisualShaderNodeCustom::update_ports() {
+ ERR_FAIL_COND(!get_script_instance());
+
+ input_ports.clear();
+ if (get_script_instance()->has_method("_get_input_port_count")) {
+ int input_port_count = (int)get_script_instance()->call("_get_input_port_count");
+ bool has_name = get_script_instance()->has_method("_get_input_port_name");
+ bool has_type = get_script_instance()->has_method("_get_input_port_type");
+ for (int i = 0; i < input_port_count; i++) {
+ Port port;
+ if (has_name) {
+ port.name = (String)get_script_instance()->call("_get_input_port_name", i);
+ } else {
+ port.name = "in" + itos(i);
+ }
+ if (has_type) {
+ port.type = (int)get_script_instance()->call("_get_input_port_type", i);
+ } else {
+ port.type = (int)PortType::PORT_TYPE_SCALAR;
+ }
+ input_ports.push_back(port);
+ }
+ }
+ output_ports.clear();
+ if (get_script_instance()->has_method("_get_output_port_count")) {
+ int output_port_count = (int)get_script_instance()->call("_get_output_port_count");
+ bool has_name = get_script_instance()->has_method("_get_output_port_name");
+ bool has_type = get_script_instance()->has_method("_get_output_port_type");
+ for (int i = 0; i < output_port_count; i++) {
+ Port port;
+ if (has_name) {
+ port.name = (String)get_script_instance()->call("_get_output_port_name", i);
+ } else {
+ port.name = "out" + itos(i);
+ }
+ if (has_type) {
+ port.type = (int)get_script_instance()->call("_get_output_port_type", i);
+ } else {
+ port.type = (int)PortType::PORT_TYPE_SCALAR;
+ }
+ output_ports.push_back(port);
+ }
+ }
+}
+
+String VisualShaderNodeCustom::get_caption() const {
+ ERR_FAIL_COND_V(!get_script_instance(), "");
+ if (get_script_instance()->has_method("_get_name")) {
+ return (String)get_script_instance()->call("_get_name");
+ }
+ return "Unnamed";
+}
+
+int VisualShaderNodeCustom::get_input_port_count() const {
+ return input_ports.size();
+}
+
+VisualShaderNodeCustom::PortType VisualShaderNodeCustom::get_input_port_type(int p_port) const {
+ ERR_FAIL_INDEX_V(p_port, input_ports.size(), PORT_TYPE_SCALAR);
+ return (PortType)input_ports[p_port].type;
+}
+
+String VisualShaderNodeCustom::get_input_port_name(int p_port) const {
+ ERR_FAIL_INDEX_V(p_port, input_ports.size(), "");
+ return input_ports[p_port].name;
+}
+
+int VisualShaderNodeCustom::get_output_port_count() const {
+ return output_ports.size();
+}
+
+VisualShaderNodeCustom::PortType VisualShaderNodeCustom::get_output_port_type(int p_port) const {
+ ERR_FAIL_INDEX_V(p_port, output_ports.size(), PORT_TYPE_SCALAR);
+ return (PortType)output_ports[p_port].type;
+}
+
+String VisualShaderNodeCustom::get_output_port_name(int p_port) const {
+ ERR_FAIL_INDEX_V(p_port, output_ports.size(), "");
+ return output_ports[p_port].name;
+}
+
+String VisualShaderNodeCustom::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+
+ ERR_FAIL_COND_V(!get_script_instance(), "");
+ ERR_FAIL_COND_V(!get_script_instance()->has_method("_get_code"), "");
+ Array input_vars;
+ for (int i = 0; i < get_input_port_count(); i++) {
+ input_vars.push_back(p_input_vars[i]);
+ }
+ Array output_vars;
+ for (int i = 0; i < get_output_port_count(); i++) {
+ output_vars.push_back(p_output_vars[i]);
+ }
+ String code = "\t{\n";
+ String _code = (String)get_script_instance()->call("_get_code", input_vars, output_vars, (int)p_mode, (int)p_type);
+ bool nend = _code.ends_with("\n");
+ _code = _code.insert(0, "\t\t");
+ _code = _code.replace("\n", "\n\t\t");
+ code += _code;
+ if (!nend) {
+ code += "\n\t}";
+ } else {
+ code.remove(code.size() - 1);
+ code += "}";
+ }
+ return code;
+}
+
+String VisualShaderNodeCustom::generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ ERR_FAIL_COND_V(!get_script_instance(), "");
+ if (get_script_instance()->has_method("_get_global_code")) {
+ String code = "// " + get_caption() + "\n";
+ code += (String)get_script_instance()->call("_get_global_code", (int)p_mode);
+ code += "\n";
+ return code;
+ }
+ return "";
+}
+
+void VisualShaderNodeCustom::_bind_methods() {
+
+ BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_name"));
+ BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_description"));
+ BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_category"));
+ BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_subcategory"));
+ BIND_VMETHOD(MethodInfo(Variant::INT, "_get_return_icon_type"));
+ BIND_VMETHOD(MethodInfo(Variant::INT, "_get_input_port_count"));
+ BIND_VMETHOD(MethodInfo(Variant::INT, "_get_input_port_type", PropertyInfo(Variant::INT, "port")));
+ BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_input_port_name", PropertyInfo(Variant::INT, "port")));
+ BIND_VMETHOD(MethodInfo(Variant::INT, "_get_output_port_count"));
+ BIND_VMETHOD(MethodInfo(Variant::INT, "_get_output_port_type", PropertyInfo(Variant::INT, "port")));
+ BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_output_port_name", PropertyInfo(Variant::INT, "port")));
+ BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_code", PropertyInfo(Variant::ARRAY, "input_vars"), PropertyInfo(Variant::ARRAY, "output_vars"), PropertyInfo(Variant::INT, "mode"), PropertyInfo(Variant::INT, "type")));
+ BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_global_code", PropertyInfo(Variant::INT, "mode")));
+}
+
+VisualShaderNodeCustom::VisualShaderNodeCustom() {
+}
+
+/////////////////////////////////////////////////////////
+
void VisualShader::add_node(Type p_type, const Ref<VisualShaderNode> &p_node, const Vector2 &p_position, int p_id) {
ERR_FAIL_COND(p_node.is_null());
ERR_FAIL_COND(p_id < 2);
@@ -150,6 +297,11 @@ void VisualShader::add_node(Type p_type, const Ref<VisualShaderNode> &p_node, co
n.node->connect("changed", this, "_queue_update");
+ Ref<VisualShaderNodeCustom> custom = n.node;
+ if (custom.is_valid()) {
+ custom->update_ports();
+ }
+
g->nodes[p_id] = n;
_queue_update();
@@ -460,6 +612,25 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port
global_code += String() + "shader_type canvas_item;\n";
+ String global_expressions;
+ for (int i = 0, index = 0; i < TYPE_MAX; i++) {
+ for (Map<int, Node>::Element *E = graph[i].nodes.front(); E; E = E->next()) {
+ Ref<VisualShaderNodeGlobalExpression> global_expression = Object::cast_to<VisualShaderNodeGlobalExpression>(E->get().node.ptr());
+ if (global_expression.is_valid()) {
+
+ String expr = "";
+ expr += "// " + global_expression->get_caption() + ":" + itos(index++) + "\n";
+ expr += global_expression->generate_global(get_mode(), Type(i), -1);
+ expr = expr.replace("\n", "\n\t");
+ expr += "\n";
+ global_expressions += expr;
+ }
+ }
+ }
+
+ global_code += "\n";
+ global_code += global_expressions;
+
//make it faster to go around through shader
VMap<ConnectionKey, const List<Connection>::Element *> input_connections;
VMap<ConnectionKey, const List<Connection>::Element *> output_connections;
@@ -965,6 +1136,7 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
bool skip_global = input.is_valid() && for_preview;
if (!skip_global) {
+
global_code += vsnode->generate_global(get_mode(), type, node);
if (!r_classes.has(vsnode->get_class_name())) {
@@ -976,7 +1148,6 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
}
}
- //handle normally
code += vsnode->generate_code(get_mode(), type, node, inputs, outputs, for_preview);
code += "\n"; //
@@ -1053,6 +1224,22 @@ void VisualShader::_update_shader() const {
static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light" };
+ String global_expressions;
+ for (int i = 0, index = 0; i < TYPE_MAX; i++) {
+ for (Map<int, Node>::Element *E = graph[i].nodes.front(); E; E = E->next()) {
+ Ref<VisualShaderNodeGlobalExpression> global_expression = Object::cast_to<VisualShaderNodeGlobalExpression>(E->get().node.ptr());
+ if (global_expression.is_valid()) {
+
+ String expr = "";
+ expr += "// " + global_expression->get_caption() + ":" + itos(index++) + "\n";
+ expr += global_expression->generate_global(get_mode(), Type(i), -1);
+ expr = expr.replace("\n", "\n\t");
+ expr += "\n";
+ global_expressions += expr;
+ }
+ }
+ }
+
for (int i = 0; i < TYPE_MAX; i++) {
//make it faster to go around through shader
@@ -1087,6 +1274,7 @@ void VisualShader::_update_shader() const {
global_code += "\n\n";
String final_code = global_code;
final_code += global_code_per_node;
+ final_code += global_expressions;
String tcode = code;
for (int i = 0; i < TYPE_MAX; i++) {
tcode = tcode.insert(insertion_pos[i], global_code_per_func[Type(i)]);
@@ -1097,6 +1285,10 @@ void VisualShader::_update_shader() const {
for (int i = 0; i < default_tex_params.size(); i++) {
const_cast<VisualShader *>(this)->set_default_texture_param(default_tex_params[i].name, default_tex_params[i].param);
}
+ if (previous_code != final_code) {
+ const_cast<VisualShader *>(this)->emit_signal("changed");
+ }
+ previous_code = final_code;
}
void VisualShader::_queue_update() {
@@ -2181,6 +2373,14 @@ void VisualShaderNodeGroupBase::_apply_port_changes() {
}
}
+void VisualShaderNodeGroupBase::set_editable(bool p_enabled) {
+ editable = p_enabled;
+}
+
+bool VisualShaderNodeGroupBase::is_editable() const {
+ return editable;
+}
+
void VisualShaderNodeGroupBase::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_size", "size"), &VisualShaderNodeGroupBase::set_size);
@@ -2216,6 +2416,11 @@ void VisualShaderNodeGroupBase::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_control", "control", "index"), &VisualShaderNodeGroupBase::set_control);
ClassDB::bind_method(D_METHOD("get_control", "index"), &VisualShaderNodeGroupBase::get_control);
+
+ ClassDB::bind_method(D_METHOD("set_editable", "enabled"), &VisualShaderNodeGroupBase::set_editable);
+ ClassDB::bind_method(D_METHOD("is_editable"), &VisualShaderNodeGroupBase::is_editable);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editable"), "set_editable", "is_editable");
}
String VisualShaderNodeGroupBase::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
@@ -2226,6 +2431,7 @@ VisualShaderNodeGroupBase::VisualShaderNodeGroupBase() {
size = Size2(0, 0);
inputs = "";
outputs = "";
+ editable = false;
}
////////////// Expression
@@ -2257,6 +2463,7 @@ String VisualShaderNodeExpression::generate_code(Shader::Mode p_mode, VisualShad
if (pre_symbols.empty()) {
pre_symbols.push_back("\t");
pre_symbols.push_back(",");
+ pre_symbols.push_back(";");
pre_symbols.push_back("{");
pre_symbols.push_back("[");
pre_symbols.push_back("(");
@@ -2273,9 +2480,9 @@ String VisualShaderNodeExpression::generate_code(Shader::Mode p_mode, VisualShad
static Vector<String> post_symbols;
if (post_symbols.empty()) {
- post_symbols.push_back("\0");
post_symbols.push_back("\t");
post_symbols.push_back("\n");
+ post_symbols.push_back(",");
post_symbols.push_back(";");
post_symbols.push_back("}");
post_symbols.push_back("]");
@@ -2352,4 +2559,19 @@ void VisualShaderNodeExpression::_bind_methods() {
VisualShaderNodeExpression::VisualShaderNodeExpression() {
expression = "";
+ set_editable(true);
+}
+
+////////////// Global Expression
+
+String VisualShaderNodeGlobalExpression::get_caption() const {
+ return "GlobalExpression";
+}
+
+String VisualShaderNodeGlobalExpression::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ return expression;
+}
+
+VisualShaderNodeGlobalExpression::VisualShaderNodeGlobalExpression() {
+ set_editable(false);
}
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index b3c0ab6e0b..45beb8e6ca 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -73,6 +73,7 @@ private:
} graph[TYPE_MAX];
Shader::Mode shader_mode;
+ mutable String previous_code;
Array _get_node_connections(Type p_type) const;
@@ -183,7 +184,7 @@ public:
PORT_TYPE_VECTOR,
PORT_TYPE_BOOLEAN,
PORT_TYPE_TRANSFORM,
- PORT_TYPE_COLOR // just a hint for node tree icons, do not use it as actual port type !
+ PORT_TYPE_ICON_COLOR // just a hint for node tree icons, do not use it as actual port type !
};
virtual String get_caption() const = 0;
@@ -216,6 +217,44 @@ public:
VisualShaderNode();
};
+
+VARIANT_ENUM_CAST(VisualShaderNode::PortType)
+
+class VisualShaderNodeCustom : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeCustom, VisualShaderNode);
+
+ struct Port {
+ String name;
+ int type;
+ };
+
+ List<Port> input_ports;
+ List<Port> output_ports;
+
+ friend class VisualShaderEditor;
+
+protected:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+protected:
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const;
+ virtual String generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
+
+ static void _bind_methods();
+
+public:
+ VisualShaderNodeCustom();
+ void update_ports();
+};
+
/////
class VisualShaderNodeInput : public VisualShaderNode {
@@ -333,6 +372,7 @@ protected:
Vector2 size;
String inputs;
String outputs;
+ bool editable;
struct Port {
PortType type;
@@ -388,6 +428,9 @@ public:
void set_control(Control *p_control, int p_index);
Control *get_control(int p_index);
+ void set_editable(bool p_enabled);
+ bool is_editable() const;
+
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const;
VisualShaderNodeGroupBase();
@@ -396,10 +439,9 @@ public:
class VisualShaderNodeExpression : public VisualShaderNodeGroupBase {
GDCLASS(VisualShaderNodeExpression, VisualShaderNodeGroupBase);
-private:
+protected:
String expression;
-protected:
static void _bind_methods();
public:
@@ -415,4 +457,15 @@ public:
VisualShaderNodeExpression();
};
+class VisualShaderNodeGlobalExpression : public VisualShaderNodeExpression {
+ GDCLASS(VisualShaderNodeGlobalExpression, VisualShaderNodeExpression);
+
+public:
+ virtual String get_caption() const;
+
+ virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
+
+ VisualShaderNodeGlobalExpression();
+};
+
#endif // VISUAL_SHADER_H