summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/ray_cast_2d.cpp24
-rw-r--r--scene/2d/ray_cast_2d.h6
-rw-r--r--scene/2d/tile_map.cpp25
-rw-r--r--scene/2d/tile_map.h4
-rw-r--r--scene/3d/ray_cast_3d.cpp20
-rw-r--r--scene/3d/ray_cast_3d.h6
-rw-r--r--scene/gui/base_button.cpp8
-rw-r--r--scene/gui/base_button.h6
-rw-r--r--scene/gui/code_edit.cpp444
-rw-r--r--scene/gui/code_edit.h135
-rw-r--r--scene/gui/color_picker.cpp4
-rw-r--r--scene/gui/graph_edit.cpp1
-rw-r--r--scene/gui/popup_menu.cpp24
-rw-r--r--scene/gui/popup_menu.h24
-rw-r--r--scene/gui/rich_text_label.cpp2
-rw-r--r--scene/gui/shortcut.cpp24
-rw-r--r--scene/gui/shortcut.h6
-rw-r--r--scene/gui/tabs.cpp9
-rw-r--r--scene/gui/tabs.h2
-rw-r--r--scene/gui/text_edit.cpp844
-rw-r--r--scene/gui/text_edit.h289
-rw-r--r--scene/main/canvas_item.cpp2
-rw-r--r--scene/main/canvas_item.h4
-rw-r--r--scene/main/http_request.cpp1
-rw-r--r--scene/main/scene_tree.h6
-rw-r--r--scene/main/viewport.cpp2
-rw-r--r--scene/register_scene_types.cpp17
-rw-r--r--scene/resources/default_theme/bookmark.pngbin0 -> 160 bytes
-rw-r--r--scene/resources/default_theme/default_theme.cpp51
-rw-r--r--scene/resources/default_theme/theme_data.h4
-rw-r--r--scene/resources/packed_scene.cpp4
-rw-r--r--scene/resources/particles_material.cpp6
-rw-r--r--scene/resources/particles_material.h1
-rw-r--r--scene/resources/syntax_highlighter.cpp8
-rw-r--r--scene/resources/syntax_highlighter.h2
-rw-r--r--scene/resources/texture.cpp304
-rw-r--r--scene/resources/texture.h116
-rw-r--r--scene/resources/visual_shader.cpp64
-rw-r--r--scene/resources/visual_shader.h10
-rw-r--r--scene/resources/visual_shader_nodes.cpp178
-rw-r--r--scene/resources/visual_shader_nodes.h63
41 files changed, 1989 insertions, 761 deletions
diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp
index 9fd24b5294..a00db36077 100644
--- a/scene/2d/ray_cast_2d.cpp
+++ b/scene/2d/ray_cast_2d.cpp
@@ -35,15 +35,15 @@
#include "physics_body_2d.h"
#include "servers/physics_server_2d.h"
-void RayCast2D::set_cast_to(const Vector2 &p_point) {
- cast_to = p_point;
+void RayCast2D::set_target_position(const Vector2 &p_point) {
+ target_position = p_point;
if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_collisions_hint())) {
update();
}
}
-Vector2 RayCast2D::get_cast_to() const {
- return cast_to;
+Vector2 RayCast2D::get_target_position() const {
+ return target_position;
}
void RayCast2D::set_collision_mask(uint32_t p_mask) {
@@ -160,8 +160,8 @@ void RayCast2D::_notification(int p_what) {
break;
}
Transform2D xf;
- xf.rotate(cast_to.angle());
- xf.translate(Vector2(cast_to.length(), 0));
+ xf.rotate(target_position.angle());
+ xf.translate(Vector2(target_position.length(), 0));
// Draw an arrow indicating where the RayCast is pointing to
Color draw_col = get_tree()->get_debug_collisions_color();
@@ -171,7 +171,7 @@ void RayCast2D::_notification(int p_what) {
draw_col.g = g;
draw_col.b = g;
}
- draw_line(Vector2(), cast_to, draw_col, 2);
+ draw_line(Vector2(), target_position, draw_col, 2);
Vector<Vector2> pts;
float tsize = 8;
pts.push_back(xf.xform(Vector2(tsize, 0)));
@@ -206,7 +206,7 @@ void RayCast2D::_update_raycast_state() {
Transform2D gt = get_global_transform();
- Vector2 to = cast_to;
+ Vector2 to = target_position;
if (to == Vector2()) {
to = Vector2(0, 0.01);
}
@@ -280,8 +280,8 @@ void RayCast2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &RayCast2D::set_enabled);
ClassDB::bind_method(D_METHOD("is_enabled"), &RayCast2D::is_enabled);
- ClassDB::bind_method(D_METHOD("set_cast_to", "local_point"), &RayCast2D::set_cast_to);
- ClassDB::bind_method(D_METHOD("get_cast_to"), &RayCast2D::get_cast_to);
+ ClassDB::bind_method(D_METHOD("set_target_position", "local_point"), &RayCast2D::set_target_position);
+ ClassDB::bind_method(D_METHOD("get_target_position"), &RayCast2D::get_target_position);
ClassDB::bind_method(D_METHOD("is_colliding"), &RayCast2D::is_colliding);
ClassDB::bind_method(D_METHOD("force_raycast_update"), &RayCast2D::force_raycast_update);
@@ -316,7 +316,7 @@ void RayCast2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclude_parent"), "set_exclude_parent_body", "get_exclude_parent_body");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "cast_to"), "set_cast_to", "get_cast_to");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "target_position"), "set_target_position", "get_target_position");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask");
ADD_GROUP("Collide With", "collide_with");
@@ -329,7 +329,7 @@ RayCast2D::RayCast2D() {
collided = false;
against_shape = 0;
collision_mask = 1;
- cast_to = Vector2(0, 50);
+ target_position = Vector2(0, 50);
exclude_parent_body = true;
collide_with_bodies = true;
collide_with_areas = false;
diff --git a/scene/2d/ray_cast_2d.h b/scene/2d/ray_cast_2d.h
index 6accc264a0..14932f782b 100644
--- a/scene/2d/ray_cast_2d.h
+++ b/scene/2d/ray_cast_2d.h
@@ -46,7 +46,7 @@ class RayCast2D : public Node2D {
uint32_t collision_mask;
bool exclude_parent_body;
- Vector2 cast_to;
+ Vector2 target_position;
bool collide_with_areas;
bool collide_with_bodies;
@@ -66,8 +66,8 @@ public:
void set_enabled(bool p_enabled);
bool is_enabled() const;
- void set_cast_to(const Vector2 &p_point);
- Vector2 get_cast_to() const;
+ void set_target_position(const Vector2 &p_point);
+ Vector2 get_target_position() const;
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index c7a809f6d8..c2951559a4 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -412,6 +412,9 @@ void TileMap::update_dirty_quadrants() {
vs->canvas_item_set_light_mask(canvas_item, get_light_mask());
vs->canvas_item_set_z_index(canvas_item, z_index);
+ vs->canvas_item_set_default_texture_filter(canvas_item, RS::CanvasItemTextureFilter(CanvasItem::get_texture_filter()));
+ vs->canvas_item_set_default_texture_repeat(canvas_item, RS::CanvasItemTextureRepeat(CanvasItem::get_texture_repeat()));
+
q.canvas_items.push_back(canvas_item);
if (debug_shapes) {
@@ -1687,6 +1690,28 @@ bool TileMap::get_clip_uv() const {
return clip_uv;
}
+void TileMap::set_texture_filter(TextureFilter p_texture_filter) {
+ CanvasItem::set_texture_filter(p_texture_filter);
+ for (Map<PosKey, Quadrant>::Element *F = quadrant_map.front(); F; F = F->next()) {
+ Quadrant &q = F->get();
+ for (List<RID>::Element *E = q.canvas_items.front(); E; E = E->next()) {
+ RenderingServer::get_singleton()->canvas_item_set_default_texture_filter(E->get(), RS::CanvasItemTextureFilter(p_texture_filter));
+ _make_quadrant_dirty(F);
+ }
+ }
+}
+
+void TileMap::set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) {
+ CanvasItem::set_texture_repeat(p_texture_repeat);
+ for (Map<PosKey, Quadrant>::Element *F = quadrant_map.front(); F; F = F->next()) {
+ Quadrant &q = F->get();
+ for (List<RID>::Element *E = q.canvas_items.front(); E; E = E->next()) {
+ RenderingServer::get_singleton()->canvas_item_set_default_texture_repeat(E->get(), RS::CanvasItemTextureRepeat(p_texture_repeat));
+ _make_quadrant_dirty(F);
+ }
+ }
+}
+
String TileMap::get_configuration_warning() const {
String warning = Node2D::get_configuration_warning();
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index 7a2a3e412c..b9dd8f5405 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -342,6 +342,10 @@ public:
String get_configuration_warning() const override;
+ virtual void set_texture_filter(CanvasItem::TextureFilter p_texture_filter) override;
+
+ virtual void set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) override;
+
void fix_invalid_tiles();
void clear();
diff --git a/scene/3d/ray_cast_3d.cpp b/scene/3d/ray_cast_3d.cpp
index 2a922e3cda..69f09ef569 100644
--- a/scene/3d/ray_cast_3d.cpp
+++ b/scene/3d/ray_cast_3d.cpp
@@ -35,8 +35,8 @@
#include "mesh_instance_3d.h"
#include "servers/physics_server_3d.h"
-void RayCast3D::set_cast_to(const Vector3 &p_point) {
- cast_to = p_point;
+void RayCast3D::set_target_position(const Vector3 &p_point) {
+ target_position = p_point;
if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_collisions_hint())) {
update_gizmo();
}
@@ -45,8 +45,8 @@ void RayCast3D::set_cast_to(const Vector3 &p_point) {
}
}
-Vector3 RayCast3D::get_cast_to() const {
- return cast_to;
+Vector3 RayCast3D::get_target_position() const {
+ return target_position;
}
void RayCast3D::set_collision_mask(uint32_t p_mask) {
@@ -202,7 +202,7 @@ void RayCast3D::_update_raycast_state() {
Transform gt = get_global_transform();
- Vector3 to = cast_to;
+ Vector3 to = target_position;
if (to == Vector3()) {
to = Vector3(0, 0.01, 0);
}
@@ -276,8 +276,8 @@ void RayCast3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &RayCast3D::set_enabled);
ClassDB::bind_method(D_METHOD("is_enabled"), &RayCast3D::is_enabled);
- ClassDB::bind_method(D_METHOD("set_cast_to", "local_point"), &RayCast3D::set_cast_to);
- ClassDB::bind_method(D_METHOD("get_cast_to"), &RayCast3D::get_cast_to);
+ ClassDB::bind_method(D_METHOD("set_target_position", "local_point"), &RayCast3D::set_target_position);
+ ClassDB::bind_method(D_METHOD("get_target_position"), &RayCast3D::get_target_position);
ClassDB::bind_method(D_METHOD("is_colliding"), &RayCast3D::is_colliding);
ClassDB::bind_method(D_METHOD("force_raycast_update"), &RayCast3D::force_raycast_update);
@@ -312,7 +312,7 @@ void RayCast3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclude_parent"), "set_exclude_parent_body", "get_exclude_parent_body");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "cast_to"), "set_cast_to", "get_cast_to");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "target_position"), "set_target_position", "get_target_position");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
ADD_GROUP("Collide With", "collide_with");
@@ -360,7 +360,7 @@ void RayCast3D::_update_debug_shape() {
Vector<Vector3> verts;
verts.push_back(Vector3());
- verts.push_back(cast_to);
+ verts.push_back(target_position);
a[Mesh::ARRAY_VERTEX] = verts;
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a);
@@ -387,7 +387,7 @@ RayCast3D::RayCast3D() {
collided = false;
against_shape = 0;
collision_mask = 1;
- cast_to = Vector3(0, -1, 0);
+ target_position = Vector3(0, -1, 0);
debug_shape = nullptr;
exclude_parent_body = true;
collide_with_areas = false;
diff --git a/scene/3d/ray_cast_3d.h b/scene/3d/ray_cast_3d.h
index 8f617e5491..f4fe7ba621 100644
--- a/scene/3d/ray_cast_3d.h
+++ b/scene/3d/ray_cast_3d.h
@@ -43,7 +43,7 @@ class RayCast3D : public Node3D {
Vector3 collision_point;
Vector3 collision_normal;
- Vector3 cast_to;
+ Vector3 target_position;
Set<RID> exclude;
uint32_t collision_mask;
@@ -74,8 +74,8 @@ public:
void set_enabled(bool p_enabled);
bool is_enabled() const;
- void set_cast_to(const Vector3 &p_point);
- Vector3 get_cast_to() const;
+ void set_target_position(const Vector3 &p_point);
+ Vector3 get_target_position() const;
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index aaae03df68..2e77d20d4e 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -326,12 +326,12 @@ bool BaseButton::is_keep_pressed_outside() const {
return keep_pressed_outside;
}
-void BaseButton::set_shortcut(const Ref<ShortCut> &p_shortcut) {
+void BaseButton::set_shortcut(const Ref<Shortcut> &p_shortcut) {
shortcut = p_shortcut;
set_process_unhandled_input(shortcut.is_valid());
}
-Ref<ShortCut> BaseButton::get_shortcut() const {
+Ref<Shortcut> BaseButton::get_shortcut() const {
return shortcut;
}
@@ -345,7 +345,7 @@ String BaseButton::get_tooltip(const Point2 &p_pos) const {
String tooltip = Control::get_tooltip(p_pos);
if (shortcut_in_tooltip && shortcut.is_valid() && shortcut->is_valid()) {
String text = shortcut->get_name() + " (" + shortcut->get_as_text() + ")";
- if (shortcut->get_name().nocasecmp_to(tooltip) != 0) {
+ if (tooltip != String() && shortcut->get_name().nocasecmp_to(tooltip) != 0) {
text += "\n" + tooltip;
}
tooltip = text;
@@ -414,7 +414,7 @@ void BaseButton::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "button_mask", PROPERTY_HINT_FLAGS, "Mouse Left, Mouse Right, Mouse Middle"), "set_button_mask", "get_button_mask");
ADD_PROPERTY(PropertyInfo(Variant::INT, "enabled_focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_enabled_focus_mode", "get_enabled_focus_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_pressed_outside"), "set_keep_pressed_outside", "is_keep_pressed_outside");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut", PROPERTY_HINT_RESOURCE_TYPE, "ShortCut"), "set_shortcut", "get_shortcut");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut", PROPERTY_HINT_RESOURCE_TYPE, "Shortcut"), "set_shortcut", "get_shortcut");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "group", PROPERTY_HINT_RESOURCE_TYPE, "ButtonGroup"), "set_button_group", "get_button_group");
BIND_ENUM_CONSTANT(DRAW_NORMAL);
diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h
index 12272446d5..8e71931f8b 100644
--- a/scene/gui/base_button.h
+++ b/scene/gui/base_button.h
@@ -50,7 +50,7 @@ private:
bool shortcut_in_tooltip;
bool keep_pressed_outside;
FocusMode enabled_focus_mode;
- Ref<ShortCut> shortcut;
+ Ref<Shortcut> shortcut;
ActionMode action_mode;
struct Status {
@@ -118,8 +118,8 @@ public:
void set_enabled_focus_mode(FocusMode p_mode);
FocusMode get_enabled_focus_mode() const;
- void set_shortcut(const Ref<ShortCut> &p_shortcut);
- Ref<ShortCut> get_shortcut() const;
+ void set_shortcut(const Ref<Shortcut> &p_shortcut);
+ Ref<Shortcut> get_shortcut() const;
virtual String get_tooltip(const Point2 &p_pos) const override;
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
new file mode 100644
index 0000000000..56cf432b38
--- /dev/null
+++ b/scene/gui/code_edit.cpp
@@ -0,0 +1,444 @@
+/*************************************************************************/
+/* code_edit.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "code_edit.h"
+
+void CodeEdit::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_THEME_CHANGED:
+ case NOTIFICATION_ENTER_TREE: {
+ set_gutter_width(main_gutter, cache.row_height);
+ set_gutter_width(line_number_gutter, (line_number_digits + 1) * cache.font->get_char_size('0').width);
+ set_gutter_width(fold_gutter, cache.row_height / 1.2);
+
+ breakpoint_color = get_theme_color("breakpoint_color");
+ breakpoint_icon = get_theme_icon("breakpoint");
+
+ bookmark_color = get_theme_color("bookmark_color");
+ bookmark_icon = get_theme_icon("bookmark");
+
+ executing_line_color = get_theme_color("executing_line_color");
+ executing_line_icon = get_theme_icon("executing_line");
+
+ line_number_color = get_theme_color("line_number_color");
+
+ folding_color = get_theme_color("code_folding_color");
+ can_fold_icon = get_theme_icon("can_fold");
+ folded_icon = get_theme_icon("folded");
+ } break;
+ case NOTIFICATION_DRAW: {
+ } break;
+ }
+}
+
+/* Main Gutter */
+void CodeEdit::_update_draw_main_gutter() {
+ set_gutter_draw(main_gutter, draw_breakpoints || draw_bookmarks || draw_executing_lines);
+}
+
+void CodeEdit::set_draw_breakpoints_gutter(bool p_draw) {
+ draw_breakpoints = p_draw;
+ set_gutter_clickable(main_gutter, p_draw);
+ _update_draw_main_gutter();
+}
+
+bool CodeEdit::is_drawing_breakpoints_gutter() const {
+ return draw_breakpoints;
+}
+
+void CodeEdit::set_draw_bookmarks_gutter(bool p_draw) {
+ draw_bookmarks = p_draw;
+ _update_draw_main_gutter();
+}
+
+bool CodeEdit::is_drawing_bookmarks_gutter() const {
+ return draw_bookmarks;
+}
+
+void CodeEdit::set_draw_executing_lines_gutter(bool p_draw) {
+ draw_executing_lines = p_draw;
+ _update_draw_main_gutter();
+}
+
+bool CodeEdit::is_drawing_executing_lines_gutter() const {
+ return draw_executing_lines;
+}
+
+void CodeEdit::_main_gutter_draw_callback(int p_line, int p_gutter, const Rect2 &p_region) {
+ if (draw_breakpoints && is_line_breakpointed(p_line)) {
+ int padding = p_region.size.x / 6;
+
+ Rect2 breakpoint_region = p_region;
+ breakpoint_region.position += Point2(padding, padding);
+ breakpoint_region.size -= Point2(padding, padding) * 2;
+ breakpoint_icon->draw_rect(get_canvas_item(), breakpoint_region, false, breakpoint_color);
+ }
+
+ if (draw_bookmarks && is_line_bookmarked(p_line)) {
+ int horizontal_padding = p_region.size.x / 2;
+ int vertical_padding = p_region.size.y / 4;
+
+ Rect2 bookmark_region = p_region;
+ bookmark_region.position += Point2(horizontal_padding, 0);
+ bookmark_region.size -= Point2(horizontal_padding * 1.1, vertical_padding);
+ bookmark_icon->draw_rect(get_canvas_item(), bookmark_region, false, bookmark_color);
+ }
+
+ if (draw_executing_lines && is_line_executing(p_line)) {
+ int horizontal_padding = p_region.size.x / 10;
+ int vertical_padding = p_region.size.y / 4;
+
+ Rect2 executing_line_region = p_region;
+ executing_line_region.position += Point2(horizontal_padding, vertical_padding);
+ executing_line_region.size -= Point2(horizontal_padding, vertical_padding) * 2;
+ executing_line_icon->draw_rect(get_canvas_item(), executing_line_region, false, executing_line_color);
+ }
+}
+
+// Breakpoints
+void CodeEdit::set_line_as_breakpoint(int p_line, bool p_breakpointed) {
+ int mask = get_line_gutter_metadata(p_line, main_gutter);
+ set_line_gutter_metadata(p_line, main_gutter, p_breakpointed ? mask | MAIN_GUTTER_BREAKPOINT : mask & ~MAIN_GUTTER_BREAKPOINT);
+ if (p_breakpointed) {
+ breakpointed_lines[p_line] = true;
+ } else if (breakpointed_lines.has(p_line)) {
+ breakpointed_lines.erase(p_line);
+ }
+ emit_signal("breakpoint_toggled", p_line);
+}
+
+bool CodeEdit::is_line_breakpointed(int p_line) const {
+ return (int)get_line_gutter_metadata(p_line, main_gutter) & MAIN_GUTTER_BREAKPOINT;
+}
+
+void CodeEdit::clear_breakpointed_lines() {
+ for (int i = 0; i < get_line_count(); i++) {
+ if (is_line_breakpointed(i)) {
+ set_line_as_breakpoint(i, false);
+ }
+ }
+}
+
+Array CodeEdit::get_breakpointed_lines() const {
+ Array ret;
+ for (int i = 0; i < get_line_count(); i++) {
+ if (is_line_breakpointed(i)) {
+ ret.append(i);
+ }
+ }
+ return ret;
+}
+
+// Bookmarks
+void CodeEdit::set_line_as_bookmarked(int p_line, bool p_bookmarked) {
+ int mask = get_line_gutter_metadata(p_line, main_gutter);
+ set_line_gutter_metadata(p_line, main_gutter, p_bookmarked ? mask | MAIN_GUTTER_BOOKMARK : mask & ~MAIN_GUTTER_BOOKMARK);
+}
+
+bool CodeEdit::is_line_bookmarked(int p_line) const {
+ return (int)get_line_gutter_metadata(p_line, main_gutter) & MAIN_GUTTER_BOOKMARK;
+}
+
+void CodeEdit::clear_bookmarked_lines() {
+ for (int i = 0; i < get_line_count(); i++) {
+ if (is_line_bookmarked(i)) {
+ set_line_as_bookmarked(i, false);
+ }
+ }
+}
+
+Array CodeEdit::get_bookmarked_lines() const {
+ Array ret;
+ for (int i = 0; i < get_line_count(); i++) {
+ if (is_line_bookmarked(i)) {
+ ret.append(i);
+ }
+ }
+ return ret;
+}
+
+// executing lines
+void CodeEdit::set_line_as_executing(int p_line, bool p_executing) {
+ int mask = get_line_gutter_metadata(p_line, main_gutter);
+ set_line_gutter_metadata(p_line, main_gutter, p_executing ? mask | MAIN_GUTTER_EXECUTING : mask & ~MAIN_GUTTER_EXECUTING);
+}
+
+bool CodeEdit::is_line_executing(int p_line) const {
+ return (int)get_line_gutter_metadata(p_line, main_gutter) & MAIN_GUTTER_EXECUTING;
+}
+
+void CodeEdit::clear_executing_lines() {
+ for (int i = 0; i < get_line_count(); i++) {
+ if (is_line_executing(i)) {
+ set_line_as_executing(i, false);
+ }
+ }
+}
+
+Array CodeEdit::get_executing_lines() const {
+ Array ret;
+ for (int i = 0; i < get_line_count(); i++) {
+ if (is_line_executing(i)) {
+ ret.append(i);
+ }
+ }
+ return ret;
+}
+
+/* Line numbers */
+void CodeEdit::set_draw_line_numbers(bool p_draw) {
+ set_gutter_draw(line_number_gutter, p_draw);
+}
+
+bool CodeEdit::is_draw_line_numbers_enabled() const {
+ return is_gutter_drawn(line_number_gutter);
+}
+
+void CodeEdit::set_line_numbers_zero_padded(bool p_zero_padded) {
+ p_zero_padded ? line_number_padding = "0" : line_number_padding = " ";
+ update();
+}
+
+bool CodeEdit::is_line_numbers_zero_padded() const {
+ return line_number_padding == "0";
+}
+
+void CodeEdit::_line_number_draw_callback(int p_line, int p_gutter, const Rect2 &p_region) {
+ String fc = String::num(p_line + 1).lpad(line_number_digits, line_number_padding);
+
+ int yofs = p_region.position.y + (cache.row_height - cache.font->get_height()) / 2;
+ Color number_color = get_line_gutter_item_color(p_line, line_number_gutter);
+ if (number_color == Color(1, 1, 1)) {
+ number_color = line_number_color;
+ }
+ cache.font->draw(get_canvas_item(), Point2(p_region.position.x, yofs + cache.font->get_ascent()), fc, number_color);
+}
+
+/* Fold Gutter */
+void CodeEdit::set_draw_fold_gutter(bool p_draw) {
+ set_gutter_draw(fold_gutter, p_draw);
+}
+
+bool CodeEdit::is_drawing_fold_gutter() const {
+ return is_gutter_drawn(fold_gutter);
+}
+
+void CodeEdit::_fold_gutter_draw_callback(int p_line, int p_gutter, Rect2 p_region) {
+ if (!can_fold(p_line) && !is_folded(p_line)) {
+ set_line_gutter_clickable(p_line, fold_gutter, false);
+ return;
+ }
+ set_line_gutter_clickable(p_line, fold_gutter, true);
+
+ int horizontal_padding = p_region.size.x / 10;
+ int vertical_padding = p_region.size.y / 6;
+
+ p_region.position += Point2(horizontal_padding, vertical_padding);
+ p_region.size -= Point2(horizontal_padding, vertical_padding) * 2;
+
+ if (can_fold(p_line)) {
+ can_fold_icon->draw_rect(get_canvas_item(), p_region, false, folding_color);
+ return;
+ }
+ folded_icon->draw_rect(get_canvas_item(), p_region, false, folding_color);
+}
+
+void CodeEdit::_bind_methods() {
+ /* Main Gutter */
+ ClassDB::bind_method(D_METHOD("_main_gutter_draw_callback"), &CodeEdit::_main_gutter_draw_callback);
+
+ ClassDB::bind_method(D_METHOD("set_draw_breakpoints_gutter", "enable"), &CodeEdit::set_draw_breakpoints_gutter);
+ ClassDB::bind_method(D_METHOD("is_drawing_breakpoints_gutter"), &CodeEdit::is_drawing_breakpoints_gutter);
+
+ ClassDB::bind_method(D_METHOD("set_draw_bookmarks_gutter", "enable"), &CodeEdit::set_draw_bookmarks_gutter);
+ ClassDB::bind_method(D_METHOD("is_drawing_bookmarks_gutter"), &CodeEdit::is_drawing_bookmarks_gutter);
+
+ ClassDB::bind_method(D_METHOD("set_draw_executing_lines_gutter", "enable"), &CodeEdit::set_draw_executing_lines_gutter);
+ ClassDB::bind_method(D_METHOD("is_drawing_executing_lines_gutter"), &CodeEdit::is_drawing_executing_lines_gutter);
+
+ // Breakpoints
+ ClassDB::bind_method(D_METHOD("set_line_as_breakpoint", "line", "breakpointed"), &CodeEdit::set_line_as_breakpoint);
+ ClassDB::bind_method(D_METHOD("is_line_breakpointed", "line"), &CodeEdit::is_line_breakpointed);
+ ClassDB::bind_method(D_METHOD("clear_breakpointed_lines"), &CodeEdit::clear_breakpointed_lines);
+ ClassDB::bind_method(D_METHOD("get_breakpointed_lines"), &CodeEdit::get_breakpointed_lines);
+
+ // Bookmarks
+ ClassDB::bind_method(D_METHOD("set_line_as_bookmarked", "line", "bookmarked"), &CodeEdit::set_line_as_bookmarked);
+ ClassDB::bind_method(D_METHOD("is_line_bookmarked", "line"), &CodeEdit::is_line_bookmarked);
+ ClassDB::bind_method(D_METHOD("clear_bookmarked_lines"), &CodeEdit::clear_bookmarked_lines);
+ ClassDB::bind_method(D_METHOD("get_bookmarked_lines"), &CodeEdit::get_bookmarked_lines);
+
+ // executing lines
+ ClassDB::bind_method(D_METHOD("set_line_as_executing", "line", "executing"), &CodeEdit::set_line_as_executing);
+ ClassDB::bind_method(D_METHOD("is_line_executing", "line"), &CodeEdit::is_line_executing);
+ ClassDB::bind_method(D_METHOD("clear_executing_lines"), &CodeEdit::clear_executing_lines);
+ ClassDB::bind_method(D_METHOD("get_executing_lines"), &CodeEdit::get_executing_lines);
+
+ /* Line numbers */
+ ClassDB::bind_method(D_METHOD("_line_number_draw_callback"), &CodeEdit::_line_number_draw_callback);
+
+ ClassDB::bind_method(D_METHOD("set_draw_line_numbers", "enable"), &CodeEdit::set_draw_line_numbers);
+ ClassDB::bind_method(D_METHOD("is_draw_line_numbers_enabled"), &CodeEdit::is_draw_line_numbers_enabled);
+ ClassDB::bind_method(D_METHOD("set_line_numbers_zero_padded", "enable"), &CodeEdit::set_line_numbers_zero_padded);
+ ClassDB::bind_method(D_METHOD("is_line_numbers_zero_padded"), &CodeEdit::is_line_numbers_zero_padded);
+
+ /* Fold Gutter */
+ ClassDB::bind_method(D_METHOD("_fold_gutter_draw_callback"), &CodeEdit::_fold_gutter_draw_callback);
+
+ ClassDB::bind_method(D_METHOD("set_draw_fold_gutter", "enable"), &CodeEdit::set_draw_fold_gutter);
+ ClassDB::bind_method(D_METHOD("is_drawing_fold_gutter"), &CodeEdit::is_drawing_fold_gutter);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_breakpoints_gutter"), "set_draw_breakpoints_gutter", "is_drawing_breakpoints_gutter");
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_bookmarks"), "set_draw_bookmarks_gutter", "is_drawing_bookmarks_gutter");
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_executing_lines"), "set_draw_executing_lines_gutter", "is_drawing_executing_lines_gutter");
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_line_numbers"), "set_draw_line_numbers", "is_draw_line_numbers_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "zero_pad_line_numbers"), "set_line_numbers_zero_padded", "is_line_numbers_zero_padded");
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_fold_gutter"), "set_draw_fold_gutter", "is_drawing_fold_gutter");
+
+ ADD_SIGNAL(MethodInfo("breakpoint_toggled", PropertyInfo(Variant::INT, "line")));
+}
+
+void CodeEdit::_gutter_clicked(int p_line, int p_gutter) {
+ if (p_gutter == main_gutter) {
+ if (draw_breakpoints) {
+ set_line_as_breakpoint(p_line, !is_line_breakpointed(p_line));
+ }
+ return;
+ }
+
+ if (p_gutter == line_number_gutter) {
+ cursor_set_line(p_line);
+ return;
+ }
+
+ if (p_gutter == fold_gutter) {
+ if (is_folded(p_line)) {
+ unfold_line(p_line);
+ } else if (can_fold(p_line)) {
+ fold_line(p_line);
+ }
+ return;
+ }
+}
+
+void CodeEdit::_lines_edited_from(int p_from_line, int p_to_line) {
+ if (p_from_line == p_to_line) {
+ return;
+ }
+
+ int lc = get_line_count();
+ line_number_digits = 1;
+ while (lc /= 10) {
+ line_number_digits++;
+ }
+ set_gutter_width(line_number_gutter, (line_number_digits + 1) * cache.font->get_char_size('0').width);
+
+ int from_line = MIN(p_from_line, p_to_line);
+ int line_count = (p_to_line - p_from_line);
+ List<int> breakpoints;
+ breakpointed_lines.get_key_list(&breakpoints);
+ for (const List<int>::Element *E = breakpoints.front(); E; E = E->next()) {
+ int line = E->get();
+ if (line <= from_line) {
+ continue;
+ }
+ breakpointed_lines.erase(line);
+
+ emit_signal("breakpoint_toggled", line);
+ if (line_count > 0 || line >= p_from_line) {
+ emit_signal("breakpoint_toggled", line + line_count);
+ breakpointed_lines[line + line_count] = true;
+ continue;
+ }
+ }
+}
+
+void CodeEdit::_update_gutter_indexes() {
+ for (int i = 0; i < get_gutter_count(); i++) {
+ if (get_gutter_name(i) == "main_gutter") {
+ main_gutter = i;
+ continue;
+ }
+
+ if (get_gutter_name(i) == "line_numbers") {
+ line_number_gutter = i;
+ continue;
+ }
+
+ if (get_gutter_name(i) == "fold_gutter") {
+ fold_gutter = i;
+ continue;
+ }
+ }
+}
+
+CodeEdit::CodeEdit() {
+ /* Gutters */
+ int gutter_idx = 0;
+
+ /* Main Gutter */
+ add_gutter();
+ set_gutter_name(gutter_idx, "main_gutter");
+ set_gutter_draw(gutter_idx, false);
+ set_gutter_overwritable(gutter_idx, true);
+ set_gutter_type(gutter_idx, GUTTER_TPYE_CUSTOM);
+ set_gutter_custom_draw(gutter_idx, this, "_main_gutter_draw_callback");
+ gutter_idx++;
+
+ /* Line numbers */
+ add_gutter();
+ set_gutter_name(gutter_idx, "line_numbers");
+ set_gutter_draw(gutter_idx, false);
+ set_gutter_type(gutter_idx, GUTTER_TPYE_CUSTOM);
+ set_gutter_custom_draw(gutter_idx, this, "_line_number_draw_callback");
+ gutter_idx++;
+
+ /* Fold Gutter */
+ add_gutter();
+ set_gutter_name(gutter_idx, "fold_gutter");
+ set_gutter_draw(gutter_idx, false);
+ set_gutter_type(gutter_idx, GUTTER_TPYE_CUSTOM);
+ set_gutter_custom_draw(gutter_idx, this, "_fold_gutter_draw_callback");
+ gutter_idx++;
+
+ connect("lines_edited_from", callable_mp(this, &CodeEdit::_lines_edited_from));
+ connect("gutter_clicked", callable_mp(this, &CodeEdit::_gutter_clicked));
+
+ connect("gutter_added", callable_mp(this, &CodeEdit::_update_gutter_indexes));
+ connect("gutter_removed", callable_mp(this, &CodeEdit::_update_gutter_indexes));
+ _update_gutter_indexes();
+}
+
+CodeEdit::~CodeEdit() {
+}
diff --git a/scene/gui/code_edit.h b/scene/gui/code_edit.h
new file mode 100644
index 0000000000..c989e5ed79
--- /dev/null
+++ b/scene/gui/code_edit.h
@@ -0,0 +1,135 @@
+/*************************************************************************/
+/* code_edit.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef CODEEDIT_H
+#define CODEEDIT_H
+
+#include "scene/gui/text_edit.h"
+
+class CodeEdit : public TextEdit {
+ GDCLASS(CodeEdit, TextEdit)
+
+private:
+ /* Main Gutter */
+ enum MainGutterType {
+ MAIN_GUTTER_BREAKPOINT = 0x01,
+ MAIN_GUTTER_BOOKMARK = 0x02,
+ MAIN_GUTTER_EXECUTING = 0x04
+ };
+
+ int main_gutter = -1;
+ void _update_draw_main_gutter();
+ void _main_gutter_draw_callback(int p_line, int p_gutter, const Rect2 &p_region);
+
+ // breakpoints
+ HashMap<int, bool> breakpointed_lines;
+ bool draw_breakpoints = false;
+ Color breakpoint_color = Color(1, 1, 1);
+ Ref<Texture2D> breakpoint_icon = Ref<Texture2D>();
+
+ // bookmarks
+ bool draw_bookmarks = false;
+ Color bookmark_color = Color(1, 1, 1);
+ Ref<Texture2D> bookmark_icon = Ref<Texture2D>();
+
+ // executing lines
+ bool draw_executing_lines = false;
+ Color executing_line_color = Color(1, 1, 1);
+ Ref<Texture2D> executing_line_icon = Ref<Texture2D>();
+
+ /* Line numbers */
+ int line_number_gutter = -1;
+ int line_number_digits = 0;
+ String line_number_padding = " ";
+ Color line_number_color = Color(1, 1, 1);
+ void _line_number_draw_callback(int p_line, int p_gutter, const Rect2 &p_region);
+
+ /* Fold Gutter */
+ int fold_gutter = -1;
+ bool draw_fold_gutter = false;
+ Color folding_color = Color(1, 1, 1);
+ Ref<Texture2D> can_fold_icon = Ref<Texture2D>();
+ Ref<Texture2D> folded_icon = Ref<Texture2D>();
+ void _fold_gutter_draw_callback(int p_line, int p_gutter, Rect2 p_region);
+
+ void _gutter_clicked(int p_line, int p_gutter);
+ void _lines_edited_from(int p_from_line, int p_to_line);
+
+ void _update_gutter_indexes();
+
+protected:
+ void _notification(int p_what);
+
+ static void _bind_methods();
+
+public:
+ /* Main Gutter */
+ void set_draw_breakpoints_gutter(bool p_draw);
+ bool is_drawing_breakpoints_gutter() const;
+
+ void set_draw_bookmarks_gutter(bool p_draw);
+ bool is_drawing_bookmarks_gutter() const;
+
+ void set_draw_executing_lines_gutter(bool p_draw);
+ bool is_drawing_executing_lines_gutter() const;
+
+ // breakpoints
+ void set_line_as_breakpoint(int p_line, bool p_breakpointed);
+ bool is_line_breakpointed(int p_line) const;
+ void clear_breakpointed_lines();
+ Array get_breakpointed_lines() const;
+
+ // bookmarks
+ void set_line_as_bookmarked(int p_line, bool p_bookmarked);
+ bool is_line_bookmarked(int p_line) const;
+ void clear_bookmarked_lines();
+ Array get_bookmarked_lines() const;
+
+ // executing lines
+ void set_line_as_executing(int p_line, bool p_executing);
+ bool is_line_executing(int p_line) const;
+ void clear_executing_lines();
+ Array get_executing_lines() const;
+
+ /* Line numbers */
+ void set_draw_line_numbers(bool p_draw);
+ bool is_draw_line_numbers_enabled() const;
+ void set_line_numbers_zero_padded(bool p_zero_padded);
+ bool is_line_numbers_zero_padded() const;
+
+ /* Fold gutter */
+ void set_draw_fold_gutter(bool p_draw);
+ bool is_drawing_fold_gutter() const;
+
+ CodeEdit();
+ ~CodeEdit();
+};
+
+#endif // CODEEDIT_H
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index fafbb298b7..cbe0367c7b 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -873,6 +873,7 @@ void ColorPickerButton::_color_changed(const Color &p_color) {
void ColorPickerButton::_modal_closed() {
emit_signal("popup_closed");
+ set_pressed(false);
}
void ColorPickerButton::pressed() {
@@ -976,9 +977,8 @@ void ColorPickerButton::_update_picker() {
popup->add_child(picker);
add_child(popup);
picker->connect("color_changed", callable_mp(this, &ColorPickerButton::_color_changed));
- popup->connect("modal_closed", callable_mp(this, &ColorPickerButton::_modal_closed));
popup->connect("about_to_popup", callable_mp((BaseButton *)this, &BaseButton::set_pressed), varray(true));
- popup->connect("popup_hide", callable_mp((BaseButton *)this, &BaseButton::set_pressed), varray(false));
+ popup->connect("popup_hide", callable_mp(this, &ColorPickerButton::_modal_closed));
picker->set_pick_color(color);
picker->set_edit_alpha(edit_alpha);
emit_signal("picker_created");
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 11b4c9e857..467d252c81 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -262,6 +262,7 @@ void GraphEdit::remove_child_notify(Node *p_child) {
if (gn) {
gn->disconnect("offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved));
gn->disconnect("raise_request", callable_mp(this, &GraphEdit::_graph_node_raised));
+ gn->disconnect("item_rect_changed", callable_mp((CanvasItem *)connections_layer, &CanvasItem::update));
}
}
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 2fdcf11ca8..bc70809ad5 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -717,7 +717,7 @@ void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int
}
#define ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global) \
- ERR_FAIL_COND_MSG(p_shortcut.is_null(), "Cannot add item with invalid ShortCut."); \
+ ERR_FAIL_COND_MSG(p_shortcut.is_null(), "Cannot add item with invalid Shortcut."); \
_ref_shortcut(p_shortcut); \
item.text = p_shortcut->get_name(); \
item.xl_text = tr(item.text); \
@@ -725,7 +725,7 @@ void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int
item.shortcut = p_shortcut; \
item.shortcut_is_global = p_global;
-void PopupMenu::add_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) {
+void PopupMenu::add_shortcut(const Ref<Shortcut> &p_shortcut, int p_id, bool p_global) {
Item item;
ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global);
items.push_back(item);
@@ -733,7 +733,7 @@ void PopupMenu::add_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_g
child_controls_changed();
}
-void PopupMenu::add_icon_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) {
+void PopupMenu::add_icon_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortcut> &p_shortcut, int p_id, bool p_global) {
Item item;
ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global);
item.icon = p_icon;
@@ -742,7 +742,7 @@ void PopupMenu::add_icon_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortC
child_controls_changed();
}
-void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) {
+void PopupMenu::add_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_id, bool p_global) {
Item item;
ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global);
item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
@@ -751,7 +751,7 @@ void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bo
child_controls_changed();
}
-void PopupMenu::add_icon_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) {
+void PopupMenu::add_icon_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortcut> &p_shortcut, int p_id, bool p_global) {
Item item;
ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global);
item.icon = p_icon;
@@ -761,7 +761,7 @@ void PopupMenu::add_icon_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<
child_controls_changed();
}
-void PopupMenu::add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) {
+void PopupMenu::add_radio_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_id, bool p_global) {
Item item;
ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global);
item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
@@ -770,7 +770,7 @@ void PopupMenu::add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_
child_controls_changed();
}
-void PopupMenu::add_icon_radio_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) {
+void PopupMenu::add_icon_radio_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortcut> &p_shortcut, int p_id, bool p_global) {
Item item;
ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global);
item.icon = p_icon;
@@ -931,8 +931,8 @@ String PopupMenu::get_item_tooltip(int p_idx) const {
return items[p_idx].tooltip;
}
-Ref<ShortCut> PopupMenu::get_item_shortcut(int p_idx) const {
- ERR_FAIL_INDEX_V(p_idx, items.size(), Ref<ShortCut>());
+Ref<Shortcut> PopupMenu::get_item_shortcut(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx, items.size(), Ref<Shortcut>());
return items[p_idx].shortcut;
}
@@ -970,7 +970,7 @@ void PopupMenu::set_item_tooltip(int p_idx, const String &p_tooltip) {
control->update();
}
-void PopupMenu::set_item_shortcut(int p_idx, const Ref<ShortCut> &p_shortcut, bool p_global) {
+void PopupMenu::set_item_shortcut(int p_idx, const Ref<Shortcut> &p_shortcut, bool p_global) {
ERR_FAIL_INDEX(p_idx, items.size());
if (items[p_idx].shortcut.is_valid()) {
_unref_shortcut(items[p_idx].shortcut);
@@ -1209,7 +1209,7 @@ Array PopupMenu::_get_items() const {
return items;
}
-void PopupMenu::_ref_shortcut(Ref<ShortCut> p_sc) {
+void PopupMenu::_ref_shortcut(Ref<Shortcut> p_sc) {
if (!shortcut_refcount.has(p_sc)) {
shortcut_refcount[p_sc] = 1;
p_sc->connect("changed", callable_mp((CanvasItem *)this, &CanvasItem::update));
@@ -1218,7 +1218,7 @@ void PopupMenu::_ref_shortcut(Ref<ShortCut> p_sc) {
}
}
-void PopupMenu::_unref_shortcut(Ref<ShortCut> p_sc) {
+void PopupMenu::_unref_shortcut(Ref<Shortcut> p_sc) {
ERR_FAIL_COND(!shortcut_refcount.has(p_sc));
shortcut_refcount[p_sc]--;
if (shortcut_refcount[p_sc] == 0) {
diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h
index 45a3336747..9535fd07d7 100644
--- a/scene/gui/popup_menu.h
+++ b/scene/gui/popup_menu.h
@@ -61,7 +61,7 @@ class PopupMenu : public Popup {
int _ofs_cache;
int _height_cache;
int h_ofs;
- Ref<ShortCut> shortcut;
+ Ref<Shortcut> shortcut;
bool shortcut_is_global;
bool shortcut_is_disabled;
@@ -114,10 +114,10 @@ class PopupMenu : public Popup {
Array _get_items() const;
void _set_items(const Array &p_items);
- Map<Ref<ShortCut>, int> shortcut_refcount;
+ Map<Ref<Shortcut>, int> shortcut_refcount;
- void _ref_shortcut(Ref<ShortCut> p_sc);
- void _unref_shortcut(Ref<ShortCut> p_sc);
+ void _ref_shortcut(Ref<Shortcut> p_sc);
+ void _unref_shortcut(Ref<Shortcut> p_sc);
bool allow_search;
uint64_t search_time_msec;
@@ -145,12 +145,12 @@ public:
void add_multistate_item(const String &p_label, int p_max_states, int p_default_state = 0, int p_id = -1, uint32_t p_accel = 0);
- void add_shortcut(const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false);
- void add_icon_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false);
- void add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false);
- void add_icon_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false);
- void add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false);
- void add_icon_radio_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false);
+ void add_shortcut(const Ref<Shortcut> &p_shortcut, int p_id = -1, bool p_global = false);
+ void add_icon_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortcut> &p_shortcut, int p_id = -1, bool p_global = false);
+ void add_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_id = -1, bool p_global = false);
+ void add_icon_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortcut> &p_shortcut, int p_id = -1, bool p_global = false);
+ void add_radio_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_id = -1, bool p_global = false);
+ void add_icon_radio_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortcut> &p_shortcut, int p_id = -1, bool p_global = false);
void add_submenu_item(const String &p_label, const String &p_submenu, int p_id = -1);
@@ -166,7 +166,7 @@ public:
void set_item_as_checkable(int p_idx, bool p_checkable);
void set_item_as_radio_checkable(int p_idx, bool p_radio_checkable);
void set_item_tooltip(int p_idx, const String &p_tooltip);
- void set_item_shortcut(int p_idx, const Ref<ShortCut> &p_shortcut, bool p_global = false);
+ void set_item_shortcut(int p_idx, const Ref<Shortcut> &p_shortcut, bool p_global = false);
void set_item_h_offset(int p_idx, int p_offset);
void set_item_multistate(int p_idx, int p_state);
void toggle_item_multistate(int p_idx);
@@ -189,7 +189,7 @@ public:
bool is_item_radio_checkable(int p_idx) const;
bool is_item_shortcut_disabled(int p_idx) const;
String get_item_tooltip(int p_idx) const;
- Ref<ShortCut> get_item_shortcut(int p_idx) const;
+ Ref<Shortcut> get_item_shortcut(int p_idx) const;
int get_item_state(int p_idx) const;
int get_current_index() const;
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index c62fd24a5e..fb4931ea91 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -256,7 +256,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
lh = line < l.height_caches.size() ? l.height_caches[line] : 1; \
line_ascent = line < l.ascent_caches.size() ? l.ascent_caches[line] : 1; \
line_descent = line < l.descent_caches.size() ? l.descent_caches[line] : 1; \
- if ((p_mode == PROCESS_DRAW) && (align != ALIGN_FILL)) { \
+ if (align != ALIGN_FILL) { \
if (line < l.offset_caches.size()) { \
wofs = l.offset_caches[line]; \
} \
diff --git a/scene/gui/shortcut.cpp b/scene/gui/shortcut.cpp
index 9f5b9c40c2..f8c7bc44a7 100644
--- a/scene/gui/shortcut.cpp
+++ b/scene/gui/shortcut.cpp
@@ -32,20 +32,20 @@
#include "core/os/keyboard.h"
-void ShortCut::set_shortcut(const Ref<InputEvent> &p_shortcut) {
+void Shortcut::set_shortcut(const Ref<InputEvent> &p_shortcut) {
shortcut = p_shortcut;
emit_changed();
}
-Ref<InputEvent> ShortCut::get_shortcut() const {
+Ref<InputEvent> Shortcut::get_shortcut() const {
return shortcut;
}
-bool ShortCut::is_shortcut(const Ref<InputEvent> &p_event) const {
+bool Shortcut::is_shortcut(const Ref<InputEvent> &p_event) const {
return shortcut.is_valid() && shortcut->shortcut_match(p_event);
}
-String ShortCut::get_as_text() const {
+String Shortcut::get_as_text() const {
if (shortcut.is_valid()) {
return shortcut->as_text();
} else {
@@ -53,21 +53,21 @@ String ShortCut::get_as_text() const {
}
}
-bool ShortCut::is_valid() const {
+bool Shortcut::is_valid() const {
return shortcut.is_valid();
}
-void ShortCut::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_shortcut", "event"), &ShortCut::set_shortcut);
- ClassDB::bind_method(D_METHOD("get_shortcut"), &ShortCut::get_shortcut);
+void Shortcut::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_shortcut", "event"), &Shortcut::set_shortcut);
+ ClassDB::bind_method(D_METHOD("get_shortcut"), &Shortcut::get_shortcut);
- ClassDB::bind_method(D_METHOD("is_valid"), &ShortCut::is_valid);
+ ClassDB::bind_method(D_METHOD("is_valid"), &Shortcut::is_valid);
- ClassDB::bind_method(D_METHOD("is_shortcut", "event"), &ShortCut::is_shortcut);
- ClassDB::bind_method(D_METHOD("get_as_text"), &ShortCut::get_as_text);
+ ClassDB::bind_method(D_METHOD("is_shortcut", "event"), &Shortcut::is_shortcut);
+ ClassDB::bind_method(D_METHOD("get_as_text"), &Shortcut::get_as_text);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), "set_shortcut", "get_shortcut");
}
-ShortCut::ShortCut() {
+Shortcut::Shortcut() {
}
diff --git a/scene/gui/shortcut.h b/scene/gui/shortcut.h
index 063d4e43dc..0d7809e5cf 100644
--- a/scene/gui/shortcut.h
+++ b/scene/gui/shortcut.h
@@ -34,8 +34,8 @@
#include "core/input/input_event.h"
#include "core/resource.h"
-class ShortCut : public Resource {
- GDCLASS(ShortCut, Resource);
+class Shortcut : public Resource {
+ GDCLASS(Shortcut, Resource);
Ref<InputEvent> shortcut;
@@ -50,7 +50,7 @@ public:
String get_as_text() const;
- ShortCut();
+ Shortcut();
};
#endif // SHORTCUT_H
diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp
index 8f71aa7cab..d47f771d1d 100644
--- a/scene/gui/tabs.cpp
+++ b/scene/gui/tabs.cpp
@@ -388,6 +388,7 @@ void Tabs::set_current_tab(int p_current) {
}
ERR_FAIL_INDEX(p_current, get_tab_count());
+ previous = current;
current = p_current;
_change_notify("current_tab");
@@ -401,6 +402,10 @@ int Tabs::get_current_tab() const {
return current;
}
+int Tabs::get_previous_tab() const {
+ return previous;
+}
+
int Tabs::get_hovered_tab() const {
return hover;
}
@@ -588,6 +593,7 @@ void Tabs::add_tab(const String &p_str, const Ref<Texture2D> &p_icon) {
void Tabs::clear_tabs() {
tabs.clear();
current = 0;
+ previous = 0;
call_deferred("_update_hover");
update();
}
@@ -605,6 +611,7 @@ void Tabs::remove_tab(int p_idx) {
if (current < 0) {
current = 0;
+ previous = 0;
}
if (current >= tabs.size()) {
current = tabs.size() - 1;
@@ -917,6 +924,7 @@ void Tabs::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_tab_count"), &Tabs::get_tab_count);
ClassDB::bind_method(D_METHOD("set_current_tab", "tab_idx"), &Tabs::set_current_tab);
ClassDB::bind_method(D_METHOD("get_current_tab"), &Tabs::get_current_tab);
+ ClassDB::bind_method(D_METHOD("get_previous_tab"), &Tabs::get_previous_tab);
ClassDB::bind_method(D_METHOD("set_tab_title", "tab_idx", "title"), &Tabs::set_tab_title);
ClassDB::bind_method(D_METHOD("get_tab_title", "tab_idx"), &Tabs::get_tab_title);
ClassDB::bind_method(D_METHOD("set_tab_icon", "tab_idx", "icon"), &Tabs::set_tab_icon);
@@ -970,6 +978,7 @@ void Tabs::_bind_methods() {
Tabs::Tabs() {
current = 0;
+ previous = 0;
tab_align = ALIGN_CENTER;
rb_hover = -1;
rb_pressing = false;
diff --git a/scene/gui/tabs.h b/scene/gui/tabs.h
index 8d7f1aa37d..b94c4a37a1 100644
--- a/scene/gui/tabs.h
+++ b/scene/gui/tabs.h
@@ -77,6 +77,7 @@ private:
bool missing_right;
Vector<Tab> tabs;
int current;
+ int previous;
int _get_top_margin() const;
TabAlign tab_align;
int rb_hover;
@@ -138,6 +139,7 @@ public:
int get_tab_count() const;
void set_current_tab(int p_current);
int get_current_tab() const;
+ int get_previous_tab() const;
int get_hovered_tab() const;
int get_tab_offset() const;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 1d732bec5b..957e1c11c7 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -107,6 +107,8 @@ static int _find_first_non_whitespace_column_of_line(const String &line) {
return left;
}
+///////////////////////////////////////////////////////////////////////////////
+
void TextEdit::Text::set_font(const Ref<Font> &p_font) {
font = p_font;
}
@@ -165,12 +167,6 @@ void TextEdit::Text::clear_wrap_cache() {
}
}
-void TextEdit::Text::clear_info_icons() {
- for (int i = 0; i < text.size(); i++) {
- text.write[i].has_info = false;
- }
-}
-
void TextEdit::Text::clear() {
text.clear();
insert(0, "");
@@ -198,12 +194,9 @@ void TextEdit::Text::set(int p_line, const String &p_text) {
void TextEdit::Text::insert(int p_at, const String &p_text) {
Line line;
+ line.gutters.resize(gutter_count);
line.marked = false;
- line.safe = false;
- line.breakpoint = false;
- line.bookmark = false;
line.hidden = false;
- line.has_info = false;
line.width_cache = -1;
line.wrap_amount_cache = -1;
line.data = p_text;
@@ -231,6 +224,32 @@ int TextEdit::Text::get_char_width(char32_t c, char32_t next_c, int px) const {
return w;
}
+void TextEdit::Text::add_gutter(int p_at) {
+ for (int i = 0; i < text.size(); i++) {
+ if (p_at < 0 || p_at > gutter_count) {
+ text.write[i].gutters.push_back(Gutter());
+ } else {
+ text.write[i].gutters.insert(p_at, Gutter());
+ }
+ }
+ gutter_count++;
+}
+
+void TextEdit::Text::remove_gutter(int p_gutter) {
+ for (int i = 0; i < text.size(); i++) {
+ text.write[i].gutters.remove(p_gutter);
+ }
+ gutter_count--;
+}
+
+void TextEdit::Text::move_gutters(int p_from_line, int p_to_line) {
+ text.write[p_to_line].gutters = text[p_from_line].gutters;
+ text.write[p_from_line].gutters.clear();
+ text.write[p_from_line].gutters.resize(gutter_count);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
void TextEdit::_update_scrollbars() {
Size2 size = get_size();
Size2 hmin = h_scroll->get_combined_minimum_size();
@@ -249,23 +268,7 @@ void TextEdit::_update_scrollbars() {
}
int visible_width = size.width - cache.style_normal->get_minimum_size().width;
- int total_width = text.get_max_width(true) + vmin.x;
-
- if (line_numbers) {
- total_width += cache.line_number_w;
- }
-
- if (draw_breakpoint_gutter || draw_bookmark_gutter) {
- total_width += cache.breakpoint_gutter_width;
- }
-
- if (draw_info_gutter) {
- total_width += cache.info_gutter_width;
- }
-
- if (draw_fold_gutter) {
- total_width += cache.fold_gutter_width;
- }
+ int total_width = text.get_max_width(true) + vmin.x + gutters_width + gutter_padding;
if (draw_minimap) {
total_width += cache.minimap_width;
@@ -557,54 +560,16 @@ void TextEdit::_notification(int p_what) {
draw_caret = false;
}
- if (draw_breakpoint_gutter || draw_bookmark_gutter) {
- breakpoint_gutter_width = (get_row_height() * 55) / 100;
- cache.breakpoint_gutter_width = breakpoint_gutter_width;
- } else {
- cache.breakpoint_gutter_width = 0;
- }
-
- if (draw_info_gutter) {
- info_gutter_width = (get_row_height());
- cache.info_gutter_width = info_gutter_width;
- } else {
- cache.info_gutter_width = 0;
- }
-
- if (draw_fold_gutter) {
- fold_gutter_width = (get_row_height() * 55) / 100;
- cache.fold_gutter_width = fold_gutter_width;
- } else {
- cache.fold_gutter_width = 0;
- }
-
cache.minimap_width = 0;
if (draw_minimap) {
cache.minimap_width = minimap_width;
}
- int line_number_char_count = 0;
-
- {
- int lc = text.size();
- cache.line_number_w = 0;
- while (lc) {
- cache.line_number_w += 1;
- lc /= 10;
- };
-
- if (line_numbers) {
- line_number_char_count = cache.line_number_w;
- cache.line_number_w = (cache.line_number_w + 1) * cache.font->get_char_size('0').width;
- } else {
- cache.line_number_w = 0;
- }
- }
_update_scrollbars();
RID ci = get_canvas_item();
RenderingServer::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_beg = cache.style_normal->get_margin(MARGIN_LEFT) + gutters_width + gutter_padding;
int xmargin_end = size.width - cache.style_normal->get_margin(MARGIN_RIGHT) - cache.minimap_width;
// Let's do it easy for now.
@@ -795,8 +760,6 @@ void TextEdit::_notification(int p_what) {
// 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" : " ";
-
int cursor_wrap_index = get_cursor_wrap_index();
FontDrawer drawer(cache.font, Color(1, 1, 1));
@@ -1053,103 +1016,52 @@ void TextEdit::_notification(int p_what) {
if (line_wrap_index == 0) {
// Only do these if we are on the first wrapped part of a line.
- if (text.is_breakpoint(line) && !draw_breakpoint_gutter) {
-#ifdef TOOLS_ENABLED
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y + get_row_height() - EDSCALE, xmargin_end - xmargin_beg, EDSCALE), cache.breakpoint_color);
-#else
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.breakpoint_color);
-#endif
- }
+ int gutter_offset = cache.style_normal->get_margin(MARGIN_LEFT);
+ for (int g = 0; g < gutters.size(); g++) {
+ const GutterInfo gutter = gutters[g];
- // Draw bookmark marker.
- if (text.is_bookmark(line)) {
- if (draw_bookmark_gutter) {
- int vertical_gap = (get_row_height() * 40) / 100;
- int horizontal_gap = (cache.breakpoint_gutter_width * 30) / 100;
- int marker_radius = get_row_height() - (vertical_gap * 2);
- RenderingServer::get_singleton()->canvas_item_add_circle(ci, Point2(cache.style_normal->get_margin(MARGIN_LEFT) + horizontal_gap - 2 + marker_radius / 2, ofs_y + vertical_gap + marker_radius / 2), marker_radius, Color(cache.bookmark_color.r, cache.bookmark_color.g, cache.bookmark_color.b));
+ if (!gutter.draw || gutter.width <= 0) {
+ continue;
}
- }
- // 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.
- RenderingServer::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.
- 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<Texture2D> info_icon = text.get_info_icon(line);
- // 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;
- }
- if (icon_size.height > get_row_height() - horizontal_gap) {
- icon_size.height = get_row_height() - horizontal_gap;
- }
+ switch (gutter.type) {
+ case GUTTER_TYPE_STRING: {
+ const String &text = get_line_gutter_text(line, g);
+ if (text == "") {
+ break;
+ }
- Size2i icon_pos;
- int xofs = horizontal_gap - (info_icon->get_width() / 4);
- int yofs = vertical_gap - (info_icon->get_height() / 4);
- icon_pos.x = gutter_left + xofs + ofs_x;
- icon_pos.y = ofs_y + yofs;
+ int yofs = ofs_y + (get_row_height() - cache.font->get_height()) / 2;
+ cache.font->draw(ci, Point2(gutter_offset + ofs_x, yofs + cache.font->get_ascent()), text, get_line_gutter_item_color(line, g));
+ } break;
+ case GUTTER_TPYE_ICON: {
+ const Ref<Texture2D> icon = get_line_gutter_icon(line, g);
+ if (icon.is_null()) {
+ break;
+ }
- draw_texture_rect(info_icon, Rect2(icon_pos, icon_size));
- }
+ Rect2i gutter_rect = Rect2i(Point2i(gutter_offset, ofs_y), Size2i(gutter.width, get_row_height()));
- // Draw execution marker.
- if (executing_line == line) {
- if (draw_breakpoint_gutter) {
- int icon_extra_size = 4;
- 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) + icon_extra_size;
- int marker_width = cache.breakpoint_gutter_width - (horizontal_gap * 2) + icon_extra_size;
- cache.executing_icon->draw_rect(ci, Rect2(cache.style_normal->get_margin(MARGIN_LEFT) + horizontal_gap - 2 - icon_extra_size / 2, ofs_y + vertical_gap - icon_extra_size / 2, marker_width, marker_height), false, Color(cache.executing_line_color.r, cache.executing_line_color.g, cache.executing_line_color.b));
- } else {
-#ifdef TOOLS_ENABLED
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y + get_row_height() - EDSCALE, xmargin_end - xmargin_beg, EDSCALE), cache.executing_line_color);
-#else
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.executing_line_color);
-#endif
- }
- }
+ int horizontal_padding = gutter_rect.size.x / 6;
+ int vertical_padding = gutter_rect.size.y / 6;
- // 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;
- if (is_folded(line)) {
- int xofs = horizontal_gap - (cache.can_fold_icon->get_width()) / 2;
- int yofs = (get_row_height() - cache.folded_icon->get_height()) / 2;
- cache.folded_icon->draw(ci, Point2(gutter_left + xofs + ofs_x, ofs_y + yofs), cache.code_folding_color);
- } else if (can_fold(line)) {
- int xofs = -cache.can_fold_icon->get_width() / 2 - horizontal_gap + 3;
- int yofs = (get_row_height() - cache.can_fold_icon->get_height()) / 2;
- cache.can_fold_icon->draw(ci, Point2(gutter_left + xofs + ofs_x, ofs_y + yofs), cache.code_folding_color);
- }
- }
+ gutter_rect.position += Point2(horizontal_padding, vertical_padding);
+ gutter_rect.size -= Point2(horizontal_padding, vertical_padding) * 2;
- // 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);
- while (fc.length() < line_number_char_count) {
- fc = line_num_padding + fc;
+ icon->draw_rect(ci, gutter_rect, false, get_line_gutter_item_color(line, g));
+ } break;
+ case GUTTER_TPYE_CUSTOM: {
+ if (gutter.custom_draw_obj.is_valid()) {
+ Object *cdo = ObjectDB::get_instance(gutter.custom_draw_obj);
+ if (cdo) {
+ Rect2i gutter_rect = Rect2i(Point2i(gutter_offset, ofs_y), Size2i(gutter.width, get_row_height()));
+ cdo->call(gutter.custom_draw_callback, line, g, Rect2(gutter_rect));
+ }
+ }
+ } break;
}
- cache.font->draw(ci, Point2(cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width + cache.info_gutter_width + ofs_x, yofs + cache.font->get_ascent()), fc, text.is_safe(line) ? cache.safe_line_number_color : cache.line_number_color);
+ gutter_offset += gutter.width;
}
}
@@ -1797,18 +1709,34 @@ void TextEdit::backspace_at_cursor() {
int prev_line = cursor.column ? cursor.line : cursor.line - 1;
int prev_column = cursor.column ? (cursor.column - 1) : (text[cursor.line - 1].length());
- if (is_line_hidden(cursor.line)) {
- set_line_as_hidden(prev_line, true);
- }
- if (is_line_set_as_breakpoint(cursor.line)) {
- if (!text.is_breakpoint(prev_line)) {
- emit_signal("breakpoint_toggled", prev_line);
+ if (cursor.line != prev_line) {
+ for (int i = 0; i < gutters.size(); i++) {
+ if (!gutters[i].overwritable) {
+ continue;
+ }
+
+ if (text.get_line_gutter_text(cursor.line, i) != "") {
+ text.set_line_gutter_text(prev_line, i, text.get_line_gutter_text(cursor.line, i));
+ text.set_line_gutter_item_color(prev_line, i, text.get_line_gutter_item_color(cursor.line, i));
+ }
+
+ if (text.get_line_gutter_icon(cursor.line, i).is_valid()) {
+ text.set_line_gutter_icon(prev_line, i, text.get_line_gutter_icon(cursor.line, i));
+ text.set_line_gutter_item_color(prev_line, i, text.get_line_gutter_item_color(cursor.line, i));
+ }
+
+ if (text.get_line_gutter_metadata(cursor.line, i) != "") {
+ text.set_line_gutter_metadata(prev_line, i, text.get_line_gutter_metadata(cursor.line, i));
+ }
+
+ if (text.is_line_gutter_clickable(cursor.line, i)) {
+ text.set_line_gutter_clickable(prev_line, i, true);
+ }
}
- set_line_as_breakpoint(prev_line, true);
}
- if (text.has_info_icon(cursor.line)) {
- set_line_info_icon(prev_line, text.get_info_icon(cursor.line), text.get_info(cursor.line));
+ if (is_line_hidden(cursor.line)) {
+ set_line_as_hidden(prev_line, true);
}
if (auto_brace_completion_enabled &&
@@ -1998,7 +1926,7 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co
row = text.size() - 1;
col = text[row].size();
} else {
- int colx = p_mouse.x - (cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width + cache.info_gutter_width);
+ int colx = p_mouse.x - (cache.style_normal->get_margin(MARGIN_LEFT) + gutters_width + gutter_padding);
colx += cursor.x_ofs;
col = get_char_pos_for_line(colx, row, wrap_index);
if (is_wrap_enabled() && wrap_index < times_line_wraps(row)) {
@@ -2043,7 +1971,7 @@ Vector2i TextEdit::_get_cursor_pixel_pos() {
// Calculate final pixel position
int y = (row - get_v_scroll_offset() + 1 /*Bottom of line*/) * get_row_height();
- int x = 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;
+ int x = cache.style_normal->get_margin(MARGIN_LEFT) + gutters_width + gutter_padding - cursor.x_ofs;
int ix = 0;
while (ix < rows2[0].size() && ix < cursor.column) {
if (cache.font != nullptr) {
@@ -2178,45 +2106,24 @@ 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);
- // 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) {
- set_line_as_breakpoint(row, !is_line_set_as_breakpoint(row));
- emit_signal("breakpoint_toggled", row);
- return;
+ int left_margin = cache.style_normal->get_margin(MARGIN_LEFT);
+ for (int i = 0; i < gutters.size(); i++) {
+ if (!gutters[i].draw || gutters[i].width <= 0) {
+ continue;
}
- }
- // 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;
- if (mb->get_position().x > gutter_left - 6 && mb->get_position().x <= gutter_left + cache.info_gutter_width - 3) {
- emit_signal("info_clicked", row, text.get_info(row));
+ if (mb->get_position().x > left_margin && mb->get_position().x <= (left_margin + gutters[i].width) - 3) {
+ emit_signal("gutter_clicked", row, i);
return;
}
- }
- // Toggle fold on gutter click if can.
- if (draw_fold_gutter) {
- int left_margin = cache.style_normal->get_margin(MARGIN_LEFT);
- int gutter_left = left_margin + cache.breakpoint_gutter_width + cache.line_number_w + cache.info_gutter_width;
- if (mb->get_position().x > gutter_left - 6 && mb->get_position().x <= gutter_left + cache.fold_gutter_width - 3) {
- if (is_folded(row)) {
- unfold_line(row);
- } else if (can_fold(row)) {
- fold_line(row);
- }
- return;
- }
+ left_margin += gutters[i].width;
}
// 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;
- if (mb->get_position().x > line_width - 3 && mb->get_position().x <= line_width + cache.folded_eol_icon->get_width() + 3) {
+ left_margin += gutter_padding + text.get_line_width(row) - cursor.x_ofs;
+ if (mb->get_position().x > left_margin && mb->get_position().x <= left_margin + cache.folded_eol_icon->get_width() + 3) {
unfold_line(row);
return;
}
@@ -3775,30 +3682,15 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i
Vector<String> substrings = p_text.replace("\r", "").split("\n");
- /* 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";
- int i = p_line + !shift_first_line;
- int lines = substrings.size() - 1;
- for (; i < text.size(); i++) {
- if (text.is_breakpoint(i)) {
- if ((i - lines < p_line || !text.is_breakpoint(i - lines)) || (i - lines == p_line && !shift_first_line)) {
- emit_signal("breakpoint_toggled", i);
- }
- if (i + lines >= text.size() || !text.is_breakpoint(i + lines)) {
- emit_signal("breakpoint_toggled", i + lines);
- }
- }
- }
-
- /* STEP 3: Add spaces if the char is greater than the end of the line. */
+ /* STEP 2: 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 3: 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());
@@ -3818,15 +3710,10 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i
}
if (shift_first_line) {
- text.set_breakpoint(p_line + 1, text.is_breakpoint(p_line));
+ text.move_gutters(p_line, p_line + 1);
text.set_hidden(p_line + 1, text.is_hidden(p_line));
- if (text.has_info_icon(p_line)) {
- text.set_info_icon(p_line + 1, text.get_info_icon(p_line), text.get_info(p_line));
- }
- text.set_breakpoint(p_line, false);
text.set_hidden(p_line, false);
- text.set_info_icon(p_line, nullptr, "");
}
text.set_line_wrap_amount(p_line, -1);
@@ -3840,7 +3727,7 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i
}
text_changed_dirty = true;
}
- emit_signal("line_edited_from", p_line);
+ emit_signal("lines_edited_from", p_line, r_end_line);
}
String TextEdit::_base_get_text(int p_from_line, int p_from_column, int p_to_line, int p_to_column) const {
@@ -3877,19 +3764,6 @@ void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_li
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());
- int lines = p_to_line - p_from_line;
-
- for (int i = p_from_line + 1; i < text.size(); i++) {
- if (text.is_breakpoint(i)) {
- if (i + lines >= text.size() || !text.is_breakpoint(i + lines)) {
- emit_signal("breakpoint_toggled", i);
- }
- if (i > p_to_line && (i - lines < 0 || !text.is_breakpoint(i - lines))) {
- emit_signal("breakpoint_toggled", i - lines);
- }
- }
- }
-
for (int i = p_from_line; i < p_to_line; i++) {
text.remove(p_from_line + 1);
}
@@ -3903,7 +3777,7 @@ void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_li
}
text_changed_dirty = true;
}
- emit_signal("line_edited_from", p_from_line);
+ emit_signal("lines_edited_from", p_to_line, p_from_line);
}
void TextEdit::_insert_text(int p_line, int p_char, const String &p_text, int *r_end_line, int *r_end_char) {
@@ -4097,7 +3971,7 @@ 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 - cache.minimap_width - wrap_right_offset;
+ wrap_at = get_size().width - cache.style_normal->get_minimum_size().width - gutters_width - gutter_padding - cache.minimap_width - wrap_right_offset;
update_cursor_wrap_offset();
text.clear_wrap_cache();
@@ -4132,7 +4006,7 @@ void TextEdit::adjust_viewport_to_cursor() {
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 - cache.minimap_width;
+ int visible_width = get_size().width - cache.style_normal->get_minimum_size().width - gutters_width - gutter_padding - cache.minimap_width;
if (v_scroll->is_visible_in_tree()) {
visible_width -= v_scroll->get_combined_minimum_size().width;
}
@@ -4167,7 +4041,7 @@ void TextEdit::center_viewport_to_cursor() {
}
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 - cache.minimap_width;
+ int visible_width = get_size().width - cache.style_normal->get_minimum_size().width - gutters_width - gutter_padding - cache.minimap_width;
if (v_scroll->is_visible_in_tree()) {
visible_width -= v_scroll->get_combined_minimum_size().width;
}
@@ -4614,54 +4488,41 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const {
return CURSOR_POINTING_HAND;
}
- int gutter = cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width + cache.info_gutter_width;
if ((completion_active && completion_rect.has_point(p_pos))) {
return CURSOR_ARROW;
}
- if (p_pos.x < gutter) {
- int row, col;
- _get_mouse_pos(p_pos, row, col);
- int left_margin = cache.style_normal->get_margin(MARGIN_LEFT);
- // 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;
- }
+ int row, col;
+ _get_mouse_pos(p_pos, row, col);
- // 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)) {
- return CURSOR_POINTING_HAND;
+ int left_margin = cache.style_normal->get_margin(MARGIN_LEFT);
+ int gutter = left_margin + gutters_width;
+ if (p_pos.x < gutter) {
+ for (int i = 0; i < gutters.size(); i++) {
+ if (!gutters[i].draw) {
+ continue;
}
- return CURSOR_ARROW;
- }
- // 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;
- } else {
- return CURSOR_ARROW;
+ if (p_pos.x > left_margin && p_pos.x <= (left_margin + gutters[i].width) - 3) {
+ if (gutters[i].clickable || is_line_gutter_clickable(row, i)) {
+ return CURSOR_POINTING_HAND;
+ }
}
+ left_margin += gutters[i].width;
}
+ return CURSOR_ARROW;
+ }
+ 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;
- } 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.
- 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;
- if (p_pos.x > line_width - 3 && p_pos.x <= line_width + cache.folded_eol_icon->get_width() + 3) {
- return CURSOR_POINTING_HAND;
- }
+ }
+
+ // EOL fold icon.
+ if (is_folded(row)) {
+ gutter += gutter_padding + text.get_line_width(row) - cursor.x_ofs;
+ if (p_pos.x > gutter - 3 && p_pos.x <= gutter + cache.folded_eol_icon->get_width() + 3) {
+ return CURSOR_POINTING_HAND;
}
}
@@ -4861,8 +4722,6 @@ void TextEdit::_update_caches() {
cache.font = get_theme_font("font");
cache.caret_color = get_theme_color("caret_color");
cache.caret_background_color = get_theme_color("caret_background_color");
- cache.line_number_color = get_theme_color("line_number_color");
- cache.safe_line_number_color = get_theme_color("safe_line_number_color");
cache.font_color = get_theme_color("font_color");
cache.font_color_selected = get_theme_color("font_color_selected");
cache.font_color_readonly = get_theme_color("font_color_readonly");
@@ -4870,9 +4729,6 @@ void TextEdit::_update_caches() {
cache.mark_color = get_theme_color("mark_color");
cache.current_line_color = get_theme_color("current_line_color");
cache.line_length_guideline_color = get_theme_color("line_length_guideline_color");
- cache.bookmark_color = get_theme_color("bookmark_color");
- cache.breakpoint_color = get_theme_color("breakpoint_color");
- cache.executing_line_color = get_theme_color("executing_line_color");
cache.code_folding_color = get_theme_color("code_folding_color");
cache.brace_mismatch_color = get_theme_color("brace_mismatch_color");
cache.word_highlighted_color = get_theme_color("word_highlighted_color");
@@ -4887,10 +4743,7 @@ void TextEdit::_update_caches() {
cache.row_height = cache.font->get_height() + cache.line_spacing;
cache.tab_icon = get_theme_icon("tab");
cache.space_icon = get_theme_icon("space");
- cache.folded_icon = get_theme_icon("folded");
- cache.can_fold_icon = get_theme_icon("fold");
cache.folded_eol_icon = get_theme_icon("GuiEllipsis", "EditorIcons");
- cache.executing_icon = get_theme_icon("MainPlay", "EditorIcons");
text.set_font(cache.font);
text.clear_width_cache();
@@ -4899,6 +4752,7 @@ void TextEdit::_update_caches() {
}
}
+/* Syntax Highlighting. */
Ref<SyntaxHighlighter> TextEdit::get_syntax_highlighter() {
return syntax_highlighter;
}
@@ -4911,6 +4765,187 @@ void TextEdit::set_syntax_highlighter(Ref<SyntaxHighlighter> p_syntax_highlighte
update();
}
+/* Gutters. */
+void TextEdit::_update_gutter_width() {
+ gutters_width = 0;
+ for (int i = 0; i < gutters.size(); i++) {
+ if (gutters[i].draw) {
+ gutters_width += gutters[i].width;
+ }
+ }
+ if (gutters_width > 0) {
+ gutter_padding = 2;
+ }
+ update();
+}
+
+void TextEdit::add_gutter(int p_at) {
+ if (p_at < 0 || p_at > gutters.size()) {
+ gutters.push_back(GutterInfo());
+ } else {
+ gutters.insert(p_at, GutterInfo());
+ }
+
+ for (int i = 0; i < text.size() + 1; i++) {
+ text.add_gutter(p_at);
+ }
+ emit_signal("gutter_added");
+ update();
+}
+
+void TextEdit::remove_gutter(int p_gutter) {
+ ERR_FAIL_INDEX(p_gutter, gutters.size());
+
+ gutters.remove(p_gutter);
+
+ for (int i = 0; i < text.size() + 1; i++) {
+ text.remove_gutter(p_gutter);
+ }
+ emit_signal("gutter_removed");
+ update();
+}
+
+int TextEdit::get_gutter_count() const {
+ return gutters.size();
+}
+
+void TextEdit::set_gutter_name(int p_gutter, const String &p_name) {
+ ERR_FAIL_INDEX(p_gutter, gutters.size());
+ gutters.write[p_gutter].name = p_name;
+}
+
+String TextEdit::get_gutter_name(int p_gutter) const {
+ ERR_FAIL_INDEX_V(p_gutter, gutters.size(), "");
+ return gutters[p_gutter].name;
+}
+
+void TextEdit::set_gutter_type(int p_gutter, GutterType p_type) {
+ ERR_FAIL_INDEX(p_gutter, gutters.size());
+ gutters.write[p_gutter].type = p_type;
+ update();
+}
+
+TextEdit::GutterType TextEdit::get_gutter_type(int p_gutter) const {
+ ERR_FAIL_INDEX_V(p_gutter, gutters.size(), GUTTER_TYPE_STRING);
+ return gutters[p_gutter].type;
+}
+
+void TextEdit::set_gutter_width(int p_gutter, int p_width) {
+ ERR_FAIL_INDEX(p_gutter, gutters.size());
+ gutters.write[p_gutter].width = p_width;
+ _update_gutter_width();
+}
+
+int TextEdit::get_gutter_width(int p_gutter) const {
+ ERR_FAIL_INDEX_V(p_gutter, gutters.size(), -1);
+ return gutters[p_gutter].width;
+}
+
+void TextEdit::set_gutter_draw(int p_gutter, bool p_draw) {
+ ERR_FAIL_INDEX(p_gutter, gutters.size());
+ gutters.write[p_gutter].draw = p_draw;
+ _update_gutter_width();
+}
+
+bool TextEdit::is_gutter_drawn(int p_gutter) const {
+ ERR_FAIL_INDEX_V(p_gutter, gutters.size(), false);
+ return gutters[p_gutter].draw;
+}
+
+void TextEdit::set_gutter_clickable(int p_gutter, bool p_clickable) {
+ ERR_FAIL_INDEX(p_gutter, gutters.size());
+ gutters.write[p_gutter].clickable = p_clickable;
+ update();
+}
+
+bool TextEdit::is_gutter_clickable(int p_gutter) const {
+ ERR_FAIL_INDEX_V(p_gutter, gutters.size(), false);
+ return gutters[p_gutter].clickable;
+}
+
+void TextEdit::set_gutter_overwritable(int p_gutter, bool p_overwritable) {
+ ERR_FAIL_INDEX(p_gutter, gutters.size());
+ gutters.write[p_gutter].overwritable = p_overwritable;
+}
+
+bool TextEdit::is_gutter_overwritable(int p_gutter) const {
+ ERR_FAIL_INDEX_V(p_gutter, gutters.size(), false);
+ return gutters[p_gutter].overwritable;
+}
+
+void TextEdit::set_gutter_custom_draw(int p_gutter, Object *p_object, const StringName &p_callback) {
+ ERR_FAIL_INDEX(p_gutter, gutters.size());
+ ERR_FAIL_NULL(p_object);
+
+ gutters.write[p_gutter].custom_draw_obj = p_object->get_instance_id();
+ gutters.write[p_gutter].custom_draw_callback = p_callback;
+ update();
+}
+
+// Line gutters.
+void TextEdit::set_line_gutter_metadata(int p_line, int p_gutter, const Variant &p_metadata) {
+ ERR_FAIL_INDEX(p_line, text.size());
+ ERR_FAIL_INDEX(p_gutter, gutters.size());
+ text.set_line_gutter_metadata(p_line, p_gutter, p_metadata);
+}
+
+Variant TextEdit::get_line_gutter_metadata(int p_line, int p_gutter) const {
+ ERR_FAIL_INDEX_V(p_line, text.size(), "");
+ ERR_FAIL_INDEX_V(p_gutter, gutters.size(), "");
+ return text.get_line_gutter_metadata(p_line, p_gutter);
+}
+
+void TextEdit::set_line_gutter_text(int p_line, int p_gutter, const String &p_text) {
+ ERR_FAIL_INDEX(p_line, text.size());
+ ERR_FAIL_INDEX(p_gutter, gutters.size());
+ text.set_line_gutter_text(p_line, p_gutter, p_text);
+ update();
+}
+
+String TextEdit::get_line_gutter_text(int p_line, int p_gutter) const {
+ ERR_FAIL_INDEX_V(p_line, text.size(), "");
+ ERR_FAIL_INDEX_V(p_gutter, gutters.size(), "");
+ return text.get_line_gutter_text(p_line, p_gutter);
+}
+
+void TextEdit::set_line_gutter_icon(int p_line, int p_gutter, Ref<Texture2D> p_icon) {
+ ERR_FAIL_INDEX(p_line, text.size());
+ ERR_FAIL_INDEX(p_gutter, gutters.size());
+ text.set_line_gutter_icon(p_line, p_gutter, p_icon);
+ update();
+}
+
+Ref<Texture2D> TextEdit::get_line_gutter_icon(int p_line, int p_gutter) const {
+ ERR_FAIL_INDEX_V(p_line, text.size(), Ref<Texture2D>());
+ ERR_FAIL_INDEX_V(p_gutter, gutters.size(), Ref<Texture2D>());
+ return text.get_line_gutter_icon(p_line, p_gutter);
+}
+
+void TextEdit::set_line_gutter_item_color(int p_line, int p_gutter, const Color &p_color) {
+ ERR_FAIL_INDEX(p_line, text.size());
+ ERR_FAIL_INDEX(p_gutter, gutters.size());
+ text.set_line_gutter_item_color(p_line, p_gutter, p_color);
+ update();
+}
+
+Color TextEdit::get_line_gutter_item_color(int p_line, int p_gutter) {
+ ERR_FAIL_INDEX_V(p_line, text.size(), Color());
+ ERR_FAIL_INDEX_V(p_gutter, gutters.size(), Color());
+ return text.get_line_gutter_item_color(p_line, p_gutter);
+}
+
+void TextEdit::set_line_gutter_clickable(int p_line, int p_gutter, bool p_clickable) {
+ ERR_FAIL_INDEX(p_line, text.size());
+ ERR_FAIL_INDEX(p_gutter, gutters.size());
+ text.set_line_gutter_clickable(p_line, p_gutter, p_clickable);
+}
+
+bool TextEdit::is_line_gutter_clickable(int p_line, int p_gutter) const {
+ ERR_FAIL_INDEX_V(p_line, text.size(), false);
+ ERR_FAIL_INDEX_V(p_gutter, gutters.size(), false);
+ return text.is_line_gutter_clickable(p_line, p_gutter);
+}
+
void TextEdit::add_keyword(const String &p_keyword) {
keywords.insert(p_keyword);
}
@@ -5341,106 +5376,6 @@ void TextEdit::set_line_as_marked(int p_line, bool p_marked) {
update();
}
-void TextEdit::set_line_as_safe(int p_line, bool p_safe) {
- ERR_FAIL_INDEX(p_line, text.size());
- text.set_safe(p_line, p_safe);
- update();
-}
-
-bool TextEdit::is_line_set_as_safe(int p_line) const {
- ERR_FAIL_INDEX_V(p_line, text.size(), false);
- return text.is_safe(p_line);
-}
-
-void TextEdit::set_executing_line(int p_line) {
- ERR_FAIL_INDEX(p_line, text.size());
- executing_line = p_line;
- update();
-}
-
-void TextEdit::clear_executing_line() {
- executing_line = -1;
- update();
-}
-
-bool TextEdit::is_line_set_as_bookmark(int p_line) const {
- ERR_FAIL_INDEX_V(p_line, text.size(), false);
- return text.is_bookmark(p_line);
-}
-
-void TextEdit::set_line_as_bookmark(int p_line, bool p_bookmark) {
- ERR_FAIL_INDEX(p_line, text.size());
- text.set_bookmark(p_line, p_bookmark);
- update();
-}
-
-void TextEdit::get_bookmarks(List<int> *p_bookmarks) const {
- for (int i = 0; i < text.size(); i++) {
- if (text.is_bookmark(i)) {
- p_bookmarks->push_back(i);
- }
- }
-}
-
-Array TextEdit::get_bookmarks_array() const {
- Array arr;
- for (int i = 0; i < text.size(); i++) {
- if (text.is_bookmark(i)) {
- arr.append(i);
- }
- }
- return arr;
-}
-
-bool TextEdit::is_line_set_as_breakpoint(int p_line) const {
- ERR_FAIL_INDEX_V(p_line, text.size(), false);
- return text.is_breakpoint(p_line);
-}
-
-void TextEdit::set_line_as_breakpoint(int p_line, bool p_breakpoint) {
- ERR_FAIL_INDEX(p_line, text.size());
- text.set_breakpoint(p_line, p_breakpoint);
- update();
-}
-
-void TextEdit::get_breakpoints(List<int> *p_breakpoints) const {
- for (int i = 0; i < text.size(); i++) {
- if (text.is_breakpoint(i)) {
- p_breakpoints->push_back(i);
- }
- }
-}
-
-Array TextEdit::get_breakpoints_array() const {
- Array arr;
- for (int i = 0; i < text.size(); i++) {
- if (text.is_breakpoint(i)) {
- arr.append(i);
- }
- }
- return arr;
-}
-
-void TextEdit::remove_breakpoints() {
- for (int i = 0; i < text.size(); i++) {
- if (text.is_breakpoint(i)) {
- /* Should "breakpoint_toggled" be fired when breakpoints are removed this way? */
- text.set_breakpoint(i, false);
- }
- }
-}
-
-void TextEdit::set_line_info_icon(int p_line, Ref<Texture2D> p_icon, String p_info) {
- ERR_FAIL_INDEX(p_line, text.size());
- text.set_info_icon(p_line, p_icon, p_info);
- update();
-}
-
-void TextEdit::clear_info_icons() {
- text.clear_info_icons();
- update();
-}
-
void TextEdit::set_line_as_hidden(int p_line, bool p_hidden) {
ERR_FAIL_INDEX(p_line, text.size());
if (is_hiding_enabled() || !p_hidden) {
@@ -6502,20 +6437,6 @@ void TextEdit::insert_at(const String &p_text, int at) {
}
}
-void TextEdit::set_show_line_numbers(bool p_show) {
- line_numbers = p_show;
- update();
-}
-
-void TextEdit::set_line_numbers_zero_padded(bool p_zero_padded) {
- line_numbers_zero_padded = p_zero_padded;
- update();
-}
-
-bool TextEdit::is_show_line_numbers_enabled() const {
- return line_numbers;
-}
-
void TextEdit::set_show_line_length_guidelines(bool p_show) {
line_length_guidelines = p_show;
update();
@@ -6531,69 +6452,6 @@ void TextEdit::set_line_length_guideline_hard_column(int p_column) {
update();
}
-void TextEdit::set_bookmark_gutter_enabled(bool p_draw) {
- draw_bookmark_gutter = p_draw;
- update();
-}
-
-bool TextEdit::is_bookmark_gutter_enabled() const {
- return draw_bookmark_gutter;
-}
-
-void TextEdit::set_breakpoint_gutter_enabled(bool p_draw) {
- draw_breakpoint_gutter = p_draw;
- update();
-}
-
-bool TextEdit::is_breakpoint_gutter_enabled() const {
- return draw_breakpoint_gutter;
-}
-
-void TextEdit::set_breakpoint_gutter_width(int p_gutter_width) {
- breakpoint_gutter_width = p_gutter_width;
- update();
-}
-
-int TextEdit::get_breakpoint_gutter_width() const {
- return cache.breakpoint_gutter_width;
-}
-
-void TextEdit::set_draw_fold_gutter(bool p_draw) {
- draw_fold_gutter = p_draw;
- update();
-}
-
-bool TextEdit::is_drawing_fold_gutter() const {
- return draw_fold_gutter;
-}
-
-void TextEdit::set_fold_gutter_width(int p_gutter_width) {
- fold_gutter_width = p_gutter_width;
- update();
-}
-
-int TextEdit::get_fold_gutter_width() const {
- return cache.fold_gutter_width;
-}
-
-void TextEdit::set_draw_info_gutter(bool p_draw) {
- draw_info_gutter = p_draw;
- update();
-}
-
-bool TextEdit::is_drawing_info_gutter() const {
- return draw_info_gutter;
-}
-
-void TextEdit::set_info_gutter_width(int p_gutter_width) {
- info_gutter_width = p_gutter_width;
- update();
-}
-
-int TextEdit::get_info_gutter_width() const {
- return info_gutter_width;
-}
-
void TextEdit::set_draw_minimap(bool p_draw) {
draw_minimap = p_draw;
update();
@@ -6800,16 +6658,10 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("redo"), &TextEdit::redo);
ClassDB::bind_method(D_METHOD("clear_undo_history"), &TextEdit::clear_undo_history);
- ClassDB::bind_method(D_METHOD("set_show_line_numbers", "enable"), &TextEdit::set_show_line_numbers);
- ClassDB::bind_method(D_METHOD("is_show_line_numbers_enabled"), &TextEdit::is_show_line_numbers_enabled);
ClassDB::bind_method(D_METHOD("set_draw_tabs"), &TextEdit::set_draw_tabs);
ClassDB::bind_method(D_METHOD("is_drawing_tabs"), &TextEdit::is_drawing_tabs);
ClassDB::bind_method(D_METHOD("set_draw_spaces"), &TextEdit::set_draw_spaces);
ClassDB::bind_method(D_METHOD("is_drawing_spaces"), &TextEdit::is_drawing_spaces);
- ClassDB::bind_method(D_METHOD("set_breakpoint_gutter_enabled", "enable"), &TextEdit::set_breakpoint_gutter_enabled);
- ClassDB::bind_method(D_METHOD("is_breakpoint_gutter_enabled"), &TextEdit::is_breakpoint_gutter_enabled);
- ClassDB::bind_method(D_METHOD("set_draw_fold_gutter"), &TextEdit::set_draw_fold_gutter);
- ClassDB::bind_method(D_METHOD("is_drawing_fold_gutter"), &TextEdit::is_drawing_fold_gutter);
ClassDB::bind_method(D_METHOD("set_hiding_enabled", "enable"), &TextEdit::set_hiding_enabled);
ClassDB::bind_method(D_METHOD("is_hiding_enabled"), &TextEdit::is_hiding_enabled);
@@ -6832,6 +6684,40 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_syntax_highlighter", "syntax_highlighter"), &TextEdit::set_syntax_highlighter);
ClassDB::bind_method(D_METHOD("get_syntax_highlighter"), &TextEdit::get_syntax_highlighter);
+ /* Gutters. */
+ BIND_ENUM_CONSTANT(GUTTER_TYPE_STRING);
+ BIND_ENUM_CONSTANT(GUTTER_TPYE_ICON);
+ BIND_ENUM_CONSTANT(GUTTER_TPYE_CUSTOM);
+
+ ClassDB::bind_method(D_METHOD("add_gutter", "at"), &TextEdit::add_gutter, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("remove_gutter", "gutter"), &TextEdit::remove_gutter);
+ ClassDB::bind_method(D_METHOD("get_gutter_count"), &TextEdit::get_gutter_count);
+ ClassDB::bind_method(D_METHOD("set_gutter_name", "gutter", "name"), &TextEdit::set_gutter_name);
+ ClassDB::bind_method(D_METHOD("get_gutter_name", "gutter"), &TextEdit::get_gutter_name);
+ ClassDB::bind_method(D_METHOD("set_gutter_type", "gutter", "type"), &TextEdit::set_gutter_type);
+ ClassDB::bind_method(D_METHOD("get_gutter_type", "gutter"), &TextEdit::get_gutter_type);
+ ClassDB::bind_method(D_METHOD("set_gutter_width", "gutter", "width"), &TextEdit::set_gutter_width);
+ ClassDB::bind_method(D_METHOD("get_gutter_width", "gutter"), &TextEdit::get_gutter_width);
+ ClassDB::bind_method(D_METHOD("set_gutter_draw", "gutter", "draw"), &TextEdit::set_gutter_draw);
+ ClassDB::bind_method(D_METHOD("is_gutter_drawn", "gutter"), &TextEdit::is_gutter_drawn);
+ ClassDB::bind_method(D_METHOD("set_gutter_clickable", "gutter", "clickable"), &TextEdit::set_gutter_clickable);
+ ClassDB::bind_method(D_METHOD("is_gutter_clickable", "gutter"), &TextEdit::is_gutter_clickable);
+ ClassDB::bind_method(D_METHOD("set_gutter_overwritable", "gutter", "overwritable"), &TextEdit::set_gutter_overwritable);
+ ClassDB::bind_method(D_METHOD("is_gutter_overwritable", "gutter"), &TextEdit::is_gutter_overwritable);
+ ClassDB::bind_method(D_METHOD("set_gutter_custom_draw", "column", "object", "callback"), &TextEdit::set_gutter_custom_draw);
+
+ // Line gutters.
+ ClassDB::bind_method(D_METHOD("set_line_gutter_metadata", "line", "gutter", "metadata"), &TextEdit::set_line_gutter_metadata);
+ ClassDB::bind_method(D_METHOD("get_line_gutter_metadata", "line", "gutter"), &TextEdit::get_line_gutter_metadata);
+ ClassDB::bind_method(D_METHOD("set_line_gutter_text", "line", "gutter", "text"), &TextEdit::set_line_gutter_text);
+ ClassDB::bind_method(D_METHOD("get_line_gutter_text", "line", "gutter"), &TextEdit::get_line_gutter_text);
+ ClassDB::bind_method(D_METHOD("set_line_gutter_icon", "line", "gutter", "icon"), &TextEdit::set_line_gutter_icon);
+ ClassDB::bind_method(D_METHOD("get_line_gutter_icon", "line", "gutter"), &TextEdit::get_line_gutter_icon);
+ ClassDB::bind_method(D_METHOD("set_line_gutter_item_color", "line", "gutter", "color"), &TextEdit::set_line_gutter_item_color);
+ ClassDB::bind_method(D_METHOD("get_line_gutter_item_color", "line", "gutter"), &TextEdit::get_line_gutter_item_color);
+ ClassDB::bind_method(D_METHOD("set_line_gutter_clickable", "line", "gutter", "clickable"), &TextEdit::set_line_gutter_clickable);
+ ClassDB::bind_method(D_METHOD("is_line_gutter_clickable", "line", "gutter"), &TextEdit::is_line_gutter_clickable);
+
ClassDB::bind_method(D_METHOD("set_highlight_current_line", "enabled"), &TextEdit::set_highlight_current_line);
ClassDB::bind_method(D_METHOD("is_highlight_current_line_enabled"), &TextEdit::is_highlight_current_line_enabled);
@@ -6847,9 +6733,6 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("menu_option", "option"), &TextEdit::menu_option);
ClassDB::bind_method(D_METHOD("get_menu"), &TextEdit::get_menu);
- 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);
@@ -6858,11 +6741,8 @@ void TextEdit::_bind_methods() {
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");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_line_numbers"), "set_show_line_numbers", "is_show_line_numbers_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_tabs"), "set_draw_tabs", "is_drawing_tabs");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_spaces"), "set_draw_spaces", "is_drawing_spaces");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "breakpoint_gutter"), "set_breakpoint_gutter_enabled", "is_breakpoint_gutter_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fold_gutter"), "set_draw_fold_gutter", "is_drawing_fold_gutter");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_all_occurrences"), "set_highlight_all_occurrences", "is_highlight_all_occurrences_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_selected_font_color"), "set_override_selected_font_color", "is_overriding_selected_font_color");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled");
@@ -6890,11 +6770,12 @@ void TextEdit::_bind_methods() {
ADD_SIGNAL(MethodInfo("cursor_changed"));
ADD_SIGNAL(MethodInfo("text_changed"));
- ADD_SIGNAL(MethodInfo("line_edited_from", PropertyInfo(Variant::INT, "line")));
+ ADD_SIGNAL(MethodInfo("lines_edited_from", PropertyInfo(Variant::INT, "from_line"), PropertyInfo(Variant::INT, "to_line")));
ADD_SIGNAL(MethodInfo("request_completion"));
- ADD_SIGNAL(MethodInfo("breakpoint_toggled", PropertyInfo(Variant::INT, "row")));
+ ADD_SIGNAL(MethodInfo("gutter_clicked", PropertyInfo(Variant::INT, "line"), PropertyInfo(Variant::INT, "gutter")));
+ ADD_SIGNAL(MethodInfo("gutter_added"));
+ ADD_SIGNAL(MethodInfo("gutter_removed"));
ADD_SIGNAL(MethodInfo("symbol_lookup", PropertyInfo(Variant::STRING, "symbol"), PropertyInfo(Variant::INT, "row"), PropertyInfo(Variant::INT, "column")));
- ADD_SIGNAL(MethodInfo("info_clicked", PropertyInfo(Variant::INT, "row"), PropertyInfo(Variant::STRING, "info")));
ADD_SIGNAL(MethodInfo("symbol_validate", PropertyInfo(Variant::STRING, "symbol")));
BIND_ENUM_CONSTANT(MENU_CUT);
@@ -6927,13 +6808,6 @@ TextEdit::TextEdit() {
_update_caches();
cache.row_height = 1;
cache.line_spacing = 1;
- cache.line_number_w = 1;
- cache.breakpoint_gutter_width = 0;
- breakpoint_gutter_width = 0;
- cache.fold_gutter_width = 0;
- fold_gutter_width = 0;
- info_gutter_width = 0;
- cache.info_gutter_width = 0;
set_default_cursor_shape(CURSOR_IBEAM);
indent_size = 4;
@@ -6997,15 +6871,9 @@ TextEdit::TextEdit() {
completion_active = false;
completion_line_ofs = 0;
tooltip_obj = nullptr;
- line_numbers = false;
- line_numbers_zero_padded = false;
line_length_guidelines = false;
line_length_guideline_soft_col = 80;
line_length_guideline_hard_col = 100;
- draw_bookmark_gutter = false;
- draw_breakpoint_gutter = false;
- draw_fold_gutter = false;
- draw_info_gutter = false;
hiding_enabled = false;
next_operation_is_complex = false;
scroll_past_end_of_file_enabled = false;
@@ -7043,8 +6911,6 @@ TextEdit::TextEdit() {
set_readonly(false);
menu->connect("id_pressed", callable_mp(this, &TextEdit::menu_option));
first_draw = true;
-
- executing_line = -1;
}
TextEdit::~TextEdit() {
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 70d7365d71..562f4768ae 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -41,28 +41,53 @@ class TextEdit : public Control {
GDCLASS(TextEdit, Control);
public:
+ enum GutterType {
+ GUTTER_TYPE_STRING,
+ GUTTER_TPYE_ICON,
+ GUTTER_TPYE_CUSTOM
+ };
+
+private:
+ struct GutterInfo {
+ GutterType type = GutterType::GUTTER_TYPE_STRING;
+ String name = "";
+ int width = 24;
+ bool draw = true;
+ bool clickable = false;
+ bool overwritable = false;
+
+ ObjectID custom_draw_obj = ObjectID();
+ StringName custom_draw_callback;
+ };
+ Vector<GutterInfo> gutters;
+ int gutters_width = 0;
+ int gutter_padding = 0;
+
+ void _update_gutter_width();
+
class Text {
public:
+ struct Gutter {
+ Variant metadata;
+ bool clickable = false;
+
+ Ref<Texture2D> icon = Ref<Texture2D>();
+ String text = "";
+ Color color = Color(1, 1, 1);
+ };
+
struct Line {
- int width_cache : 24;
- bool marked : 1;
- bool breakpoint : 1;
- bool bookmark : 1;
- bool hidden : 1;
- bool safe : 1;
- bool has_info : 1;
- int wrap_amount_cache : 24;
- Ref<Texture2D> info_icon;
- String info;
+ Vector<Gutter> gutters;
+
+ int32_t width_cache;
+ bool marked;
+ bool hidden;
+ int32_t wrap_amount_cache;
String data;
Line() {
width_cache = 0;
marked = false;
- breakpoint = false;
- bookmark = false;
hidden = false;
- safe = false;
- has_info = false;
wrap_amount_cache = 0;
}
};
@@ -70,7 +95,8 @@ public:
private:
mutable Vector<Line> text;
Ref<Font> font;
- int indent_size;
+ int indent_size = 4;
+ int gutter_count = 0;
void _update_line_cache(int p_line) const;
@@ -85,38 +111,37 @@ public:
void set(int p_line, const String &p_text);
void set_marked(int p_line, bool p_marked) { text.write[p_line].marked = p_marked; }
bool is_marked(int p_line) const { return text[p_line].marked; }
- void set_bookmark(int p_line, bool p_bookmark) { text.write[p_line].bookmark = p_bookmark; }
- bool is_bookmark(int p_line) const { return text[p_line].bookmark; }
- void set_breakpoint(int p_line, bool p_breakpoint) { text.write[p_line].breakpoint = p_breakpoint; }
- bool is_breakpoint(int p_line) const { return text[p_line].breakpoint; }
void set_hidden(int p_line, bool p_hidden) { text.write[p_line].hidden = p_hidden; }
bool is_hidden(int p_line) const { return text[p_line].hidden; }
- void set_safe(int p_line, bool p_safe) { text.write[p_line].safe = p_safe; }
- bool is_safe(int p_line) const { return text[p_line].safe; }
- void set_info_icon(int p_line, Ref<Texture2D> p_icon, String p_info) {
- if (p_icon.is_null()) {
- text.write[p_line].has_info = false;
- return;
- }
- text.write[p_line].info_icon = p_icon;
- text.write[p_line].info = p_info;
- text.write[p_line].has_info = true;
- }
- bool has_info_icon(int p_line) const { return text[p_line].has_info; }
- const Ref<Texture2D> &get_info_icon(int p_line) const { return text[p_line].info_icon; }
- const String &get_info(int p_line) const { return text[p_line].info; }
void insert(int p_at, const String &p_text);
void remove(int p_at);
int size() const { return text.size(); }
void clear();
void clear_width_cache();
void clear_wrap_cache();
- void clear_info_icons();
_FORCE_INLINE_ const String &operator[](int p_line) const { return text[p_line].data; }
- Text() { indent_size = 4; }
+
+ /* Gutters. */
+ void add_gutter(int p_at);
+ void remove_gutter(int p_gutter);
+ void move_gutters(int p_from_line, int p_to_line);
+
+ void set_line_gutter_metadata(int p_line, int p_gutter, const Variant &p_metadata) { text.write[p_line].gutters.write[p_gutter].metadata = p_metadata; }
+ const Variant &get_line_gutter_metadata(int p_line, int p_gutter) const { return text[p_line].gutters[p_gutter].metadata; }
+
+ void set_line_gutter_text(int p_line, int p_gutter, const String &p_text) { text.write[p_line].gutters.write[p_gutter].text = p_text; }
+ const String &get_line_gutter_text(int p_line, int p_gutter) const { return text[p_line].gutters[p_gutter].text; }
+
+ void set_line_gutter_icon(int p_line, int p_gutter, Ref<Texture2D> p_icon) { text.write[p_line].gutters.write[p_gutter].icon = p_icon; }
+ const Ref<Texture2D> &get_line_gutter_icon(int p_line, int p_gutter) const { return text[p_line].gutters[p_gutter].icon; }
+
+ void set_line_gutter_item_color(int p_line, int p_gutter, const Color &p_color) { text.write[p_line].gutters.write[p_gutter].color = p_color; }
+ const Color &get_line_gutter_item_color(int p_line, int p_gutter) const { return text[p_line].gutters[p_gutter].color; }
+
+ void set_line_gutter_clickable(int p_line, int p_gutter, bool p_clickable) { text.write[p_line].gutters.write[p_gutter].clickable = p_clickable; }
+ bool is_line_gutter_clickable(int p_line, int p_gutter) const { return text[p_line].gutters[p_gutter].clickable; }
};
-private:
struct Cursor {
int last_fit_x;
int line, column; ///< cursor
@@ -169,60 +194,6 @@ private:
}
} selection;
- struct Cache {
- Ref<Texture2D> tab_icon;
- Ref<Texture2D> space_icon;
- Ref<Texture2D> can_fold_icon;
- Ref<Texture2D> folded_icon;
- Ref<Texture2D> folded_eol_icon;
- Ref<Texture2D> executing_icon;
- Ref<StyleBox> style_normal;
- Ref<StyleBox> style_focus;
- Ref<StyleBox> style_readonly;
- Ref<Font> font;
- Color completion_background_color;
- Color completion_selected_color;
- Color completion_existing_color;
- Color completion_font_color;
- Color caret_color;
- Color caret_background_color;
- Color line_number_color;
- Color safe_line_number_color;
- Color font_color;
- Color font_color_selected;
- Color font_color_readonly;
- Color selection_color;
- Color mark_color;
- Color bookmark_color;
- Color breakpoint_color;
- Color executing_line_color;
- Color code_folding_color;
- Color current_line_color;
- Color line_length_guideline_color;
- Color brace_mismatch_color;
- Color word_highlighted_color;
- Color search_result_color;
- Color search_result_border_color;
- Color background_color;
-
- int row_height;
- int line_spacing;
- int line_number_w;
- int breakpoint_gutter_width;
- int fold_gutter_width;
- int info_gutter_width;
- int minimap_width;
- Cache() {
- row_height = 0;
- line_spacing = 0;
- line_number_w = 0;
- breakpoint_gutter_width = 0;
- fold_gutter_width = 0;
- info_gutter_width = 0;
- minimap_width = 0;
- }
- } cache;
-
Map<int, Dictionary> syntax_highlighting_cache;
struct TextOperation {
@@ -318,19 +289,10 @@ private:
bool cursor_changed_dirty;
bool text_changed_dirty;
bool undo_enabled;
- bool line_numbers;
- bool line_numbers_zero_padded;
bool line_length_guidelines;
int line_length_guideline_soft_col;
int line_length_guideline_hard_col;
- bool draw_bookmark_gutter;
- bool draw_breakpoint_gutter;
- int breakpoint_gutter_width;
- bool draw_fold_gutter;
- int fold_gutter_width;
bool hiding_enabled;
- bool draw_info_gutter;
- int info_gutter_width;
bool draw_minimap;
int minimap_width;
Point2 minimap_char_size;
@@ -385,11 +347,8 @@ private:
bool context_menu_enabled;
bool shortcut_keys_enabled;
-
bool virtual_keyboard_enabled = true;
- int executing_line;
-
void _generate_context_menu();
int get_visible_rows() const;
@@ -447,8 +406,6 @@ private:
Size2 get_minimum_size() const override;
int _get_control_height() const;
- int get_row_height() const;
-
void _reset_caret_blink_timer();
void _toggle_draw_caret();
@@ -480,6 +437,44 @@ private:
int _calculate_spaces_till_next_right_indent(int column);
protected:
+ struct Cache {
+ Ref<Texture2D> tab_icon;
+ Ref<Texture2D> space_icon;
+ Ref<Texture2D> folded_eol_icon;
+ Ref<StyleBox> style_normal;
+ Ref<StyleBox> style_focus;
+ Ref<StyleBox> style_readonly;
+ Ref<Font> font;
+ Color completion_background_color;
+ Color completion_selected_color;
+ Color completion_existing_color;
+ Color completion_font_color;
+ Color caret_color;
+ Color caret_background_color;
+ Color font_color;
+ Color font_color_selected;
+ Color font_color_readonly;
+ Color selection_color;
+ Color mark_color;
+ Color code_folding_color;
+ Color current_line_color;
+ Color line_length_guideline_color;
+ Color brace_mismatch_color;
+ Color word_highlighted_color;
+ Color search_result_color;
+ Color search_result_border_color;
+ Color background_color;
+
+ int row_height;
+ int line_spacing;
+ int minimap_width;
+ Cache() {
+ row_height = 0;
+ line_spacing = 0;
+ minimap_width = 0;
+ }
+ } cache;
+
virtual String get_tooltip(const Point2 &p_pos) const override;
void _insert_text(int p_line, int p_char, const String &p_text, int *r_end_line = nullptr, int *r_end_char = nullptr);
@@ -494,9 +489,51 @@ protected:
static void _bind_methods();
public:
+ /* Syntax Highlighting. */
Ref<SyntaxHighlighter> get_syntax_highlighter();
void set_syntax_highlighter(Ref<SyntaxHighlighter> p_syntax_highlighter);
+ /* Gutters. */
+ void add_gutter(int p_at = -1);
+ void remove_gutter(int p_gutter);
+ int get_gutter_count() const;
+
+ void set_gutter_name(int p_gutter, const String &p_name);
+ String get_gutter_name(int p_gutter) const;
+
+ void set_gutter_type(int p_gutter, GutterType p_type);
+ GutterType get_gutter_type(int p_gutter) const;
+
+ void set_gutter_width(int p_gutter, int p_width);
+ int get_gutter_width(int p_gutter) const;
+
+ void set_gutter_draw(int p_gutter, bool p_draw);
+ bool is_gutter_drawn(int p_gutter) const;
+
+ void set_gutter_clickable(int p_gutter, bool p_clickable);
+ bool is_gutter_clickable(int p_gutter) const;
+
+ void set_gutter_overwritable(int p_gutter, bool p_overwritable);
+ bool is_gutter_overwritable(int p_gutter) const;
+
+ void set_gutter_custom_draw(int p_gutter, Object *p_object, const StringName &p_callback);
+
+ // Line gutters.
+ void set_line_gutter_metadata(int p_line, int p_gutter, const Variant &p_metadata);
+ Variant get_line_gutter_metadata(int p_line, int p_gutter) const;
+
+ void set_line_gutter_text(int p_line, int p_gutter, const String &p_text);
+ String get_line_gutter_text(int p_line, int p_gutter) const;
+
+ void set_line_gutter_icon(int p_line, int p_gutter, Ref<Texture2D> p_icon);
+ Ref<Texture2D> get_line_gutter_icon(int p_line, int p_gutter) const;
+
+ void set_line_gutter_item_color(int p_line, int p_gutter, const Color &p_color);
+ Color get_line_gutter_item_color(int p_line, int p_gutter);
+
+ void set_line_gutter_clickable(int p_line, int p_gutter, bool p_clickable);
+ bool is_line_gutter_clickable(int p_line, int p_gutter) const;
+
enum MenuItems {
MENU_CUT,
MENU_COPY,
@@ -534,22 +571,6 @@ public:
void insert_at(const String &p_text, int at);
int get_line_count() const;
void set_line_as_marked(int p_line, bool p_marked);
- void set_line_as_bookmark(int p_line, bool p_bookmark);
- bool is_line_set_as_bookmark(int p_line) const;
- void get_bookmarks(List<int> *p_bookmarks) const;
- Array get_bookmarks_array() const;
- void set_line_as_breakpoint(int p_line, bool p_breakpoint);
- bool is_line_set_as_breakpoint(int p_line) const;
- void set_executing_line(int p_line);
- void clear_executing_line();
- void set_line_as_safe(int p_line, bool p_safe);
- bool is_line_set_as_safe(int p_line) const;
- void get_breakpoints(List<int> *p_breakpoints) const;
- Array get_breakpoints_array() const;
- void remove_breakpoints();
-
- void set_line_info_icon(int p_line, Ref<Texture2D> p_icon, String p_info = "");
- void clear_info_icons();
void set_line_as_hidden(int p_line, bool p_hidden);
bool is_line_hidden(int p_line) const;
@@ -569,6 +590,7 @@ public:
String get_text();
String get_line(int line) const;
void set_line(int line, String new_text);
+ int get_row_height() const;
void backspace_at_cursor();
void indent_left();
@@ -690,39 +712,13 @@ public:
void menu_option(int p_option);
- void set_show_line_numbers(bool p_show);
- bool is_show_line_numbers_enabled() const;
-
void set_highlight_current_line(bool p_enabled);
bool is_highlight_current_line_enabled() const;
- void set_line_numbers_zero_padded(bool p_zero_padded);
-
void set_show_line_length_guidelines(bool p_show);
void set_line_length_guideline_soft_column(int p_column);
void set_line_length_guideline_hard_column(int p_column);
- void set_bookmark_gutter_enabled(bool p_draw);
- bool is_bookmark_gutter_enabled() const;
-
- void set_breakpoint_gutter_enabled(bool p_draw);
- bool is_breakpoint_gutter_enabled() const;
-
- void set_breakpoint_gutter_width(int p_gutter_width);
- int get_breakpoint_gutter_width() const;
-
- void set_draw_fold_gutter(bool p_draw);
- bool is_drawing_fold_gutter() const;
-
- void set_fold_gutter_width(int p_gutter_width);
- int get_fold_gutter_width() const;
-
- void set_draw_info_gutter(bool p_draw);
- bool is_drawing_info_gutter() const;
-
- 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;
@@ -764,6 +760,7 @@ public:
~TextEdit();
};
+VARIANT_ENUM_CAST(TextEdit::GutterType);
VARIANT_ENUM_CAST(TextEdit::MenuItems);
VARIANT_ENUM_CAST(TextEdit::SearchFlags);
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 5cd45ea408..796408a38d 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -1369,6 +1369,7 @@ void CanvasItem::set_texture_filter(TextureFilter p_texture_filter) {
}
texture_filter = p_texture_filter;
_update_texture_filter_changed(true);
+ _change_notify();
}
CanvasItem::TextureFilter CanvasItem::get_texture_filter() const {
@@ -1421,6 +1422,7 @@ void CanvasItem::set_texture_repeat(TextureRepeat p_texture_repeat) {
}
texture_repeat = p_texture_repeat;
_update_texture_repeat_changed(true);
+ _change_notify();
}
CanvasItem::TextureRepeat CanvasItem::get_texture_repeat() const {
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
index d9ffe770ff..3f32df87a7 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -405,10 +405,10 @@ public:
void force_update_transform();
- void set_texture_filter(TextureFilter p_texture_filter);
+ virtual void set_texture_filter(TextureFilter p_texture_filter);
TextureFilter get_texture_filter() const;
- void set_texture_repeat(TextureRepeat p_texture_repeat);
+ virtual void set_texture_repeat(TextureRepeat p_texture_repeat);
TextureRepeat get_texture_repeat() const;
// Used by control nodes to retrieve the parent's anchorable area
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index 2b506b686b..da0169b60b 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -631,6 +631,7 @@ void HTTPRequest::_bind_methods() {
BIND_ENUM_CONSTANT(RESULT_SSL_HANDSHAKE_ERROR);
BIND_ENUM_CONSTANT(RESULT_NO_RESPONSE);
BIND_ENUM_CONSTANT(RESULT_BODY_SIZE_LIMIT_EXCEEDED);
+ BIND_ENUM_CONSTANT(RESULT_BODY_DECOMPRESS_FAILED);
BIND_ENUM_CONSTANT(RESULT_REQUEST_FAILED);
BIND_ENUM_CONSTANT(RESULT_DOWNLOAD_FILE_CANT_OPEN);
BIND_ENUM_CONSTANT(RESULT_DOWNLOAD_FILE_WRITE_ERROR);
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index 0f74f2e973..e5ab4f9958 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SCENE_MAIN_LOOP_H
-#define SCENE_MAIN_LOOP_H
+#ifndef SCENE_TREE_H
+#define SCENE_TREE_H
#include "core/io/multiplayer_api.h"
#include "core/os/main_loop.h"
@@ -354,4 +354,4 @@ public:
VARIANT_ENUM_CAST(SceneTree::GroupCallFlags);
-#endif
+#endif // SCENE_TREE_H
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index d962171555..b29b40ea5f 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -1509,7 +1509,7 @@ void Viewport::_gui_show_tooltip() {
}
Control *which = nullptr;
- String tooltip = _gui_get_tooltip(gui.tooltip, gui.tooltip->get_global_transform().xform_inv(gui.tooltip_pos), &which);
+ String tooltip = _gui_get_tooltip(gui.tooltip, gui.tooltip->get_global_transform().xform_inv(gui.last_mouse_pos), &which);
tooltip = tooltip.strip_edges();
if (tooltip.length() == 0) {
return; // bye
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 0f6475cf0d..820513c53d 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -81,6 +81,7 @@
#include "scene/gui/center_container.h"
#include "scene/gui/check_box.h"
#include "scene/gui/check_button.h"
+#include "scene/gui/code_edit.h"
#include "scene/gui/color_picker.h"
#include "scene/gui/color_rect.h"
#include "scene/gui/control.h"
@@ -230,6 +231,7 @@ static Ref<ResourceFormatLoaderDynamicFont> resource_loader_dynamic_font;
static Ref<ResourceFormatLoaderStreamTexture2D> resource_loader_stream_texture;
static Ref<ResourceFormatLoaderStreamTextureLayered> resource_loader_texture_layered;
+static Ref<ResourceFormatLoaderStreamTexture3D> resource_loader_texture_3d;
static Ref<ResourceFormatLoaderBMFont> resource_loader_bmfont;
@@ -252,6 +254,9 @@ void register_scene_types() {
resource_loader_texture_layered.instance();
ResourceLoader::add_resource_format_loader(resource_loader_texture_layered);
+ resource_loader_texture_3d.instance();
+ ResourceLoader::add_resource_format_loader(resource_loader_texture_3d);
+
resource_saver_text.instance();
ResourceSaver::add_resource_format_saver(resource_saver_text, true);
@@ -291,7 +296,7 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
- ClassDB::register_class<ShortCut>();
+ ClassDB::register_class<Shortcut>();
ClassDB::register_class<Control>();
ClassDB::register_class<Button>();
ClassDB::register_class<Label>();
@@ -347,6 +352,7 @@ void register_scene_types() {
ClassDB::register_class<Tree>();
ClassDB::register_class<TextEdit>();
+ ClassDB::register_class<CodeEdit>();
ClassDB::register_class<SyntaxHighlighter>();
ClassDB::register_class<CodeHighlighter>();
@@ -549,6 +555,7 @@ void register_scene_types() {
ClassDB::register_class<VisualShaderNodeTexture>();
ClassDB::register_virtual_class<VisualShaderNodeSample3D>();
ClassDB::register_class<VisualShaderNodeTexture2DArray>();
+ ClassDB::register_class<VisualShaderNodeTexture3D>();
ClassDB::register_class<VisualShaderNodeCubemap>();
ClassDB::register_virtual_class<VisualShaderNodeUniform>();
ClassDB::register_class<VisualShaderNodeUniformRef>();
@@ -561,6 +568,7 @@ void register_scene_types() {
ClassDB::register_class<VisualShaderNodeTextureUniform>();
ClassDB::register_class<VisualShaderNodeTextureUniformTriplanar>();
ClassDB::register_class<VisualShaderNodeTexture2DArrayUniform>();
+ ClassDB::register_class<VisualShaderNodeTexture3DUniform>();
ClassDB::register_class<VisualShaderNodeCubemapUniform>();
ClassDB::register_class<VisualShaderNodeIf>();
ClassDB::register_class<VisualShaderNodeSwitch>();
@@ -701,6 +709,9 @@ void register_scene_types() {
ClassDB::register_class<CameraTexture>();
ClassDB::register_virtual_class<TextureLayered>();
ClassDB::register_virtual_class<ImageTextureLayered>();
+ ClassDB::register_virtual_class<Texture3D>();
+ ClassDB::register_class<ImageTexture3D>();
+ ClassDB::register_class<StreamTexture3D>();
ClassDB::register_class<Cubemap>();
ClassDB::register_class<CubemapArray>();
ClassDB::register_class<Texture2DArray>();
@@ -864,6 +875,7 @@ void register_scene_types() {
ClassDB::add_compatibility_class("RemoteTransform", "RemoteTransform3D");
ClassDB::add_compatibility_class("RigidBody", "RigidBody3D");
ClassDB::add_compatibility_class("Shape", "Shape3D");
+ ClassDB::add_compatibility_class("ShortCut", "Shortcut");
ClassDB::add_compatibility_class("Skeleton", "Skeleton3D");
ClassDB::add_compatibility_class("SkeletonIK", "SkeletonIK3D");
ClassDB::add_compatibility_class("SliderJoint", "SliderJoint3D");
@@ -946,6 +958,9 @@ void unregister_scene_types() {
ResourceLoader::remove_resource_format_loader(resource_loader_texture_layered);
resource_loader_texture_layered.unref();
+ ResourceLoader::remove_resource_format_loader(resource_loader_texture_3d);
+ resource_loader_texture_3d.unref();
+
ResourceLoader::remove_resource_format_loader(resource_loader_stream_texture);
resource_loader_stream_texture.unref();
diff --git a/scene/resources/default_theme/bookmark.png b/scene/resources/default_theme/bookmark.png
new file mode 100644
index 0000000000..9718cf53b6
--- /dev/null
+++ b/scene/resources/default_theme/bookmark.png
Binary files differ
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 9008f6d5b9..f65f78b332 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -382,8 +382,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("tab", "TextEdit", make_icon(tab_png));
theme->set_icon("space", "TextEdit", make_icon(space_png));
- theme->set_icon("folded", "TextEdit", make_icon(arrow_right_png));
- theme->set_icon("fold", "TextEdit", make_icon(arrow_down_png));
theme->set_font("font", "TextEdit", Ref<Font>());
@@ -398,16 +396,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_color_readonly", "TextEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f));
theme->set_color("selection_color", "TextEdit", font_color_selection);
theme->set_color("mark_color", "TextEdit", Color(1.0, 0.4, 0.4, 0.4));
- theme->set_color("bookmark_color", "TextEdit", Color(0.08, 0.49, 0.98));
- theme->set_color("breakpoint_color", "TextEdit", Color(0.8, 0.8, 0.4, 0.2));
- theme->set_color("executing_line_color", "TextEdit", Color(0.2, 0.8, 0.2, 0.4));
theme->set_color("code_folding_color", "TextEdit", Color(0.8, 0.8, 0.8, 0.8));
theme->set_color("current_line_color", "TextEdit", Color(0.25, 0.25, 0.26, 0.8));
theme->set_color("caret_color", "TextEdit", control_font_color);
theme->set_color("caret_background_color", "TextEdit", Color(0, 0, 0));
theme->set_color("brace_mismatch_color", "TextEdit", Color(1, 0.2, 0.2));
- theme->set_color("line_number_color", "TextEdit", Color(0.67, 0.67, 0.67, 0.4));
- theme->set_color("safe_line_number_color", "TextEdit", Color(0.67, 0.78, 0.67, 0.6));
theme->set_color("word_highlighted_color", "TextEdit", Color(0.8, 0.9, 0.9, 0.15));
theme->set_constant("completion_lines", "TextEdit", 7);
@@ -415,6 +408,50 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("completion_scroll_width", "TextEdit", 3);
theme->set_constant("line_spacing", "TextEdit", 4 * scale);
+ // CodeEdit
+ theme->set_stylebox("normal", "CodeEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3, 0, 0, 0, 0));
+ theme->set_stylebox("focus", "CodeEdit", focus);
+ theme->set_stylebox("read_only", "CodeEdit", make_stylebox(tree_bg_disabled_png, 4, 4, 4, 4, 0, 0, 0, 0));
+ theme->set_stylebox("completion", "CodeEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3, 0, 0, 0, 0));
+
+ theme->set_icon("tab", "CodeEdit", make_icon(tab_png));
+ theme->set_icon("space", "CodeEdit", make_icon(space_png));
+ theme->set_icon("breakpoint", "CodeEdit", make_icon(graph_port_png));
+ theme->set_icon("bookmark", "CodeEdit", make_icon(bookmark_png));
+ theme->set_icon("executing_line", "CodeEdit", make_icon(arrow_right_png));
+ theme->set_icon("can_fold", "CodeEdit", make_icon(arrow_down_png));
+ theme->set_icon("folded", "CodeEdit", make_icon(arrow_right_png));
+
+ theme->set_font("font", "CodeEdit", Ref<Font>());
+
+ theme->set_color("background_color", "CodeEdit", Color(0, 0, 0, 0));
+ theme->set_color("completion_background_color", "CodeEdit", Color(0.17, 0.16, 0.2));
+ theme->set_color("completion_selected_color", "CodeEdit", Color(0.26, 0.26, 0.27));
+ theme->set_color("completion_existing_color", "CodeEdit", Color(0.87, 0.87, 0.87, 0.13));
+ theme->set_color("completion_scroll_color", "CodeEdit", control_font_color_pressed);
+ theme->set_color("completion_font_color", "CodeEdit", Color(0.67, 0.67, 0.67));
+ theme->set_color("font_color", "CodeEdit", control_font_color);
+ theme->set_color("font_color_selected", "CodeEdit", Color(0, 0, 0));
+ theme->set_color("font_color_readonly", "CodeEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f));
+ theme->set_color("selection_color", "CodeEdit", font_color_selection);
+ theme->set_color("mark_color", "CodeEdit", Color(1.0, 0.4, 0.4, 0.4));
+ theme->set_color("bookmark_color", "CodeEdit", Color(0.5, 0.64, 1, 0.8));
+ theme->set_color("breakpoint_color", "CodeEdit", Color(0.9, 0.29, 0.3));
+ theme->set_color("executing_line_color", "CodeEdit", Color(0.98, 0.89, 0.27));
+ theme->set_color("code_folding_color", "CodeEdit", Color(0.8, 0.8, 0.8, 0.8));
+ theme->set_color("current_line_color", "CodeEdit", Color(0.25, 0.25, 0.26, 0.8));
+ theme->set_color("caret_color", "CodeEdit", control_font_color);
+ theme->set_color("caret_background_color", "CodeEdit", Color(0, 0, 0));
+ theme->set_color("brace_mismatch_color", "CodeEdit", Color(1, 0.2, 0.2));
+ theme->set_color("line_number_color", "CodeEdit", Color(0.67, 0.67, 0.67, 0.4));
+ theme->set_color("safe_line_number_color", "CodeEdit", Color(0.67, 0.78, 0.67, 0.6));
+ theme->set_color("word_highlighted_color", "CodeEdit", Color(0.8, 0.9, 0.9, 0.15));
+
+ theme->set_constant("completion_lines", "CodeEdit", 7);
+ theme->set_constant("completion_max_width", "CodeEdit", 50);
+ theme->set_constant("completion_scroll_width", "CodeEdit", 3);
+ theme->set_constant("line_spacing", "CodeEdit", 4 * scale);
+
Ref<Texture2D> empty_icon = memnew(ImageTexture);
// HScrollBar
diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h
index edcdb90db9..a15efb593a 100644
--- a/scene/resources/default_theme/theme_data.h
+++ b/scene/resources/default_theme/theme_data.h
@@ -10,6 +10,10 @@ static const unsigned char arrow_right_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x4, 0x0, 0x0, 0x0, 0xfc, 0x7c, 0x94, 0x6c, 0x0, 0x0, 0x0, 0x2e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x17, 0x3c, 0xf8, 0xf, 0x82, 0xf7, 0x13, 0x70, 0x48, 0x3c, 0xf8, 0xf2, 0x50, 0x1b, 0x43, 0x2, 0xa, 0xaf, 0xbe, 0xe0, 0xc6, 0x2e, 0xf1, 0xff, 0xe1, 0x7c, 0x12, 0x24, 0x10, 0x46, 0x11, 0xb6, 0x1c, 0xe1, 0x5c, 0xa, 0x0, 0x0, 0xe0, 0x14, 0x48, 0xb1, 0x3d, 0x1b, 0x7a, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
+static const unsigned char bookmark_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x4, 0x73, 0x42, 0x49, 0x54, 0x8, 0x8, 0x8, 0x8, 0x7c, 0x8, 0x64, 0x88, 0x0, 0x0, 0x0, 0x57, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xed, 0x93, 0x31, 0xa, 0xc0, 0x30, 0xc, 0x3, 0xa5, 0xd0, 0xff, 0x7f, 0x59, 0x1d, 0x8a, 0x42, 0x8, 0x9, 0x95, 0xc9, 0xd2, 0xa1, 0x9a, 0x8c, 0xf1, 0xdd, 0x62, 0x1b, 0x38, 0xc, 0x87, 0x5a, 0x5, 0xae, 0x79, 0xde, 0x2, 0x1, 0x80, 0x94, 0x39, 0x48, 0x76, 0x49, 0x17, 0xa4, 0xf0, 0x24, 0x61, 0x2b, 0x51, 0x8b, 0xfc, 0x82, 0xcf, 0xb, 0x48, 0x7a, 0xdf, 0x75, 0x81, 0xf, 0xe5, 0x29, 0xf7, 0x92, 0x6b, 0x3, 0x1a, 0x1e, 0xda, 0x7c, 0x3d, 0x77, 0x21, 0x7b, 0xa8, 0x74, 0x2e, 0xcb, 0xd, 0xc8, 0x75, 0x13, 0x28, 0x9, 0xed, 0xc2, 0xc8, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+};
+
static const unsigned char button_disabled_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0xc7, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6c, 0xd0, 0x81, 0x66, 0x43, 0x31, 0x14, 0x87, 0xf1, 0xf, 0x5, 0x17, 0xb8, 0x28, 0x2e, 0x8, 0x71, 0xf3, 0x6, 0x19, 0xb6, 0xb9, 0xcb, 0xac, 0x95, 0xa4, 0xb7, 0xad, 0x6a, 0xd5, 0x68, 0x5f, 0xe4, 0x3e, 0x76, 0x1e, 0xe1, 0xbf, 0x21, 0xa6, 0xab, 0xf8, 0x1, 0x7c, 0x9c, 0x73, 0xe, 0xac, 0xe8, 0xe8, 0x19, 0x30, 0x58, 0xc6, 0xca, 0x62, 0x18, 0xe8, 0xe9, 0x58, 0x41, 0xc7, 0x1a, 0x87, 0x27, 0x10, 0x49, 0xe4, 0x5f, 0x89, 0x48, 0xc0, 0xe3, 0x58, 0xd3, 0x41, 0x8f, 0xb, 0xcb, 0xbd, 0x7c, 0xeb, 0xbf, 0x7b, 0x9, 0xb, 0x8e, 0x1e, 0x6, 0xfc, 0xad, 0x64, 0x6d, 0xb5, 0x79, 0xb0, 0x55, 0xd6, 0xad, 0xe0, 0x19, 0xc0, 0x10, 0xae, 0xda, 0x34, 0x5c, 0x45, 0xc0, 0x80, 0x25, 0x5e, 0xf4, 0xd5, 0x70, 0x11, 0x11, 0xb, 0x23, 0xe9, 0xac, 0xcf, 0x86, 0xb3, 0x48, 0x8c, 0x30, 0x92, 0x4f, 0xa, 0xd, 0x27, 0x91, 0x6b, 0x70, 0xd4, 0x47, 0xc3, 0xf1, 0x2f, 0x48, 0x7, 0x4d, 0xd, 0x87, 0x3a, 0xc2, 0x12, 0x67, 0xbd, 0x37, 0xcc, 0x75, 0x49, 0x43, 0xd8, 0xe9, 0xad, 0x61, 0x57, 0xcf, 0x1c, 0xf0, 0xfb, 0x32, 0xe9, 0xf5, 0xc9, 0xa4, 0x7d, 0x7d, 0x54, 0x8f, 0x7b, 0x59, 0xe6, 0x92, 0x14, 0x1f, 0x24, 0xcd, 0x3f, 0x7b, 0x6b, 0xa, 0xe, 0x6a, 0x82, 0x91, 0x45, 0x30, 0xba, 0x1, 0x4a, 0x51, 0xc4, 0x35, 0x1f, 0xe5, 0xa1, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index cb201bc539..5e8bfd9387 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -848,7 +848,7 @@ Error SceneState::pack(Node *p_scene) {
Map<Node *, int> node_map;
Map<Node *, int> nodepath_map;
- //if using scene inheritance, pack the scene it inherits from
+ // If using scene inheritance, pack the scene it inherits from.
if (scene->get_scene_inherited_state().is_valid()) {
String path = scene->get_scene_inherited_state()->get_path();
Ref<PackedScene> instance = ResourceLoader::load(path);
@@ -856,8 +856,8 @@ Error SceneState::pack(Node *p_scene) {
base_scene_idx = _vm_get_variant(instance, variant_map);
}
}
- //instanced, only direct sub-scnes are supported of course
+ // Instanced, only direct sub-scenes are supported of course.
Error err = _parse_node(scene, scene, -1, name_map, variant_map, node_map, nodepath_map);
if (err) {
clear();
diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp
index 49b8cbe7e0..4bbfa8965a 100644
--- a/scene/resources/particles_material.cpp
+++ b/scene/resources/particles_material.cpp
@@ -1246,6 +1246,12 @@ void ParticlesMaterial::_bind_methods() {
BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINTS);
BIND_ENUM_CONSTANT(EMISSION_SHAPE_DIRECTED_POINTS);
BIND_ENUM_CONSTANT(EMISSION_SHAPE_MAX);
+
+ BIND_ENUM_CONSTANT(SUB_EMITTER_DISABLED);
+ BIND_ENUM_CONSTANT(SUB_EMITTER_CONSTANT);
+ BIND_ENUM_CONSTANT(SUB_EMITTER_AT_END);
+ BIND_ENUM_CONSTANT(SUB_EMITTER_AT_COLLISION);
+ BIND_ENUM_CONSTANT(SUB_EMITTER_MAX);
}
ParticlesMaterial::ParticlesMaterial() :
diff --git a/scene/resources/particles_material.h b/scene/resources/particles_material.h
index 9d41c91937..fa8858f67f 100644
--- a/scene/resources/particles_material.h
+++ b/scene/resources/particles_material.h
@@ -50,7 +50,6 @@ class ParticlesMaterial : public Material {
public:
enum Parameter {
-
PARAM_INITIAL_LINEAR_VELOCITY,
PARAM_ANGULAR_VELOCITY,
PARAM_ORBIT_VELOCITY,
diff --git a/scene/resources/syntax_highlighter.cpp b/scene/resources/syntax_highlighter.cpp
index d7a08d9eb6..5d58e71fc5 100644
--- a/scene/resources/syntax_highlighter.cpp
+++ b/scene/resources/syntax_highlighter.cpp
@@ -53,13 +53,13 @@ Dictionary SyntaxHighlighter::get_line_syntax_highlighting(int p_line) {
return color_map;
}
-void SyntaxHighlighter::_line_edited_from(int p_line) {
+void SyntaxHighlighter::_lines_edited_from(int p_from_line, int p_to_line) {
if (highlighting_cache.size() < 1) {
return;
}
int cache_size = highlighting_cache.back()->key();
- for (int i = p_line - 1; i <= cache_size; i++) {
+ for (int i = MIN(p_from_line, p_to_line) - 1; i <= cache_size; i++) {
if (highlighting_cache.has(i)) {
highlighting_cache.erase(i);
}
@@ -93,7 +93,7 @@ void SyntaxHighlighter::update_cache() {
void SyntaxHighlighter::set_text_edit(TextEdit *p_text_edit) {
if (text_edit && ObjectDB::get_instance(text_edit_instance_id)) {
- text_edit->disconnect("line_edited_from", callable_mp(this, &SyntaxHighlighter::_line_edited_from));
+ text_edit->disconnect("lines_edited_from", callable_mp(this, &SyntaxHighlighter::_lines_edited_from));
}
text_edit = p_text_edit;
@@ -101,7 +101,7 @@ void SyntaxHighlighter::set_text_edit(TextEdit *p_text_edit) {
return;
}
text_edit_instance_id = text_edit->get_instance_id();
- text_edit->connect("line_edited_from", callable_mp(this, &SyntaxHighlighter::_line_edited_from));
+ text_edit->connect("lines_edited_from", callable_mp(this, &SyntaxHighlighter::_lines_edited_from));
update_cache();
}
diff --git a/scene/resources/syntax_highlighter.h b/scene/resources/syntax_highlighter.h
index 40a8870b45..720227a256 100644
--- a/scene/resources/syntax_highlighter.h
+++ b/scene/resources/syntax_highlighter.h
@@ -40,7 +40,7 @@ class SyntaxHighlighter : public Resource {
private:
Map<int, Dictionary> highlighting_cache;
- void _line_edited_from(int p_line);
+ void _lines_edited_from(int p_from_line, int p_to_line);
protected:
ObjectID text_edit_instance_id; // For validity check
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 5681613c04..39237e1a33 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -791,8 +791,312 @@ String ResourceFormatLoaderStreamTexture2D::get_resource_type(const String &p_pa
return "";
}
+////////////////////////////////////
+
+TypedArray<Image> Texture3D::_get_data() const {
+ Vector<Ref<Image>> data = get_data();
+
+ TypedArray<Image> ret;
+ ret.resize(data.size());
+ for (int i = 0; i < data.size(); i++) {
+ ret[i] = data[i];
+ }
+ return ret;
+}
+
+void Texture3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_format"), &Texture3D::get_format);
+ ClassDB::bind_method(D_METHOD("get_width"), &Texture3D::get_width);
+ ClassDB::bind_method(D_METHOD("get_height"), &Texture3D::get_height);
+ ClassDB::bind_method(D_METHOD("get_depth"), &Texture3D::get_depth);
+ ClassDB::bind_method(D_METHOD("has_mipmaps"), &Texture3D::has_mipmaps);
+ ClassDB::bind_method(D_METHOD("get_data"), &Texture3D::_get_data);
+}
//////////////////////////////////////////
+Image::Format ImageTexture3D::get_format() const {
+ return format;
+}
+int ImageTexture3D::get_width() const {
+ return width;
+}
+int ImageTexture3D::get_height() const {
+ return height;
+}
+int ImageTexture3D::get_depth() const {
+ return depth;
+}
+bool ImageTexture3D::has_mipmaps() const {
+ return mipmaps;
+}
+
+Error ImageTexture3D::_create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const TypedArray<Image> &p_data) {
+ Vector<Ref<Image>> images;
+ images.resize(p_data.size());
+ for (int i = 0; i < images.size(); i++) {
+ images.write[i] = p_data[i];
+ }
+ return create(p_format, p_width, p_height, p_depth, p_mipmaps, images);
+}
+
+void ImageTexture3D::_update(const TypedArray<Image> &p_data) {
+ Vector<Ref<Image>> images;
+ images.resize(p_data.size());
+ for (int i = 0; i < images.size(); i++) {
+ images.write[i] = p_data[i];
+ }
+ return update(images);
+}
+
+Error ImageTexture3D::create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) {
+ RID tex = RenderingServer::get_singleton()->texture_3d_create(p_format, p_width, p_height, p_depth, p_mipmaps, p_data);
+ ERR_FAIL_COND_V(tex.is_null(), ERR_CANT_CREATE);
+
+ if (texture.is_valid()) {
+ RenderingServer::get_singleton()->texture_replace(texture, tex);
+ }
+
+ return OK;
+}
+
+void ImageTexture3D::update(const Vector<Ref<Image>> &p_data) {
+ ERR_FAIL_COND(!texture.is_valid());
+ RenderingServer::get_singleton()->texture_3d_update(texture, p_data);
+}
+
+Vector<Ref<Image>> ImageTexture3D::get_data() const {
+ ERR_FAIL_COND_V(!texture.is_valid(), Vector<Ref<Image>>());
+ return RS::get_singleton()->texture_3d_get(texture);
+}
+
+RID ImageTexture3D::get_rid() const {
+ if (!texture.is_valid()) {
+ texture = RS::get_singleton()->texture_3d_placeholder_create();
+ }
+ return texture;
+}
+void ImageTexture3D::set_path(const String &p_path, bool p_take_over) {
+ if (texture.is_valid()) {
+ RenderingServer::get_singleton()->texture_set_path(texture, p_path);
+ }
+
+ Resource::set_path(p_path, p_take_over);
+}
+
+void ImageTexture3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("create", "format", "width", "height", "depth", "use_mipmaps", "data"), &ImageTexture3D::_create);
+ ClassDB::bind_method(D_METHOD("update", "data"), &ImageTexture3D::_update);
+}
+
+ImageTexture3D::ImageTexture3D() {
+}
+
+ImageTexture3D::~ImageTexture3D() {
+ if (texture.is_valid()) {
+ RS::get_singleton()->free(texture);
+ }
+}
+
+////////////////////////////////////////////
+
+void StreamTexture3D::set_path(const String &p_path, bool p_take_over) {
+ if (texture.is_valid()) {
+ RenderingServer::get_singleton()->texture_set_path(texture, p_path);
+ }
+
+ Resource::set_path(p_path, p_take_over);
+}
+
+Image::Format StreamTexture3D::get_format() const {
+ return format;
+}
+
+Error StreamTexture3D::_load_data(const String &p_path, Vector<Ref<Image>> &r_data, Image::Format &r_format, int &r_width, int &r_height, int &r_depth, bool &r_mipmaps) {
+ FileAccessRef f = FileAccess::open(p_path, FileAccess::READ);
+ ERR_FAIL_COND_V(!f, ERR_CANT_OPEN);
+
+ uint8_t header[4];
+ f->get_buffer(header, 4);
+ ERR_FAIL_COND_V(header[0] != 'G' || header[1] != 'S' || header[2] != 'T' || header[3] != 'L', ERR_FILE_UNRECOGNIZED);
+
+ //stored as stream textures (used for lossless and lossy compression)
+ uint32_t version = f->get_32();
+
+ if (version > FORMAT_VERSION) {
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Stream texture file is too new.");
+ }
+
+ r_depth = f->get_32(); //depth
+ f->get_32(); //ignored (mode)
+ f->get_32(); // ignored (data format)
+
+ f->get_32(); //ignored
+ int mipmaps = f->get_32();
+ f->get_32(); //ignored
+ f->get_32(); //ignored
+
+ r_mipmaps = mipmaps != 0;
+
+ r_data.clear();
+
+ for (int i = 0; i < (r_depth + mipmaps); i++) {
+ Ref<Image> image = StreamTexture2D::load_image_from_file(f, 0);
+ ERR_FAIL_COND_V(image.is_null() || image->empty(), ERR_CANT_OPEN);
+ if (i == 0) {
+ r_format = image->get_format();
+ r_width = image->get_width();
+ r_height = image->get_height();
+ }
+ r_data.push_back(image);
+ }
+
+ return OK;
+}
+
+Error StreamTexture3D::load(const String &p_path) {
+ Vector<Ref<Image>> data;
+
+ int tw, th, td;
+ Image::Format tfmt;
+ bool tmm;
+
+ Error err = _load_data(p_path, data, tfmt, tw, th, td, tmm);
+ if (err) {
+ return err;
+ }
+
+ if (texture.is_valid()) {
+ RID new_texture = RS::get_singleton()->texture_3d_create(tfmt, tw, th, td, tmm, data);
+ RS::get_singleton()->texture_replace(texture, new_texture);
+ } else {
+ texture = RS::get_singleton()->texture_3d_create(tfmt, tw, th, td, tmm, data);
+ }
+
+ w = tw;
+ h = th;
+ d = td;
+ mipmaps = tmm;
+ format = tfmt;
+
+ path_to_file = p_path;
+
+ if (get_path() == String()) {
+ //temporarily set path if no path set for resource, helps find errors
+ RenderingServer::get_singleton()->texture_set_path(texture, p_path);
+ }
+
+ _change_notify();
+ emit_changed();
+ return OK;
+}
+
+String StreamTexture3D::get_load_path() const {
+ return path_to_file;
+}
+
+int StreamTexture3D::get_width() const {
+ return w;
+}
+
+int StreamTexture3D::get_height() const {
+ return h;
+}
+
+int StreamTexture3D::get_depth() const {
+ return d;
+}
+
+bool StreamTexture3D::has_mipmaps() const {
+ return mipmaps;
+}
+
+RID StreamTexture3D::get_rid() const {
+ if (!texture.is_valid()) {
+ texture = RS::get_singleton()->texture_3d_placeholder_create();
+ }
+ return texture;
+}
+
+Vector<Ref<Image>> StreamTexture3D::get_data() const {
+ if (texture.is_valid()) {
+ return RS::get_singleton()->texture_3d_get(texture);
+ } else {
+ return Vector<Ref<Image>>();
+ }
+}
+
+void StreamTexture3D::reload_from_file() {
+ String path = get_path();
+ if (!path.is_resource_file()) {
+ return;
+ }
+
+ path = ResourceLoader::path_remap(path); //remap for translation
+ path = ResourceLoader::import_remap(path); //remap for import
+ if (!path.is_resource_file()) {
+ return;
+ }
+
+ load(path);
+}
+
+void StreamTexture3D::_validate_property(PropertyInfo &property) const {
+}
+
+void StreamTexture3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("load", "path"), &StreamTexture3D::load);
+ ClassDB::bind_method(D_METHOD("get_load_path"), &StreamTexture3D::get_load_path);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.stex"), "load", "get_load_path");
+}
+
+StreamTexture3D::StreamTexture3D() {
+ format = Image::FORMAT_MAX;
+ w = 0;
+ h = 0;
+ d = 0;
+ mipmaps = false;
+}
+
+StreamTexture3D::~StreamTexture3D() {
+ if (texture.is_valid()) {
+ RS::get_singleton()->free(texture);
+ }
+}
+
+/////////////////////////////
+
+RES ResourceFormatLoaderStreamTexture3D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+ Ref<StreamTexture3D> st;
+ st.instance();
+ Error err = st->load(p_path);
+ if (r_error) {
+ *r_error = err;
+ }
+ if (err != OK) {
+ return RES();
+ }
+
+ return st;
+}
+
+void ResourceFormatLoaderStreamTexture3D::get_recognized_extensions(List<String> *p_extensions) const {
+ p_extensions->push_back("stex3d");
+}
+
+bool ResourceFormatLoaderStreamTexture3D::handles_type(const String &p_type) const {
+ return p_type == "StreamTexture3D";
+}
+
+String ResourceFormatLoaderStreamTexture3D::get_resource_type(const String &p_path) const {
+ if (p_path.get_extension().to_lower() == "stex3d") {
+ return "StreamTexture3D";
+ }
+ return "";
+}
+
+////////////////////////////////////////////
+
int AtlasTexture::get_width() const {
if (region.size.width == 0) {
if (atlas.is_valid()) {
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index fd213859b7..eebbf4f233 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -515,6 +515,122 @@ public:
virtual String get_resource_type(const String &p_path) const;
};
+class Texture3D : public Texture {
+ GDCLASS(Texture3D, Texture);
+
+protected:
+ static void _bind_methods();
+
+ TypedArray<Image> _get_data() const;
+
+public:
+ virtual Image::Format get_format() const = 0;
+ virtual int get_width() const = 0;
+ virtual int get_height() const = 0;
+ virtual int get_depth() const = 0;
+ virtual bool has_mipmaps() const = 0;
+ virtual Vector<Ref<Image>> get_data() const = 0;
+};
+
+class ImageTexture3D : public Texture3D {
+ GDCLASS(ImageTexture3D, Texture3D);
+
+ mutable RID texture;
+
+ Image::Format format = Image::FORMAT_MAX;
+ int width = 1;
+ int height = 1;
+ int depth = 1;
+ bool mipmaps = false;
+
+protected:
+ static void _bind_methods();
+
+ Error _create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const TypedArray<Image> &p_data);
+ void _update(const TypedArray<Image> &p_data);
+
+public:
+ virtual Image::Format get_format() const override;
+ virtual int get_width() const override;
+ virtual int get_height() const override;
+ virtual int get_depth() const override;
+ virtual bool has_mipmaps() const override;
+
+ Error create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data);
+ void update(const Vector<Ref<Image>> &p_data);
+ virtual Vector<Ref<Image>> get_data() const override;
+
+ virtual RID get_rid() const override;
+ virtual void set_path(const String &p_path, bool p_take_over = false) override;
+
+ ImageTexture3D();
+ ~ImageTexture3D();
+};
+
+class StreamTexture3D : public Texture3D {
+ GDCLASS(StreamTexture3D, Texture3D);
+
+public:
+ enum DataFormat {
+ DATA_FORMAT_IMAGE,
+ DATA_FORMAT_LOSSLESS,
+ DATA_FORMAT_LOSSY,
+ DATA_FORMAT_BASIS_UNIVERSAL,
+ };
+
+ enum {
+ FORMAT_VERSION = 1
+ };
+
+ enum FormatBits {
+ FORMAT_MASK_IMAGE_FORMAT = (1 << 20) - 1,
+ FORMAT_BIT_LOSSLESS = 1 << 20,
+ FORMAT_BIT_LOSSY = 1 << 21,
+ FORMAT_BIT_STREAM = 1 << 22,
+ FORMAT_BIT_HAS_MIPMAPS = 1 << 23,
+ };
+
+private:
+ Error _load_data(const String &p_path, Vector<Ref<Image>> &r_data, Image::Format &r_format, int &r_width, int &r_height, int &r_depth, bool &r_mipmaps);
+ String path_to_file;
+ mutable RID texture;
+ Image::Format format;
+ int w, h, d;
+ bool mipmaps;
+
+ virtual void reload_from_file() override;
+
+protected:
+ static void _bind_methods();
+ void _validate_property(PropertyInfo &property) const override;
+
+public:
+ Image::Format get_format() const override;
+ Error load(const String &p_path);
+ String get_load_path() const;
+
+ int get_width() const override;
+ int get_height() const override;
+ int get_depth() const override;
+ virtual bool has_mipmaps() const override;
+ virtual RID get_rid() const override;
+
+ virtual void set_path(const String &p_path, bool p_take_over) override;
+
+ virtual Vector<Ref<Image>> get_data() const override;
+
+ StreamTexture3D();
+ ~StreamTexture3D();
+};
+
+class ResourceFormatLoaderStreamTexture3D : public ResourceFormatLoader {
+public:
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual bool handles_type(const String &p_type) const;
+ virtual String get_resource_type(const String &p_path) const;
+};
+
class CurveTexture : public Texture2D {
GDCLASS(CurveTexture, Texture2D);
RES_BASE_EXTENSION("curvetex")
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 394133dd47..f15e43c141 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -101,6 +101,14 @@ bool VisualShaderNode::is_code_generated() const {
return true;
}
+bool VisualShaderNode::is_show_prop_names() const {
+ return false;
+}
+
+bool VisualShaderNode::is_use_prop_slots() const {
+ return false;
+}
+
Vector<VisualShader::DefaultTextureParam> VisualShaderNode::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const {
return Vector<VisualShader::DefaultTextureParam>();
}
@@ -317,17 +325,14 @@ VisualShaderNodeCustom::VisualShaderNodeCustom() {
/////////////////////////////////////////////////////////
-void VisualShader::set_graph_node(Type p_type, int p_id, GraphNode *p_graph_node) {
- ERR_FAIL_INDEX(p_type, TYPE_MAX);
- Graph *g = &graph[p_type];
- ERR_FAIL_COND(!g->nodes.has(p_id));
- g->nodes[p_id].graph_node = p_graph_node;
-}
-
void VisualShader::set_shader_type(Type p_type) {
current_type = p_type;
}
+VisualShader::Type VisualShader::get_shader_type() const {
+ return current_type;
+}
+
void VisualShader::set_version(const String &p_version) {
version = p_version;
}
@@ -411,11 +416,6 @@ void VisualShader::set_node_position(Type p_type, int p_id, const Vector2 &p_pos
Graph *g = &graph[p_type];
ERR_FAIL_COND(!g->nodes.has(p_id));
g->nodes[p_id].position = p_position;
- if (current_type == p_type) {
- if (g->nodes[p_id].graph_node != nullptr) {
- g->nodes[p_id].graph_node->set_offset(p_position);
- }
- }
}
Vector2 VisualShader::get_node_position(Type p_type, int p_id) const {
@@ -1517,11 +1517,11 @@ void VisualShader::_update_shader() const {
if (shader_mode != Shader::MODE_PARTICLES) {
func_code += "\nvoid " + String(func_name[i]) + "() {\n";
}
+ insertion_pos.insert(i, code.get_string_length() + func_code.get_string_length());
Set<int> processed;
Error err = _write_node(Type(i), global_code, global_code_per_node, global_code_per_func, func_code, default_tex_params, input_connections, output_connections, NODE_ID_OUTPUT, processed, false, classes);
ERR_FAIL_COND(err != OK);
- insertion_pos.insert(i, code.get_string_length());
if (shader_mode == Shader::MODE_PARTICLES) {
code_map.insert(i, func_code);
@@ -1632,6 +1632,9 @@ void VisualShader::_bind_methods() {
BIND_ENUM_CONSTANT(TYPE_VERTEX);
BIND_ENUM_CONSTANT(TYPE_FRAGMENT);
BIND_ENUM_CONSTANT(TYPE_LIGHT);
+ BIND_ENUM_CONSTANT(TYPE_EMIT);
+ BIND_ENUM_CONSTANT(TYPE_PROCESS);
+ BIND_ENUM_CONSTANT(TYPE_END);
BIND_ENUM_CONSTANT(TYPE_MAX);
BIND_CONSTANT(NODE_ID_INVALID);
@@ -2128,6 +2131,15 @@ void VisualShaderNodeUniformRef::clear_uniforms() {
uniforms.clear();
}
+bool VisualShaderNodeUniformRef::has_uniform(const String &p_name) {
+ for (List<VisualShaderNodeUniformRef::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+ if (E->get().name == p_name) {
+ return true;
+ }
+ }
+ return false;
+}
+
String VisualShaderNodeUniformRef::get_caption() const {
return "UniformRef";
}
@@ -2145,10 +2157,6 @@ String VisualShaderNodeUniformRef::get_input_port_name(int p_port) const {
}
int VisualShaderNodeUniformRef::get_output_port_count() const {
- if (uniform_name == "[None]") {
- return 0;
- }
-
switch (uniform_type) {
case UniformType::UNIFORM_TYPE_FLOAT:
return 1;
@@ -2167,7 +2175,7 @@ int VisualShaderNodeUniformRef::get_output_port_count() const {
default:
break;
}
- return 0;
+ return 1;
}
VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_output_port_type(int p_port) const {
@@ -2227,8 +2235,8 @@ String VisualShaderNodeUniformRef::get_output_port_name(int p_port) const {
void VisualShaderNodeUniformRef::set_uniform_name(const String &p_name) {
uniform_name = p_name;
- if (p_name != "[None]") {
- uniform_type = get_uniform_type_by_name(p_name);
+ if (uniform_name != "[None]") {
+ uniform_type = get_uniform_type_by_name(uniform_name);
} else {
uniform_type = UniformType::UNIFORM_TYPE_FLOAT;
}
@@ -2269,6 +2277,9 @@ VisualShaderNodeUniformRef::UniformType VisualShaderNodeUniformRef::get_uniform_
String VisualShaderNodeUniformRef::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 {
switch (uniform_type) {
case UniformType::UNIFORM_TYPE_FLOAT:
+ if (uniform_name == "[None]") {
+ return "\t" + p_output_vars[0] + " = 0.0;\n";
+ }
return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
case UniformType::UNIFORM_TYPE_INT:
return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
@@ -2291,16 +2302,29 @@ String VisualShaderNodeUniformRef::generate_code(Shader::Mode p_mode, VisualShad
return "";
}
+void VisualShaderNodeUniformRef::_set_uniform_type(int p_uniform_type) {
+ uniform_type = (UniformType)p_uniform_type;
+}
+
+int VisualShaderNodeUniformRef::_get_uniform_type() const {
+ return (int)uniform_type;
+}
+
void VisualShaderNodeUniformRef::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_uniform_name", "name"), &VisualShaderNodeUniformRef::set_uniform_name);
ClassDB::bind_method(D_METHOD("get_uniform_name"), &VisualShaderNodeUniformRef::get_uniform_name);
+ ClassDB::bind_method(D_METHOD("_set_uniform_type", "type"), &VisualShaderNodeUniformRef::_set_uniform_type);
+ ClassDB::bind_method(D_METHOD("_get_uniform_type"), &VisualShaderNodeUniformRef::_get_uniform_type);
+
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "uniform_name", PROPERTY_HINT_ENUM, ""), "set_uniform_name", "get_uniform_name");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "uniform_type", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_uniform_type", "_get_uniform_type");
}
Vector<StringName> VisualShaderNodeUniformRef::get_editable_properties() const {
Vector<StringName> props;
props.push_back("uniform_name");
+ props.push_back("uniform_type");
return props;
}
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index d45029ec03..e7d74b6c17 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -33,7 +33,6 @@
#include "core/string_builder.h"
#include "scene/gui/control.h"
-#include "scene/gui/graph_edit.h"
#include "scene/resources/shader.h"
class VisualShaderNodeUniform;
@@ -76,7 +75,6 @@ private:
Ref<VisualShaderNode> node;
Vector2 position;
List<int> prev_connected_nodes;
- GraphNode *graph_node;
};
struct Graph {
@@ -129,8 +127,8 @@ protected:
void _get_property_list(List<PropertyInfo> *p_list) const;
public: // internal methods
- void set_graph_node(Type p_type, int p_id, GraphNode *p_graph_node);
void set_shader_type(Type p_type);
+ Type get_shader_type() const;
public:
void set_version(const String &p_version);
@@ -244,6 +242,8 @@ public:
virtual bool is_generate_input_var(int p_port) const;
virtual bool is_code_generated() const;
+ virtual bool is_show_prop_names() const;
+ virtual bool is_use_prop_slots() const;
virtual Vector<StringName> get_editable_properties() const;
@@ -456,6 +456,7 @@ protected:
public:
static void add_uniform(const String &p_name, UniformType p_type);
static void clear_uniforms();
+ static bool has_uniform(const String &p_name);
public:
virtual String get_caption() const override;
@@ -471,6 +472,9 @@ public:
void set_uniform_name(const String &p_name);
String get_uniform_name() const;
+ void _set_uniform_type(int p_uniform_type);
+ int _get_uniform_type() const;
+
int get_uniforms_count() const;
String get_uniform_name_by_index(int p_idx) const;
UniformType get_uniform_type_by_name(const String &p_name) const;
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index 182aeae5d4..cffe0bb5cd 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -951,6 +951,64 @@ void VisualShaderNodeTexture2DArray::_bind_methods() {
VisualShaderNodeTexture2DArray::VisualShaderNodeTexture2DArray() {
}
+
+////////////// Texture3D
+
+String VisualShaderNodeTexture3D::get_caption() const {
+ return "Texture3D";
+}
+
+String VisualShaderNodeTexture3D::get_input_port_name(int p_port) const {
+ if (p_port == 2) {
+ return "sampler3D";
+ }
+ return VisualShaderNodeSample3D::get_input_port_name(p_port);
+}
+
+Vector<VisualShader::DefaultTextureParam> VisualShaderNodeTexture3D::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const {
+ VisualShader::DefaultTextureParam dtp;
+ dtp.name = make_unique_id(p_type, p_id, "tex3d");
+ dtp.param = texture;
+ Vector<VisualShader::DefaultTextureParam> ret;
+ ret.push_back(dtp);
+ return ret;
+}
+
+String VisualShaderNodeTexture3D::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ if (source == SOURCE_TEXTURE) {
+ return "uniform sampler3D " + make_unique_id(p_type, p_id, "tex3d") + ";\n";
+ }
+ return String();
+}
+
+void VisualShaderNodeTexture3D::set_texture(Ref<Texture3D> p_value) {
+ texture = p_value;
+ emit_changed();
+}
+
+Ref<Texture3D> VisualShaderNodeTexture3D::get_texture() const {
+ return texture;
+}
+
+Vector<StringName> VisualShaderNodeTexture3D::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("source");
+ if (source == SOURCE_TEXTURE) {
+ props.push_back("texture");
+ }
+ return props;
+}
+
+void VisualShaderNodeTexture3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_texture", "value"), &VisualShaderNodeTexture3D::set_texture);
+ ClassDB::bind_method(D_METHOD("get_texture"), &VisualShaderNodeTexture3D::get_texture);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture3D"), "set_texture", "get_texture");
+}
+
+VisualShaderNodeTexture3D::VisualShaderNodeTexture3D() {
+}
+
////////////// Cubemap
String VisualShaderNodeCubemap::get_caption() const {
@@ -3432,6 +3490,14 @@ String VisualShaderNodeFloatUniform::generate_code(Shader::Mode p_mode, VisualSh
return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
}
+bool VisualShaderNodeFloatUniform::is_show_prop_names() const {
+ return true;
+}
+
+bool VisualShaderNodeFloatUniform::is_use_prop_slots() const {
+ return true;
+}
+
void VisualShaderNodeFloatUniform::set_hint(Hint p_hint) {
hint = p_hint;
emit_changed();
@@ -3591,6 +3657,14 @@ String VisualShaderNodeIntUniform::generate_code(Shader::Mode p_mode, VisualShad
return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
}
+bool VisualShaderNodeIntUniform::is_show_prop_names() const {
+ return true;
+}
+
+bool VisualShaderNodeIntUniform::is_use_prop_slots() const {
+ return true;
+}
+
void VisualShaderNodeIntUniform::set_hint(Hint p_hint) {
hint = p_hint;
emit_changed();
@@ -3765,6 +3839,14 @@ String VisualShaderNodeBooleanUniform::generate_code(Shader::Mode p_mode, Visual
return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
}
+bool VisualShaderNodeBooleanUniform::is_show_prop_names() const {
+ return true;
+}
+
+bool VisualShaderNodeBooleanUniform::is_use_prop_slots() const {
+ return true;
+}
+
void VisualShaderNodeBooleanUniform::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeBooleanUniform::set_default_value_enabled);
ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeBooleanUniform::is_default_value_enabled);
@@ -3855,6 +3937,10 @@ String VisualShaderNodeColorUniform::generate_code(Shader::Mode p_mode, VisualSh
return code;
}
+bool VisualShaderNodeColorUniform::is_show_prop_names() const {
+ return true;
+}
+
void VisualShaderNodeColorUniform::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeColorUniform::set_default_value_enabled);
ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeColorUniform::is_default_value_enabled);
@@ -3954,6 +4040,14 @@ void VisualShaderNodeVec3Uniform::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "default_value"), "set_default_value", "get_default_value");
}
+bool VisualShaderNodeVec3Uniform::is_show_prop_names() const {
+ return true;
+}
+
+bool VisualShaderNodeVec3Uniform::is_use_prop_slots() const {
+ return true;
+}
+
bool VisualShaderNodeVec3Uniform::is_qualifier_supported(Qualifier p_qual) const {
return true; // all qualifiers are supported
}
@@ -4046,6 +4140,14 @@ void VisualShaderNodeTransformUniform::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "default_value"), "set_default_value", "get_default_value");
}
+bool VisualShaderNodeTransformUniform::is_show_prop_names() const {
+ return true;
+}
+
+bool VisualShaderNodeTransformUniform::is_use_prop_slots() const {
+ return true;
+}
+
bool VisualShaderNodeTransformUniform::is_qualifier_supported(Qualifier p_qual) const {
return true; // all qualifiers are supported
}
@@ -4301,13 +4403,13 @@ String VisualShaderNodeTextureUniformTriplanar::generate_code(Shader::Mode p_mod
String code = "\t{\n";
if (p_input_vars[0] == String() && p_input_vars[1] == String()) {
- code += "\t\tvec4 n_tex_read = triplanar_texture( " + id + ", triplanar_power_normal, triplanar_pos );\n";
+ code += "\t\tvec4 n_tex_read = triplanar_texture(" + id + ", triplanar_power_normal, triplanar_pos);\n";
} else if (p_input_vars[0] != String() && p_input_vars[1] == String()) {
- code += "\t\tvec4 n_tex_read = triplanar_texture( " + id + ", " + p_input_vars[0] + ", triplanar_pos );\n";
+ code += "\t\tvec4 n_tex_read = triplanar_texture(" + id + ", " + p_input_vars[0] + ", triplanar_pos);\n";
} else if (p_input_vars[0] == String() && p_input_vars[1] != String()) {
- code += "\t\tvec4 n_tex_read = triplanar_texture( " + id + ", triplanar_power_normal," + p_input_vars[1] + " );\n";
+ code += "\t\tvec4 n_tex_read = triplanar_texture(" + id + ", triplanar_power_normal, " + p_input_vars[1] + ");\n";
} else {
- code += "\t\tvec4 n_tex_read = triplanar_texture( " + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + " );\n";
+ code += "\t\tvec4 n_tex_read = triplanar_texture(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
}
code += "\t\t" + p_output_vars[0] + " = n_tex_read.rgb;\n";
@@ -4397,6 +4499,74 @@ String VisualShaderNodeTexture2DArrayUniform::generate_code(Shader::Mode p_mode,
VisualShaderNodeTexture2DArrayUniform::VisualShaderNodeTexture2DArrayUniform() {
}
+////////////// Texture3D Uniform
+
+String VisualShaderNodeTexture3DUniform::get_caption() const {
+ return "Texture3DUniform";
+}
+
+int VisualShaderNodeTexture3DUniform::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeTexture3DUniform::PortType VisualShaderNodeTexture3DUniform::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SAMPLER;
+}
+
+String VisualShaderNodeTexture3DUniform::get_output_port_name(int p_port) const {
+ return "sampler3D";
+}
+
+int VisualShaderNodeTexture3DUniform::get_input_port_count() const {
+ return 0;
+}
+
+VisualShaderNodeTexture3DUniform::PortType VisualShaderNodeTexture3DUniform::get_input_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeTexture3DUniform::get_input_port_name(int p_port) const {
+ return "";
+}
+
+String VisualShaderNodeTexture3DUniform::get_input_port_default_hint(int p_port) const {
+ return "";
+}
+
+String VisualShaderNodeTexture3DUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform sampler3D " + get_uniform_name();
+
+ switch (texture_type) {
+ case TYPE_DATA:
+ if (color_default == COLOR_DEFAULT_BLACK)
+ code += " : hint_black;\n";
+ else
+ code += ";\n";
+ break;
+ case TYPE_COLOR:
+ if (color_default == COLOR_DEFAULT_BLACK)
+ code += " : hint_black_albedo;\n";
+ else
+ code += " : hint_albedo;\n";
+ break;
+ case TYPE_NORMALMAP:
+ code += " : hint_normal;\n";
+ break;
+ case TYPE_ANISO:
+ code += " : hint_aniso;\n";
+ break;
+ }
+
+ return code;
+}
+
+String VisualShaderNodeTexture3DUniform::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 {
+ return String();
+}
+
+VisualShaderNodeTexture3DUniform::VisualShaderNodeTexture3DUniform() {
+}
+
////////////// Cubemap Uniform
String VisualShaderNodeCubemapUniform::get_caption() const {
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index 245435591b..1c986d1ef4 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -343,6 +343,29 @@ public:
VisualShaderNodeTexture2DArray();
};
+class VisualShaderNodeTexture3D : public VisualShaderNodeSample3D {
+ GDCLASS(VisualShaderNodeTexture3D, VisualShaderNodeSample3D);
+ Ref<Texture3D> texture;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const override;
+
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const override;
+ virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
+
+ void set_texture(Ref<Texture3D> p_value);
+ Ref<Texture3D> get_texture() const;
+
+ virtual Vector<StringName> get_editable_properties() const override;
+
+ VisualShaderNodeTexture3D();
+};
+
class VisualShaderNodeCubemap : public VisualShaderNode {
GDCLASS(VisualShaderNodeCubemap, VisualShaderNode);
Ref<Cubemap> cube_map;
@@ -1506,6 +1529,9 @@ public:
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
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 override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual bool is_show_prop_names() const override;
+ virtual bool is_use_prop_slots() const override;
+
void set_hint(Hint p_hint);
Hint get_hint() const;
@@ -1568,6 +1594,9 @@ public:
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
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 override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual bool is_show_prop_names() const override;
+ virtual bool is_use_prop_slots() const override;
+
void set_hint(Hint p_hint);
Hint get_hint() const;
@@ -1621,6 +1650,9 @@ public:
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
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 override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual bool is_show_prop_names() const override;
+ virtual bool is_use_prop_slots() const override;
+
void set_default_value_enabled(bool p_enabled);
bool is_default_value_enabled() const;
@@ -1660,6 +1692,8 @@ public:
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
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 override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual bool is_show_prop_names() const override;
+
void set_default_value_enabled(bool p_enabled);
bool is_default_value_enabled() const;
@@ -1699,6 +1733,9 @@ public:
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
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 override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual bool is_show_prop_names() const override;
+ virtual bool is_use_prop_slots() const override;
+
void set_default_value_enabled(bool p_enabled);
bool is_default_value_enabled() const;
@@ -1738,6 +1775,9 @@ public:
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
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 override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual bool is_show_prop_names() const override;
+ virtual bool is_use_prop_slots() const override;
+
void set_default_value_enabled(bool p_enabled);
bool is_default_value_enabled() const;
@@ -1855,6 +1895,29 @@ public:
///////////////////////////////////////
+class VisualShaderNodeTexture3DUniform : public VisualShaderNodeTextureUniform {
+ GDCLASS(VisualShaderNodeTexture3DUniform, VisualShaderNodeTextureUniform);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String get_input_port_default_hint(int p_port) const override;
+ virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
+ 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 override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeTexture3DUniform();
+};
+
+///////////////////////////////////////
+
class VisualShaderNodeCubemapUniform : public VisualShaderNodeTextureUniform {
GDCLASS(VisualShaderNodeCubemapUniform, VisualShaderNodeTextureUniform);