summaryrefslogtreecommitdiff
path: root/editor/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'editor/plugins')
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp39
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp6
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp15
-rw-r--r--editor/plugins/asset_library_editor_plugin.h1
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp285
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h8
-rw-r--r--editor/plugins/curve_editor_plugin.cpp3
-rw-r--r--editor/plugins/editor_preview_plugins.cpp8
-rw-r--r--editor/plugins/mesh_instance_editor_plugin.cpp1
-rw-r--r--editor/plugins/script_text_editor.cpp59
-rw-r--r--editor/plugins/script_text_editor.h1
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp78
-rw-r--r--editor/plugins/spatial_editor_plugin.h12
-rw-r--r--editor/plugins/style_box_editor_plugin.cpp13
-rw-r--r--editor/plugins/style_box_editor_plugin.h3
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp4
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp1
-rw-r--r--editor/plugins/tile_set_editor_plugin.cpp5
-rw-r--r--editor/plugins/version_control_editor_plugin.cpp24
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp71
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h2
21 files changed, 518 insertions, 121 deletions
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index 235c204265..e147206ec4 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -534,6 +534,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
updating = true;
Set<String> paths;
+ HashMap<String, Set<String> > types;
{
List<StringName> animations;
player->get_animation_list(&animations);
@@ -542,7 +543,27 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
Ref<Animation> anim = player->get_animation(E->get());
for (int i = 0; i < anim->get_track_count(); i++) {
- paths.insert(anim->track_get_path(i));
+ String track_path = anim->track_get_path(i);
+ paths.insert(track_path);
+
+ String track_type_name;
+ Animation::TrackType track_type = anim->track_get_type(i);
+ switch (track_type) {
+ case Animation::TrackType::TYPE_ANIMATION: {
+ track_type_name = TTR("Anim Clips");
+ } break;
+ case Animation::TrackType::TYPE_AUDIO: {
+ track_type_name = TTR("Audio Clips");
+ } break;
+ case Animation::TrackType::TYPE_METHOD: {
+ track_type_name = TTR("Functions");
+ } break;
+ default: {
+ } break;
+ }
+ if (!track_type_name.empty()) {
+ types[track_path].insert(track_type_name);
+ }
}
}
}
@@ -646,10 +667,22 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
}
} else {
if (ti) {
- //just a node, likely call or animation track
+ //just a node, not a property track
+ String types_text = "[";
+ if (types.has(path)) {
+ Set<String>::Element *F = types[path].front();
+ types_text += F->get();
+ while (F->next()) {
+ F = F->next();
+ types_text += " / " + F->get();
+ }
+ }
+ types_text += "]";
+ ti = filters->create_item(ti);
+ ti->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
+ ti->set_text(0, types_text);
ti->set_editable(0, true);
ti->set_selectable(0, true);
- ti->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
ti->set_checked(0, anode->is_path_filtered(path));
ti->set_metadata(0, path);
}
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index bc22d9315e..ce400ad6dd 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -1117,15 +1117,17 @@ void AnimationNodeStateMachineEditor::_name_edited(const String &p_text) {
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
undo_redo->commit_action();
+ name_edit->hide();
updating = false;
state_machine_draw->update();
-
- name_edit->hide();
}
void AnimationNodeStateMachineEditor::_name_edited_focus_out() {
+ if (updating)
+ return;
+
_name_edited(name_edit->get_text());
}
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index d5b1f46333..95767a96d8 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -1137,9 +1137,12 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const
initial_loading = false;
- // The loading text only needs to be displayed before the first page is loaded
+ // The loading text only needs to be displayed before the first page is loaded.
+ // Therefore, we don't need to show it again.
library_loading->hide();
+ library_error->hide();
+
if (asset_items) {
memdelete(asset_items);
}
@@ -1187,6 +1190,11 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const
asset_bottom_page = _make_pages(page, pages, page_len, total_items, result.size());
library_vb->add_child(asset_bottom_page);
+ if (result.empty()) {
+ library_error->set_text(vformat(TTR("No results for \"%s\"."), filter->get_text()));
+ library_error->show();
+ }
+
for (int i = 0; i < result.size(); i++) {
Dictionary r = result[i];
@@ -1453,6 +1461,11 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
library_loading->set_align(Label::ALIGN_CENTER);
library_vb->add_child(library_loading);
+ library_error = memnew(Label);
+ library_error->set_align(Label::ALIGN_CENTER);
+ library_error->hide();
+ library_vb->add_child(library_error);
+
asset_top_page = memnew(HBoxContainer);
library_vb->add_child(asset_top_page);
diff --git a/editor/plugins/asset_library_editor_plugin.h b/editor/plugins/asset_library_editor_plugin.h
index 94289f3b49..70ffbd9eed 100644
--- a/editor/plugins/asset_library_editor_plugin.h
+++ b/editor/plugins/asset_library_editor_plugin.h
@@ -184,6 +184,7 @@ class EditorAssetLibrary : public PanelContainer {
ScrollContainer *library_scroll;
VBoxContainer *library_vb;
Label *library_loading;
+ Label *library_error;
LineEdit *filter;
OptionButton *categories;
OptionButton *repository;
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 2a31d53a7e..7170ce30cc 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -67,13 +67,18 @@ class SnapDialog : public ConfirmationDialog {
SpinBox *grid_offset_y;
SpinBox *grid_step_x;
SpinBox *grid_step_y;
+ SpinBox *primary_grid_steps;
SpinBox *rotation_offset;
SpinBox *rotation_step;
+ SpinBox *scale_step;
public:
SnapDialog() {
const int SPIN_BOX_GRID_RANGE = 16384;
const int SPIN_BOX_ROTATION_RANGE = 360;
+ const float SPIN_BOX_SCALE_MIN = 0.01f;
+ const float SPIN_BOX_SCALE_MAX = 100;
+
Label *label;
VBoxContainer *container;
GridContainer *child_container;
@@ -132,8 +137,28 @@ public:
grid_step_y->set_h_size_flags(SIZE_EXPAND_FILL);
child_container->add_child(grid_step_y);
+ child_container = memnew(GridContainer);
+ child_container->set_columns(2);
+ container->add_child(child_container);
+
+ label = memnew(Label);
+ label->set_text(TTR("Primary Line Every:"));
+ label->set_h_size_flags(SIZE_EXPAND_FILL);
+ child_container->add_child(label);
+
+ primary_grid_steps = memnew(SpinBox);
+ primary_grid_steps->set_min(0);
+ primary_grid_steps->set_step(1);
+ primary_grid_steps->set_max(100);
+ primary_grid_steps->set_allow_greater(true);
+ primary_grid_steps->set_suffix(TTR("steps"));
+ primary_grid_steps->set_h_size_flags(SIZE_EXPAND_FILL);
+ child_container->add_child(primary_grid_steps);
+
container->add_child(memnew(HSeparator));
+ // We need to create another GridContainer with the same column count,
+ // so we can put an HSeparator above
child_container = memnew(GridContainer);
child_container->set_columns(2);
container->add_child(child_container);
@@ -161,22 +186,44 @@ public:
rotation_step->set_suffix("deg");
rotation_step->set_h_size_flags(SIZE_EXPAND_FILL);
child_container->add_child(rotation_step);
+
+ container->add_child(memnew(HSeparator));
+
+ child_container = memnew(GridContainer);
+ child_container->set_columns(2);
+ container->add_child(child_container);
+ label = memnew(Label);
+ label->set_text(TTR("Scale Step:"));
+ child_container->add_child(label);
+ label->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ scale_step = memnew(SpinBox);
+ scale_step->set_min(SPIN_BOX_SCALE_MIN);
+ scale_step->set_max(SPIN_BOX_SCALE_MAX);
+ scale_step->set_allow_greater(true);
+ scale_step->set_h_size_flags(SIZE_EXPAND_FILL);
+ scale_step->set_step(0.01f);
+ child_container->add_child(scale_step);
}
- void set_fields(const Point2 p_grid_offset, const Point2 p_grid_step, const float p_rotation_offset, const float p_rotation_step) {
+ void set_fields(const Point2 p_grid_offset, const Point2 p_grid_step, const int p_primary_grid_steps, const float p_rotation_offset, const float p_rotation_step, const float p_scale_step) {
grid_offset_x->set_value(p_grid_offset.x);
grid_offset_y->set_value(p_grid_offset.y);
grid_step_x->set_value(p_grid_step.x);
grid_step_y->set_value(p_grid_step.y);
+ primary_grid_steps->set_value(p_primary_grid_steps);
rotation_offset->set_value(p_rotation_offset * (180 / Math_PI));
rotation_step->set_value(p_rotation_step * (180 / Math_PI));
+ scale_step->set_value(p_scale_step);
}
- void get_fields(Point2 &p_grid_offset, Point2 &p_grid_step, float &p_rotation_offset, float &p_rotation_step) {
+ void get_fields(Point2 &p_grid_offset, Point2 &p_grid_step, int &p_primary_grid_steps, float &p_rotation_offset, float &p_rotation_step, float &p_scale_step) {
p_grid_offset = Point2(grid_offset_x->get_value(), grid_offset_y->get_value());
p_grid_step = Point2(grid_step_x->get_value(), grid_step_y->get_value());
+ p_primary_grid_steps = int(primary_grid_steps->get_value());
p_rotation_offset = rotation_offset->get_value() / (180 / Math_PI);
p_rotation_step = rotation_step->get_value() / (180 / Math_PI);
+ p_scale_step = scale_step->get_value();
}
};
@@ -898,7 +945,7 @@ void CanvasItemEditor::_commit_canvas_item_state(List<CanvasItem *> p_canvas_ite
}
void CanvasItemEditor::_snap_changed() {
- ((SnapDialog *)snap_dialog)->get_fields(grid_offset, grid_step, snap_rotation_offset, snap_rotation_step);
+ ((SnapDialog *)snap_dialog)->get_fields(grid_offset, grid_step, primary_grid_steps, snap_rotation_offset, snap_rotation_step, snap_scale_step);
grid_step_multiplier = 0;
viewport->update();
}
@@ -1180,8 +1227,8 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
}
if (panning) {
- if (!b->is_pressed()) {
- // Stop panning the viewport (for any mouse button press)
+ if (!b->is_pressed() && (pan_on_scroll || (b->get_button_index() != BUTTON_WHEEL_DOWN && b->get_button_index() != BUTTON_WHEEL_UP))) {
+ // Stop panning the viewport (for any mouse button press except zooming)
panning = false;
}
}
@@ -1268,6 +1315,7 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) {
// Start dragging if we still have nodes
if (drag_selection.size() > 0) {
+ _save_canvas_item_state(drag_selection);
drag_from = transform.affine_inverse().xform((b.is_valid()) ? b->get_position() : viewport->get_local_mouse_position());
Vector2 new_pos;
if (drag_selection.size() == 1) {
@@ -1281,7 +1329,6 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) {
}
drag_type = DRAG_PIVOT;
- _save_canvas_item_state(drag_selection);
}
return true;
}
@@ -1791,7 +1838,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
if (_is_node_movable(canvas_item)) {
Transform2D xform = transform * canvas_item->get_global_transform_with_canvas();
- Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * Transform2D(canvas_item->_edit_get_rotation(), canvas_item->_edit_get_position())).orthonormalized();
+ Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized();
Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
drag_type = DRAG_SCALE_BOTH;
@@ -1825,10 +1872,11 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
drag_to = transform.affine_inverse().xform(m->get_position());
Transform2D parent_xform = canvas_item->get_global_transform_with_canvas() * canvas_item->get_transform().affine_inverse();
- Transform2D unscaled_transform = (transform * parent_xform * Transform2D(canvas_item->_edit_get_rotation(), canvas_item->_edit_get_position())).orthonormalized();
+ Transform2D unscaled_transform = (transform * parent_xform * canvas_item->_edit_get_transform()).orthonormalized();
Transform2D simple_xform = (viewport->get_transform() * unscaled_transform).affine_inverse() * transform;
bool uniform = m->get_shift();
+ bool is_ctrl = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
Point2 drag_from_local = simple_xform.xform(drag_from);
Point2 drag_to_local = simple_xform.xform(drag_to);
@@ -1859,6 +1907,12 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
}
}
}
+
+ if (snap_scale && !is_ctrl) {
+ scale.x = roundf(scale.x / snap_scale_step) * snap_scale_step;
+ scale.y = roundf(scale.y / snap_scale_step) * snap_scale_step;
+ }
+
canvas_item->call("set_scale", scale);
return true;
}
@@ -2274,7 +2328,7 @@ bool CanvasItemEditor::_gui_input_ruler_tool(const Ref<InputEvent> &p_event) {
Point2 previous_origin = ruler_tool_origin;
if (!ruler_tool_active)
- ruler_tool_origin = snap_point(viewport->get_local_mouse_position() / zoom + view_offset) * zoom;
+ ruler_tool_origin = snap_point(viewport->get_local_mouse_position() / zoom + view_offset);
if (b.is_valid() && b->get_button_index() == BUTTON_LEFT) {
if (b->is_pressed()) {
@@ -2287,9 +2341,7 @@ bool CanvasItemEditor::_gui_input_ruler_tool(const Ref<InputEvent> &p_event) {
return true;
}
- bool is_snap_active = smart_snap_active ^ Input::get_singleton()->is_key_pressed(KEY_CONTROL);
-
- if (m.is_valid() && (ruler_tool_active || (is_snap_active && previous_origin != ruler_tool_origin))) {
+ if (m.is_valid() && (ruler_tool_active || (grid_snap_active && previous_origin != ruler_tool_origin))) {
viewport->update();
return true;
@@ -2641,41 +2693,72 @@ void CanvasItemEditor::_draw_rulers() {
}
void CanvasItemEditor::_draw_grid() {
- if (show_grid || grid_snap_active) {
- //Draw the grid
- Size2 s = viewport->get_size();
- int last_cell = 0;
- Transform2D xform = transform.affine_inverse();
+ if (show_grid || grid_snap_active) {
+ // Draw the grid
Vector2 real_grid_offset;
- List<CanvasItem *> selection = _get_edited_canvas_items();
+ const List<CanvasItem *> selection = _get_edited_canvas_items();
+
if (snap_relative && selection.size() > 0) {
- Vector2 topleft = _get_encompassing_rect_from_list(selection).position;
+ const Vector2 topleft = _get_encompassing_rect_from_list(selection).position;
real_grid_offset.x = fmod(topleft.x, grid_step.x * (real_t)Math::pow(2.0, grid_step_multiplier));
real_grid_offset.y = fmod(topleft.y, grid_step.y * (real_t)Math::pow(2.0, grid_step_multiplier));
} else {
real_grid_offset = grid_offset;
}
- const Color grid_color = EditorSettings::get_singleton()->get("editors/2d/grid_color");
+ // Draw a "primary" line every several lines to make measurements easier.
+ // The step is configurable in the Configure Snap dialog.
+ const Color secondary_grid_color = EditorSettings::get_singleton()->get("editors/2d/grid_color");
+ const Color primary_grid_color =
+ Color(secondary_grid_color.r, secondary_grid_color.g, secondary_grid_color.b, secondary_grid_color.a * 2.5);
+
+ const Size2 viewport_size = viewport->get_size();
+ const Transform2D xform = transform.affine_inverse();
+ int last_cell = 0;
+
if (grid_step.x != 0) {
- for (int i = 0; i < s.width; i++) {
- int cell = Math::fast_ftoi(Math::floor((xform.xform(Vector2(i, 0)).x - real_grid_offset.x) / (grid_step.x * Math::pow(2.0, grid_step_multiplier))));
- if (i == 0)
+ for (int i = 0; i < viewport_size.width; i++) {
+ const int cell =
+ Math::fast_ftoi(Math::floor((xform.xform(Vector2(i, 0)).x - real_grid_offset.x) / (grid_step.x * Math::pow(2.0, grid_step_multiplier))));
+
+ if (i == 0) {
last_cell = cell;
- if (last_cell != cell)
- viewport->draw_line(Point2(i, 0), Point2(i, s.height), grid_color, Math::round(EDSCALE));
+ }
+
+ if (last_cell != cell) {
+ Color grid_color;
+ if (primary_grid_steps == 0) {
+ grid_color = secondary_grid_color;
+ } else {
+ grid_color = cell % primary_grid_steps == 0 ? primary_grid_color : secondary_grid_color;
+ }
+
+ viewport->draw_line(Point2(i, 0), Point2(i, viewport_size.height), grid_color, Math::round(EDSCALE));
+ }
last_cell = cell;
}
}
if (grid_step.y != 0) {
- for (int i = 0; i < s.height; i++) {
- int cell = Math::fast_ftoi(Math::floor((xform.xform(Vector2(0, i)).y - real_grid_offset.y) / (grid_step.y * Math::pow(2.0, grid_step_multiplier))));
- if (i == 0)
+ for (int i = 0; i < viewport_size.height; i++) {
+ const int cell =
+ Math::fast_ftoi(Math::floor((xform.xform(Vector2(0, i)).y - real_grid_offset.y) / (grid_step.y * Math::pow(2.0, grid_step_multiplier))));
+
+ if (i == 0) {
last_cell = cell;
- if (last_cell != cell)
- viewport->draw_line(Point2(0, i), Point2(s.width, i), grid_color, Math::round(EDSCALE));
+ }
+
+ if (last_cell != cell) {
+ Color grid_color;
+ if (primary_grid_steps == 0) {
+ grid_color = secondary_grid_color;
+ } else {
+ grid_color = cell % primary_grid_steps == 0 ? primary_grid_color : secondary_grid_color;
+ }
+
+ viewport->draw_line(Point2(0, i), Point2(viewport_size.width, i), grid_color, Math::round(EDSCALE));
+ }
last_cell = cell;
}
}
@@ -2687,19 +2770,17 @@ void CanvasItemEditor::_draw_ruler_tool() {
if (tool != TOOL_RULER)
return;
- bool is_snap_active = smart_snap_active ^ Input::get_singleton()->is_key_pressed(KEY_CONTROL);
-
if (ruler_tool_active) {
Color ruler_primary_color = get_color("accent_color", "Editor");
Color ruler_secondary_color = ruler_primary_color;
ruler_secondary_color.a = 0.5;
- Point2 begin = ruler_tool_origin - view_offset * zoom;
+ Point2 begin = (ruler_tool_origin - view_offset) * zoom;
Point2 end = snap_point(viewport->get_local_mouse_position() / zoom + view_offset) * zoom - view_offset * zoom;
Point2 corner = Point2(begin.x, end.y);
Vector2 length_vector = (begin - end).abs() / zoom;
- bool draw_secondary_lines = (begin.y != corner.y && end.x != corner.x);
+ bool draw_secondary_lines = !(Math::is_equal_approx(begin.y, corner.y) || Math::is_equal_approx(end.x, corner.x));
viewport->draw_line(begin, end, ruler_primary_color, Math::round(EDSCALE * 3), true);
if (draw_secondary_lines) {
@@ -2721,8 +2802,10 @@ void CanvasItemEditor::_draw_ruler_tool() {
viewport->draw_string(font, text_pos, vformat("%.2f px", length_vector.length()), font_color);
if (draw_secondary_lines) {
- int horizontal_axis_angle = round(180 * atan2(length_vector.y, length_vector.x) / Math_PI);
- int vertictal_axis_angle = 90 - horizontal_axis_angle;
+ const float horizontal_angle_rad = atan2(length_vector.y, length_vector.x);
+ const float vertical_angle_rad = Math_PI / 2.0 - horizontal_angle_rad;
+ const int horizontal_angle = round(180 * horizontal_angle_rad / Math_PI);
+ const int vertical_angle = round(180 * vertical_angle_rad / Math_PI);
Point2 text_pos2 = text_pos;
text_pos2.x = begin.x < text_pos.x ? MIN(text_pos.x - text_width, begin.x - text_width / 2) : MAX(text_pos.x + text_width, begin.x - text_width / 2);
@@ -2731,7 +2814,7 @@ void CanvasItemEditor::_draw_ruler_tool() {
Point2 v_angle_text_pos = Point2();
v_angle_text_pos.x = CLAMP(begin.x - angle_text_width / 2, angle_text_width / 2, viewport->get_rect().size.x - angle_text_width);
v_angle_text_pos.y = begin.y < end.y ? MIN(text_pos2.y - 2 * text_height, begin.y - text_height * 0.5) : MAX(text_pos2.y + text_height * 3, begin.y + text_height * 1.5);
- viewport->draw_string(font, v_angle_text_pos, vformat("%d deg", vertictal_axis_angle), font_secondary_color);
+ viewport->draw_string(font, v_angle_text_pos, vformat("%d deg", vertical_angle), font_secondary_color);
text_pos2 = text_pos;
text_pos2.y = end.y < text_pos.y ? MIN(text_pos.y - text_height * 2, end.y - text_height / 2) : MAX(text_pos.y + text_height * 2, end.y - text_height / 2);
@@ -2742,20 +2825,48 @@ void CanvasItemEditor::_draw_ruler_tool() {
if (begin.y < end.y) {
h_angle_text_pos.y = end.y + text_height * 1.5;
if (ABS(text_pos2.x - h_angle_text_pos.x) < text_width) {
- int height_multiplier = 1.5 + (int)is_snap_active;
+ int height_multiplier = 1.5 + (int)grid_snap_active;
h_angle_text_pos.y = MAX(text_pos.y + height_multiplier * text_height, MAX(end.y + text_height * 1.5, text_pos2.y + height_multiplier * text_height));
}
} else {
h_angle_text_pos.y = end.y - text_height * 0.5;
if (ABS(text_pos2.x - h_angle_text_pos.x) < text_width) {
- int height_multiplier = 1 + (int)is_snap_active;
+ int height_multiplier = 1 + (int)grid_snap_active;
h_angle_text_pos.y = MIN(text_pos.y - height_multiplier * text_height, MIN(end.y - text_height * 0.5, text_pos2.y - height_multiplier * text_height));
}
}
- viewport->draw_string(font, h_angle_text_pos, vformat("%d deg", horizontal_axis_angle), font_secondary_color);
+ viewport->draw_string(font, h_angle_text_pos, vformat("%d deg", horizontal_angle), font_secondary_color);
+
+ // Angle arcs
+ int arc_point_count = 8;
+ float arc_radius_max_length_percent = 0.1;
+ float ruler_length = length_vector.length() * zoom;
+ float arc_max_radius = 50.0;
+ float arc_line_width = 2.0;
+
+ const Vector2 end_to_begin = (end - begin);
+
+ float arc_1_start_angle =
+ end_to_begin.x < 0 ?
+ (end_to_begin.y < 0 ? 3.0 * Math_PI / 2.0 - vertical_angle_rad : Math_PI / 2.0) :
+ (end_to_begin.y < 0 ? 3.0 * Math_PI / 2.0 : Math_PI / 2.0 - vertical_angle_rad);
+ float arc_1_end_angle = arc_1_start_angle + vertical_angle_rad;
+ // Constrain arc to triangle height & max size
+ float arc_1_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.y)), arc_max_radius);
+
+ float arc_2_start_angle =
+ end_to_begin.x < 0 ?
+ (end_to_begin.y < 0 ? 0.0 : -horizontal_angle_rad) :
+ (end_to_begin.y < 0 ? Math_PI - horizontal_angle_rad : Math_PI);
+ float arc_2_end_angle = arc_2_start_angle + horizontal_angle_rad;
+ // Constrain arc to triangle width & max size
+ float arc_2_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.x)), arc_max_radius);
+
+ viewport->draw_arc(begin, arc_1_radius, arc_1_start_angle, arc_1_end_angle, arc_point_count, ruler_primary_color, Math::round(EDSCALE * arc_line_width));
+ viewport->draw_arc(end, arc_2_radius, arc_2_start_angle, arc_2_end_angle, arc_point_count, ruler_primary_color, Math::round(EDSCALE * arc_line_width));
}
- if (is_snap_active) {
+ if (grid_snap_active) {
text_pos = (begin + end) / 2 + Vector2(-text_width / 2, text_height / 2);
text_pos.x = CLAMP(text_pos.x, text_width / 2, viewport->get_rect().size.x - text_width * 1.5);
@@ -2766,20 +2877,20 @@ void CanvasItemEditor::_draw_ruler_tool() {
Point2 text_pos2 = text_pos;
text_pos2.x = begin.x < text_pos.x ? MIN(text_pos.x - text_width, begin.x - text_width / 2) : MAX(text_pos.x + text_width, begin.x - text_width / 2);
- viewport->draw_string(font, text_pos2, vformat("%d units", (int)(length_vector.y / grid_step.y)), font_secondary_color);
+ viewport->draw_string(font, text_pos2, vformat("%d units", roundf(length_vector.y / grid_step.y)), font_secondary_color);
text_pos2 = text_pos;
text_pos2.y = end.y < text_pos.y ? MIN(text_pos.y - text_height * 2, end.y + text_height / 2) : MAX(text_pos.y + text_height * 2, end.y + text_height / 2);
- viewport->draw_string(font, text_pos2, vformat("%d units", (int)(length_vector.x / grid_step.x)), font_secondary_color);
+ viewport->draw_string(font, text_pos2, vformat("%d units", roundf(length_vector.x / grid_step.x)), font_secondary_color);
} else {
viewport->draw_string(font, text_pos, vformat("%d units", roundf((length_vector / grid_step).length())), font_color);
}
}
} else {
- if (is_snap_active) {
+ if (grid_snap_active) {
Ref<Texture> position_icon = get_icon("EditorPosition", "EditorIcons");
- viewport->draw_texture(get_icon("EditorPosition", "EditorIcons"), ruler_tool_origin - view_offset * zoom - position_icon->get_size() / 2);
+ viewport->draw_texture(get_icon("EditorPosition", "EditorIcons"), (ruler_tool_origin - view_offset) * zoom - position_icon->get_size() / 2);
}
}
}
@@ -3048,7 +3159,7 @@ void CanvasItemEditor::_draw_selection() {
}
} else {
- Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * Transform2D(canvas_item->_edit_get_rotation(), canvas_item->_edit_get_position())).orthonormalized();
+ Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized();
Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
viewport->draw_set_transform_matrix(simple_xform);
viewport->draw_texture(position_icon, -(position_icon->get_size() / 2));
@@ -3060,7 +3171,7 @@ void CanvasItemEditor::_draw_selection() {
if (canvas_item->_edit_use_pivot()) {
// Draw the node's pivot
- Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * Transform2D(canvas_item->_edit_get_rotation(), canvas_item->_edit_get_position() + canvas_item->_edit_get_pivot())).orthonormalized();
+ Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized();
Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
viewport->draw_set_transform_matrix(simple_xform);
@@ -3105,7 +3216,7 @@ void CanvasItemEditor::_draw_selection() {
bool is_alt = Input::get_singleton()->is_key_pressed(KEY_ALT);
if ((is_alt && is_ctrl) || tool == TOOL_SCALE || drag_type == DRAG_SCALE_X || drag_type == DRAG_SCALE_Y) {
if (_is_node_movable(canvas_item)) {
- Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * Transform2D(canvas_item->_edit_get_rotation(), canvas_item->_edit_get_position())).orthonormalized();
+ Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized();
Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
Size2 scale_factor = Size2(SCALE_HANDLE_DISTANCE, SCALE_HANDLE_DISTANCE);
@@ -3324,7 +3435,7 @@ void CanvasItemEditor::_draw_invisible_nodes_positions(Node *p_node, const Trans
// Draw the node's position
Ref<Texture> position_icon = get_icon("EditorPositionUnselected", "EditorIcons");
- Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * Transform2D(canvas_item->_edit_get_rotation(), canvas_item->_edit_get_position())).orthonormalized();
+ Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized();
Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
viewport->draw_set_transform_matrix(simple_xform);
viewport->draw_texture(position_icon, -position_icon->get_size() / 2, Color(1.0, 1.0, 1.0, 0.5));
@@ -3700,6 +3811,7 @@ void CanvasItemEditor::_notification(int p_what) {
grid_snap_button->set_icon(get_icon("SnapGrid", "EditorIcons"));
snap_config_menu->set_icon(get_icon("GuiTabMenu", "EditorIcons"));
skeleton_menu->set_icon(get_icon("Bone", "EditorIcons"));
+ override_camera_button->set_icon(get_icon("Camera2D", "EditorIcons"));
pan_button->set_icon(get_icon("ToolPan", "EditorIcons"));
ruler_button->set_icon(get_icon("Ruler", "EditorIcons"));
pivot_button->set_icon(get_icon("EditPivot", "EditorIcons"));
@@ -3769,6 +3881,15 @@ void CanvasItemEditor::_notification(int p_what) {
anchor_mode_button->set_icon(get_icon("Anchor", "EditorIcons"));
}
+
+ if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+ if (!is_visible() && override_camera_button->is_pressed()) {
+ ScriptEditorDebugger *debugger = ScriptEditor::get_singleton()->get_debugger();
+
+ debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_NONE);
+ override_camera_button->set_pressed(false);
+ }
+ }
}
void CanvasItemEditor::_selection_changed() {
@@ -4110,6 +4231,15 @@ void CanvasItemEditor::_button_toggle_grid_snap(bool p_status) {
grid_snap_active = p_status;
viewport->update();
}
+void CanvasItemEditor::_button_override_camera(bool p_pressed) {
+ ScriptEditorDebugger *debugger = ScriptEditor::get_singleton()->get_debugger();
+
+ if (p_pressed) {
+ debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_2D);
+ } else {
+ debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_NONE);
+ }
+}
void CanvasItemEditor::_button_tool_select(int p_index) {
@@ -4207,6 +4337,17 @@ void CanvasItemEditor::_button_toggle_anchor_mode(bool p_status) {
viewport->update();
}
+void CanvasItemEditor::_update_override_camera_button(bool p_game_running) {
+ if (p_game_running) {
+ override_camera_button->set_disabled(false);
+ override_camera_button->set_tooltip(TTR("Game Camera Override\nOverrides game camera with editor viewport camera."));
+ } else {
+ override_camera_button->set_disabled(true);
+ override_camera_button->set_pressed(false);
+ override_camera_button->set_tooltip(TTR("Game Camera Override\nNo game instance running."));
+ }
+}
+
void CanvasItemEditor::_popup_callback(int p_op) {
last_option = MenuOption(p_op);
@@ -4271,6 +4412,11 @@ void CanvasItemEditor::_popup_callback(int p_op) {
int idx = snap_config_menu->get_popup()->get_item_index(SNAP_USE_ROTATION);
snap_config_menu->get_popup()->set_item_checked(idx, snap_rotation);
} break;
+ case SNAP_USE_SCALE: {
+ snap_scale = !snap_scale;
+ int idx = snap_config_menu->get_popup()->get_item_index(SNAP_USE_SCALE);
+ snap_config_menu->get_popup()->set_item_checked(idx, snap_scale);
+ } break;
case SNAP_RELATIVE: {
snap_relative = !snap_relative;
int idx = snap_config_menu->get_popup()->get_item_index(SNAP_RELATIVE);
@@ -4283,8 +4429,8 @@ void CanvasItemEditor::_popup_callback(int p_op) {
snap_config_menu->get_popup()->set_item_checked(idx, snap_pixel);
} break;
case SNAP_CONFIGURE: {
- ((SnapDialog *)snap_dialog)->set_fields(grid_offset, grid_step, snap_rotation_offset, snap_rotation_step);
- snap_dialog->popup_centered(Size2(220, 160));
+ ((SnapDialog *)snap_dialog)->set_fields(grid_offset, grid_step, primary_grid_steps, snap_rotation_offset, snap_rotation_step, snap_scale_step);
+ snap_dialog->popup_centered(Size2(220, 160) * EDSCALE);
} break;
case SKELETON_SHOW_BONES: {
skeleton_show_bones = !skeleton_show_bones;
@@ -4799,6 +4945,8 @@ void CanvasItemEditor::_bind_methods() {
ClassDB::bind_method("_button_zoom_plus", &CanvasItemEditor::_button_zoom_plus);
ClassDB::bind_method("_button_toggle_smart_snap", &CanvasItemEditor::_button_toggle_smart_snap);
ClassDB::bind_method("_button_toggle_grid_snap", &CanvasItemEditor::_button_toggle_grid_snap);
+ ClassDB::bind_method(D_METHOD("_button_override_camera", "pressed"), &CanvasItemEditor::_button_override_camera);
+ ClassDB::bind_method(D_METHOD("_update_override_camera_button", "game_running"), &CanvasItemEditor::_update_override_camera_button);
ClassDB::bind_method("_button_toggle_anchor_mode", &CanvasItemEditor::_button_toggle_anchor_mode);
ClassDB::bind_method("_update_scroll", &CanvasItemEditor::_update_scroll);
ClassDB::bind_method("_update_scrollbars", &CanvasItemEditor::_update_scrollbars);
@@ -4831,8 +4979,10 @@ Dictionary CanvasItemEditor::get_state() const {
state["ofs"] = view_offset;
state["grid_offset"] = grid_offset;
state["grid_step"] = grid_step;
+ state["primary_grid_steps"] = primary_grid_steps;
state["snap_rotation_offset"] = snap_rotation_offset;
state["snap_rotation_step"] = snap_rotation_step;
+ state["snap_scale_step"] = snap_scale_step;
state["smart_snap_active"] = smart_snap_active;
state["grid_snap_active"] = grid_snap_active;
state["snap_node_parent"] = snap_node_parent;
@@ -4850,6 +5000,7 @@ Dictionary CanvasItemEditor::get_state() const {
state["show_zoom_control"] = zoom_hb->is_visible();
state["show_edit_locks"] = show_edit_locks;
state["snap_rotation"] = snap_rotation;
+ state["snap_scale"] = snap_scale;
state["snap_relative"] = snap_relative;
state["snap_pixel"] = snap_pixel;
state["skeleton_show_bones"] = skeleton_show_bones;
@@ -4879,6 +5030,10 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) {
grid_step = state["grid_step"];
}
+ if (state.has("primary_grid_steps")) {
+ primary_grid_steps = state["primary_grid_steps"];
+ }
+
if (state.has("snap_rotation_step")) {
snap_rotation_step = state["snap_rotation_step"];
}
@@ -4887,6 +5042,10 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) {
snap_rotation_offset = state["snap_rotation_offset"];
}
+ if (state.has("snap_scale_step")) {
+ snap_scale_step = state["snap_scale_step"];
+ }
+
if (state.has("smart_snap_active")) {
smart_snap_active = state["smart_snap_active"];
smart_snap_button->set_pressed(smart_snap_active);
@@ -4987,6 +5146,12 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) {
snap_config_menu->get_popup()->set_item_checked(idx, snap_rotation);
}
+ if (state.has("snap_scale")) {
+ snap_scale = state["snap_scale"];
+ int idx = snap_config_menu->get_popup()->get_item_index(SNAP_USE_SCALE);
+ snap_config_menu->get_popup()->set_item_checked(idx, snap_scale);
+ }
+
if (state.has("snap_relative")) {
snap_relative = state["snap_relative"];
int idx = snap_config_menu->get_popup()->get_item_index(SNAP_RELATIVE);
@@ -5068,9 +5233,11 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
previous_update_view_offset = view_offset; // Moves the view a little bit to the left so that (0,0) is visible. The values a relative to a 16/10 screen
grid_offset = Point2();
grid_step = Point2(10, 10);
+ primary_grid_steps = 8; // A power-of-two value works better as a default
grid_step_multiplier = 0;
snap_rotation_offset = 0;
snap_rotation_step = 15 / (180 / Math_PI);
+ snap_scale_step = 0.1f;
smart_snap_active = false;
grid_snap_active = false;
snap_node_parent = true;
@@ -5080,6 +5247,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
snap_other_nodes = true;
snap_guides = true;
snap_rotation = false;
+ snap_scale = false;
snap_relative = false;
snap_pixel = false;
snap_target[0] = SNAP_TARGET_NONE;
@@ -5111,6 +5279,9 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
editor_selection->connect("selection_changed", this, "update");
editor_selection->connect("selection_changed", this, "_selection_changed");
+ editor->call_deferred("connect", "play_pressed", this, "_update_override_camera_button", make_binds(true));
+ editor->call_deferred("connect", "stop_pressed", this, "_update_override_camera_button", make_binds(false));
+
hb = memnew(HBoxContainer);
add_child(hb);
hb->set_anchors_and_margins_preset(Control::PRESET_WIDE);
@@ -5293,6 +5464,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
p->connect("id_pressed", this, "_popup_callback");
p->set_hide_on_checkable_item_selection(false);
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/use_rotation_snap", TTR("Use Rotation Snap")), SNAP_USE_ROTATION);
+ p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/use_scale_snap", TTR("Use Scale Snap")), SNAP_USE_SCALE);
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_relative", TTR("Snap Relative")), SNAP_RELATIVE);
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/use_pixel_snap", TTR("Use Pixel Snap")), SNAP_USE_PIXEL);
p->add_submenu_item(TTR("Smart Snapping"), "SmartSnapping");
@@ -5355,6 +5527,15 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
hb->add_child(memnew(VSeparator));
+ override_camera_button = memnew(ToolButton);
+ hb->add_child(override_camera_button);
+ override_camera_button->connect("toggled", this, "_button_override_camera");
+ override_camera_button->set_toggle_mode(true);
+ override_camera_button->set_disabled(true);
+ _update_override_camera_button(false);
+
+ hb->add_child(memnew(VSeparator));
+
view_menu = memnew(MenuButton);
view_menu->set_text(TTR("View"));
hb->add_child(view_menu);
@@ -5438,7 +5619,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
key_auto_insert_button->set_toggle_mode(true);
key_auto_insert_button->set_focus_mode(FOCUS_NONE);
//key_auto_insert_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_KEY));
- key_auto_insert_button->set_tooltip(TTR("Auto insert keys when objects are translated, rotated on scaled (based on mask).\nKeys are only added to existing tracks, no new tracks will be created.\nKeys must be inserted manually for the first time."));
+ key_auto_insert_button->set_tooltip(TTR("Auto insert keys when objects are translated, rotated or scaled (based on mask).\nKeys are only added to existing tracks, no new tracks will be created.\nKeys must be inserted manually for the first time."));
key_auto_insert_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/anim_auto_insert_key", TTR("Auto Insert Key")));
animation_hb->add_child(key_auto_insert_button);
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 480fb89621..3fdf00d611 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -108,6 +108,7 @@ private:
SNAP_USE_GRID,
SNAP_USE_GUIDES,
SNAP_USE_ROTATION,
+ SNAP_USE_SCALE,
SNAP_RELATIVE,
SNAP_CONFIGURE,
SNAP_USE_PIXEL,
@@ -255,10 +256,12 @@ private:
Point2 grid_offset;
Point2 grid_step;
+ int primary_grid_steps;
int grid_step_multiplier;
float snap_rotation_step;
float snap_rotation_offset;
+ float snap_scale_step;
bool smart_snap_active;
bool grid_snap_active;
@@ -269,6 +272,7 @@ private:
bool snap_other_nodes;
bool snap_guides;
bool snap_rotation;
+ bool snap_scale;
bool snap_relative;
bool snap_pixel;
bool skeleton_show_bones;
@@ -360,6 +364,7 @@ private:
ToolButton *ungroup_button;
MenuButton *skeleton_menu;
+ ToolButton *override_camera_button;
MenuButton *view_menu;
HBoxContainer *animation_hb;
MenuButton *animation_menu;
@@ -533,8 +538,11 @@ private:
void _button_zoom_plus();
void _button_toggle_smart_snap(bool p_status);
void _button_toggle_grid_snap(bool p_status);
+ void _button_override_camera(bool p_pressed);
void _button_tool_select(int p_index);
+ void _update_override_camera_button(bool p_game_running);
+
HSplitContainer *palette_split;
VSplitContainer *bottom_split;
diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp
index 9160920c50..727d92ba05 100644
--- a/editor/plugins/curve_editor_plugin.cpp
+++ b/editor/plugins/curve_editor_plugin.cpp
@@ -736,6 +736,9 @@ void CurveEditor::_draw() {
if (_selected_point > 0 && _selected_point + 1 < curve.get_point_count()) {
text_color.a *= 0.4;
draw_string(font, Vector2(50, font_height), TTR("Hold Shift to edit tangents individually"), text_color);
+ } else if (curve.get_point_count() == 0) {
+ text_color.a *= 0.4;
+ draw_string(font, Vector2(50, font_height), TTR("Right click to add point"), text_color);
}
}
diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp
index 8acc41a2c7..007ce58bd7 100644
--- a/editor/plugins/editor_preview_plugins.cpp
+++ b/editor/plugins/editor_preview_plugins.cpp
@@ -103,9 +103,11 @@ Ref<Texture> EditorTexturePreviewPlugin::generate(const RES &p_from, const Size2
img = ltex->to_image();
} else {
Ref<Texture> tex = p_from;
- img = tex->get_data();
- if (img.is_valid()) {
- img = img->duplicate();
+ if (tex.is_valid()) {
+ img = tex->get_data();
+ if (img.is_valid()) {
+ img = img->duplicate();
+ }
}
}
diff --git a/editor/plugins/mesh_instance_editor_plugin.cpp b/editor/plugins/mesh_instance_editor_plugin.cpp
index 635b934333..22df8fd8f4 100644
--- a/editor/plugins/mesh_instance_editor_plugin.cpp
+++ b/editor/plugins/mesh_instance_editor_plugin.cpp
@@ -180,6 +180,7 @@ void MeshInstanceEditor::_menu_option(int p_option) {
CollisionShape *cshape = memnew(CollisionShape);
cshape->set_shape(shapes[i]);
+ cshape->set_transform(node->get_transform());
Node *owner = node->get_owner();
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index ecb2354aa1..f63445dab8 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -571,6 +571,7 @@ void ScriptTextEditor::_validate_script() {
String error_text = "error(" + itos(line) + "," + itos(col) + "): " + errortxt;
code_editor->set_error(error_text);
code_editor->set_error_pos(line - 1, col - 1);
+ script_is_valid = false;
} else {
code_editor->set_error("");
line = -1;
@@ -585,6 +586,7 @@ void ScriptTextEditor::_validate_script() {
functions.push_back(E->get());
}
+ script_is_valid = true;
}
_update_connected_methods();
@@ -967,12 +969,17 @@ void ScriptTextEditor::_update_connected_methods() {
text_edit->clear_info_icons();
missing_connections.clear();
+ if (!script_is_valid) {
+ return;
+ }
+
Node *base = get_tree()->get_edited_scene_root();
if (!base) {
return;
}
Vector<Node *> nodes = _find_all_node_for_script(base, base, script);
+ Set<StringName> methods_found;
for (int i = 0; i < nodes.size(); i++) {
List<Connection> connections;
nodes[i]->get_signals_connected_to_this(&connections);
@@ -989,28 +996,41 @@ void ScriptTextEditor::_update_connected_methods() {
continue;
}
- if (!ClassDB::has_method(script->get_instance_base_type(), connection.method)) {
+ if (methods_found.has(connection.method)) {
+ continue;
+ }
- int line = script->get_language()->find_function(connection.method, text_edit->get_text());
- if (line < 0) {
- // There is a chance that the method is inherited from another script.
- bool found_inherited_function = false;
- Ref<Script> inherited_script = script->get_base_script();
- while (!inherited_script.is_null()) {
- line = inherited_script->get_language()->find_function(connection.method, inherited_script->get_source_code());
- if (line != -1) {
- found_inherited_function = true;
- break;
- }
-
- inherited_script = inherited_script->get_base_script();
+ if (!ClassDB::has_method(script->get_instance_base_type(), connection.method)) {
+ int line = -1;
+
+ for (int j = 0; j < functions.size(); j++) {
+ String name = functions[j].get_slice(":", 0);
+ if (name == connection.method) {
+ line = functions[j].get_slice(":", 1).to_int();
+ text_edit->set_line_info_icon(line - 1, get_parent_control()->get_icon("Slot", "EditorIcons"), connection.method);
+ methods_found.insert(connection.method);
+ break;
}
+ }
- if (!found_inherited_function) {
- missing_connections.push_back(connection);
+ if (line >= 0) {
+ continue;
+ }
+
+ // There is a chance that the method is inherited from another script.
+ bool found_inherited_function = false;
+ Ref<Script> inherited_script = script->get_base_script();
+ while (!inherited_script.is_null()) {
+ if (inherited_script->has_method(connection.method)) {
+ found_inherited_function = true;
+ break;
}
- } else {
- text_edit->set_line_info_icon(line - 1, get_parent_control()->get_icon("Slot", "EditorIcons"), connection.method);
+
+ inherited_script = inherited_script->get_base_script();
+ }
+
+ if (!found_inherited_function) {
+ missing_connections.push_back(connection);
}
}
}
@@ -1186,7 +1206,7 @@ void ScriptTextEditor::_edit_option(int p_op) {
if (expression.parse(line) == OK) {
Variant result = expression.execute(Array(), Variant(), false);
if (expression.get_error_text() == "") {
- results.append(whitespace + (String)result);
+ results.append(whitespace + result.get_construct_string());
} else {
results.append(line);
}
@@ -1718,6 +1738,7 @@ void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p
ScriptTextEditor::ScriptTextEditor() {
theme_loaded = false;
+ script_is_valid = false;
VSplitContainer *editor_box = memnew(VSplitContainer);
add_child(editor_box);
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index eba75befd4..2ba0be8feb 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -59,6 +59,7 @@ class ScriptTextEditor : public ScriptEditorBase {
RichTextLabel *warnings_panel;
Ref<Script> script;
+ bool script_is_valid;
Vector<String> functions;
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index 1d8fd38858..e0189f8a92 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/editor/plugins/spatial_editor_plugin.cpp
@@ -901,6 +901,8 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> b = p_event;
if (b.is_valid()) {
+ emit_signal("clicked", this);
+
float zoom_factor = 1 + (ZOOM_MULTIPLIER - 1) * b->get_factor();
switch (b->get_button_index()) {
@@ -2760,8 +2762,10 @@ void SpatialEditorViewport::_menu_option(int p_option) {
void SpatialEditorViewport::_preview_exited_scene() {
+ preview_camera->disconnect("toggled", this, "_toggle_camera_preview");
preview_camera->set_pressed(false);
_toggle_camera_preview(false);
+ preview_camera->connect("toggled", this, "_toggle_camera_preview");
view_menu->show();
}
@@ -3031,6 +3035,9 @@ void SpatialEditorViewport::set_state(const Dictionary &p_state) {
view_menu->get_popup()->set_item_checked(idx, previewing_cinema);
}
+ if (preview_camera->is_connected("toggled", this, "_toggle_camera_preview")) {
+ preview_camera->disconnect("toggled", this, "_toggle_camera_preview");
+ }
if (p_state.has("previewing")) {
Node *pv = EditorNode::get_singleton()->get_edited_scene()->get_node(p_state["previewing"]);
if (Object::cast_to<Camera>(pv)) {
@@ -3043,6 +3050,7 @@ void SpatialEditorViewport::set_state(const Dictionary &p_state) {
preview_camera->show();
}
}
+ preview_camera->connect("toggled", this, "_toggle_camera_preview");
}
Dictionary SpatialEditorViewport::get_state() const {
@@ -3096,6 +3104,7 @@ void SpatialEditorViewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("drop_data_fw"), &SpatialEditorViewport::drop_data_fw);
ADD_SIGNAL(MethodInfo("toggle_maximize_view", PropertyInfo(Variant::OBJECT, "viewport")));
+ ADD_SIGNAL(MethodInfo("clicked", PropertyInfo(Variant::OBJECT, "viewport")));
}
void SpatialEditorViewport::reset() {
@@ -4369,6 +4378,19 @@ void SpatialEditor::_menu_item_toggled(bool pressed, int p_option) {
tool_option_button[TOOL_OPT_USE_SNAP]->set_pressed(pressed);
snap_enabled = pressed;
} break;
+
+ case MENU_TOOL_OVERRIDE_CAMERA: {
+ ScriptEditorDebugger *const debugger = ScriptEditor::get_singleton()->get_debugger();
+
+ if (pressed) {
+ using Override = ScriptEditorDebugger::CameraOverride;
+
+ debugger->set_camera_override((Override)(Override::OVERRIDE_3D_1 + camera_override_viewport_id));
+ } else {
+ debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_NONE);
+ }
+
+ } break;
}
}
@@ -4396,6 +4418,35 @@ void SpatialEditor::_menu_gizmo_toggled(int p_option) {
update_all_gizmos();
}
+void SpatialEditor::_update_camera_override_button(bool p_game_running) {
+ Button *const button = tool_option_button[TOOL_OPT_OVERRIDE_CAMERA];
+
+ if (p_game_running) {
+ button->set_disabled(false);
+ button->set_tooltip(TTR("Game Camera Override\nNo game instance running."));
+ } else {
+ button->set_disabled(true);
+ button->set_pressed(false);
+ button->set_tooltip(TTR("Game Camera Override\nOverrides game camera with editor viewport camera."));
+ }
+}
+
+void SpatialEditor::_update_camera_override_viewport(Object *p_viewport) {
+ SpatialEditorViewport *current_viewport = Object::cast_to<SpatialEditorViewport>(p_viewport);
+
+ if (!current_viewport)
+ return;
+
+ ScriptEditorDebugger *const debugger = ScriptEditor::get_singleton()->get_debugger();
+
+ camera_override_viewport_id = current_viewport->index;
+ if (debugger->get_camera_override() >= ScriptEditorDebugger::OVERRIDE_3D_1) {
+ using Override = ScriptEditorDebugger::CameraOverride;
+
+ debugger->set_camera_override((Override)(Override::OVERRIDE_3D_1 + camera_override_viewport_id));
+ }
+}
+
void SpatialEditor::_menu_item_pressed(int p_option) {
switch (p_option) {
@@ -5290,6 +5341,7 @@ void SpatialEditor::_notification(int p_what) {
tool_option_button[SpatialEditor::TOOL_OPT_LOCAL_COORDS]->set_icon(get_icon("Object", "EditorIcons"));
tool_option_button[SpatialEditor::TOOL_OPT_USE_SNAP]->set_icon(get_icon("Snap", "EditorIcons"));
+ tool_option_button[SpatialEditor::TOOL_OPT_OVERRIDE_CAMERA]->set_icon(get_icon("Camera", "EditorIcons"));
view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), get_icon("Panels1", "EditorIcons"));
view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), get_icon("Panels2", "EditorIcons"));
@@ -5305,6 +5357,9 @@ void SpatialEditor::_notification(int p_what) {
get_tree()->connect("node_removed", this, "_node_removed");
EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor()->connect("node_changed", this, "_refresh_menu_icons");
editor_selection->connect("selection_changed", this, "_refresh_menu_icons");
+
+ editor->connect("stop_pressed", this, "_update_camera_override_button", make_binds(false));
+ editor->connect("play_pressed", this, "_update_camera_override_button", make_binds(true));
} else if (p_what == NOTIFICATION_ENTER_TREE) {
_register_all_gizmos();
@@ -5339,6 +5394,13 @@ void SpatialEditor::_notification(int p_what) {
// Update grid color by rebuilding grid.
_finish_grid();
_init_grid();
+ } else if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+ if (!is_visible() && tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->is_pressed()) {
+ ScriptEditorDebugger *debugger = ScriptEditor::get_singleton()->get_debugger();
+
+ debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_NONE);
+ tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_pressed(false);
+ }
}
}
@@ -5483,6 +5545,8 @@ void SpatialEditor::_bind_methods() {
ClassDB::bind_method("_request_gizmo", &SpatialEditor::_request_gizmo);
ClassDB::bind_method("_toggle_maximize_view", &SpatialEditor::_toggle_maximize_view);
ClassDB::bind_method("_refresh_menu_icons", &SpatialEditor::_refresh_menu_icons);
+ ClassDB::bind_method("_update_camera_override_button", &SpatialEditor::_update_camera_override_button);
+ ClassDB::bind_method("_update_camera_override_viewport", &SpatialEditor::_update_camera_override_viewport);
ADD_SIGNAL(MethodInfo("transform_key_request"));
ADD_SIGNAL(MethodInfo("item_lock_status_changed"));
@@ -5536,6 +5600,8 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
snap_key_enabled = false;
tool_mode = TOOL_MODE_SELECT;
+ camera_override_viewport_id = 0;
+
hbc_menu = memnew(HBoxContainer);
vbc->add_child(hbc_menu);
@@ -5633,6 +5699,17 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
hbc_menu->add_child(memnew(VSeparator));
+ tool_option_button[TOOL_OPT_OVERRIDE_CAMERA] = memnew(ToolButton);
+ hbc_menu->add_child(tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]);
+ tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_toggle_mode(true);
+ tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_flat(true);
+ tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_disabled(true);
+ button_binds.write[0] = MENU_TOOL_OVERRIDE_CAMERA;
+ tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->connect("toggled", this, "_menu_item_toggled", button_binds);
+ _update_camera_override_button(false);
+
+ hbc_menu->add_child(memnew(VSeparator));
+
// Drag and drop support;
preview_node = memnew(Spatial);
preview_bounds = AABB();
@@ -5721,6 +5798,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
viewports[i] = memnew(SpatialEditorViewport(this, editor, i));
viewports[i]->connect("toggle_maximize_view", this, "_toggle_maximize_view");
+ viewports[i]->connect("clicked", this, "_update_camera_override_viewport");
viewports[i]->assign_pending_data_pointers(preview_node, &preview_bounds, accept);
viewport_base->add_child(viewports[i]);
}
diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h
index fe91c33642..65e3c32ca8 100644
--- a/editor/plugins/spatial_editor_plugin.h
+++ b/editor/plugins/spatial_editor_plugin.h
@@ -494,6 +494,7 @@ public:
TOOL_OPT_LOCAL_COORDS,
TOOL_OPT_USE_SNAP,
+ TOOL_OPT_OVERRIDE_CAMERA,
TOOL_OPT_MAX
};
@@ -559,6 +560,7 @@ private:
MENU_TOOL_LIST_SELECT,
MENU_TOOL_LOCAL_COORDS,
MENU_TOOL_USE_SNAP,
+ MENU_TOOL_OVERRIDE_CAMERA,
MENU_TRANSFORM_CONFIGURE_SNAP,
MENU_TRANSFORM_DIALOG,
MENU_VIEW_USE_1_VIEWPORT,
@@ -585,9 +587,6 @@ private:
PopupMenu *gizmos_menu;
MenuButton *view_menu;
- ToolButton *lock_button;
- ToolButton *unlock_button;
-
AcceptDialog *accept;
ConfirmationDialog *snap_dialog;
@@ -615,13 +614,16 @@ private:
void _menu_item_pressed(int p_option);
void _menu_item_toggled(bool pressed, int p_option);
void _menu_gizmo_toggled(int p_option);
+ void _update_camera_override_button(bool p_game_running);
+ void _update_camera_override_viewport(Object *p_viewport);
HBoxContainer *hbc_menu;
void _generate_selection_box();
UndoRedo *undo_redo;
- void _instance_scene();
+ int camera_override_viewport_id;
+
void _init_indicators();
void _update_gizmos_menu();
void _update_gizmos_menu_theme();
@@ -716,7 +718,7 @@ public:
void set_can_preview(Camera *p_preview);
SpatialEditorViewport *get_editor_viewport(int p_idx) {
- ERR_FAIL_INDEX_V(p_idx, 4, NULL);
+ ERR_FAIL_INDEX_V(p_idx, static_cast<int>(VIEWPORTS_COUNT), NULL);
return viewports[p_idx];
}
diff --git a/editor/plugins/style_box_editor_plugin.cpp b/editor/plugins/style_box_editor_plugin.cpp
index defc0a40ea..c4a9803ff4 100644
--- a/editor/plugins/style_box_editor_plugin.cpp
+++ b/editor/plugins/style_box_editor_plugin.cpp
@@ -64,21 +64,24 @@ void StyleBoxPreview::edit(const Ref<StyleBox> &p_stylebox) {
void StyleBoxPreview::_sb_changed() {
preview->update();
+}
+
+void StyleBoxPreview::_redraw() {
if (stylebox.is_valid()) {
- Size2 ms = stylebox->get_minimum_size() * 4 / 3;
- ms.height = MAX(ms.height, 150 * EDSCALE);
- preview->set_custom_minimum_size(ms);
+ preview->draw_style_box(stylebox, preview->get_rect());
}
}
void StyleBoxPreview::_bind_methods() {
ClassDB::bind_method("_sb_changed", &StyleBoxPreview::_sb_changed);
+ ClassDB::bind_method("_redraw", &StyleBoxPreview::_redraw);
}
StyleBoxPreview::StyleBoxPreview() {
-
- preview = memnew(Panel);
+ preview = memnew(Control);
+ preview->set_custom_minimum_size(Size2(0, 150 * EDSCALE));
+ preview->connect("draw", this, "_redraw");
add_margin_child(TTR("Preview:"), preview);
}
diff --git a/editor/plugins/style_box_editor_plugin.h b/editor/plugins/style_box_editor_plugin.h
index d31a28b3e4..fead8e0de8 100644
--- a/editor/plugins/style_box_editor_plugin.h
+++ b/editor/plugins/style_box_editor_plugin.h
@@ -41,10 +41,11 @@ class StyleBoxPreview : public VBoxContainer {
GDCLASS(StyleBoxPreview, VBoxContainer);
- Panel *preview;
+ Control *preview;
Ref<StyleBox> stylebox;
void _sb_changed();
+ void _redraw();
protected:
static void _bind_methods();
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 21eebf9ca2..bda3d142fa 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -866,8 +866,8 @@ void TextureRegionEditor::_edit_region() {
Vector2 TextureRegionEditor::snap_point(Vector2 p_target) const {
if (snap_mode == SNAP_GRID) {
- p_target.x = Math::snap_scalar_seperation(snap_offset.x, snap_step.x, p_target.x, snap_separation.x);
- p_target.y = Math::snap_scalar_seperation(snap_offset.y, snap_step.y, p_target.y, snap_separation.y);
+ p_target.x = Math::snap_scalar_separation(snap_offset.x, snap_step.x, p_target.x, snap_separation.x);
+ p_target.y = Math::snap_scalar_separation(snap_offset.y, snap_step.y, p_target.y, snap_separation.y);
}
return p_target;
diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
index 2d66087699..10567557d6 100644
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ b/editor/plugins/tile_map_editor_plugin.cpp
@@ -1996,6 +1996,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
info_message->set_valign(Label::VALIGN_CENTER);
info_message->set_align(Label::ALIGN_CENTER);
info_message->set_autowrap(true);
+ info_message->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
info_message->set_anchors_and_margins_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE);
palette->add_child(info_message);
diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp
index e0bf8dfdb2..cc4c21cc04 100644
--- a/editor/plugins/tile_set_editor_plugin.cpp
+++ b/editor/plugins/tile_set_editor_plugin.cpp
@@ -584,6 +584,7 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
empty_message->set_valign(Label::VALIGN_CENTER);
empty_message->set_align(Label::ALIGN_CENTER);
empty_message->set_autowrap(true);
+ empty_message->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
empty_message->set_v_size_flags(SIZE_EXPAND_FILL);
main_vb->add_child(empty_message);
@@ -3038,8 +3039,8 @@ Vector2 TileSetEditor::snap_point(const Vector2 &point) {
}
if (tools[TOOL_GRID_SNAP]->is_pressed()) {
- p.x = Math::snap_scalar_seperation(snap_offset.x, snap_step.x, p.x, snap_separation.x);
- p.y = Math::snap_scalar_seperation(snap_offset.y, snap_step.y, p.y, snap_separation.y);
+ p.x = Math::snap_scalar_separation(snap_offset.x, snap_step.x, p.x, snap_separation.x);
+ p.y = Math::snap_scalar_separation(snap_offset.y, snap_step.y, p.y, snap_separation.y);
}
if (tools[SHAPE_KEEP_INSIDE_TILE]->is_pressed()) {
if (p.x < region.position.x)
diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp
index d4f985e1de..783797ada4 100644
--- a/editor/plugins/version_control_editor_plugin.cpp
+++ b/editor/plugins/version_control_editor_plugin.cpp
@@ -106,29 +106,20 @@ void VersionControlEditorPlugin::_initialize_vcs() {
register_editor();
- if (EditorVCSInterface::get_singleton()) {
-
- ERR_EXPLAIN(EditorVCSInterface::get_singleton()->get_vcs_name() + " is already active");
- return;
- }
+ ERR_FAIL_COND_MSG(EditorVCSInterface::get_singleton(), EditorVCSInterface::get_singleton()->get_vcs_name() + " is already active");
const int id = set_up_choice->get_selected_id();
String selected_addon = set_up_choice->get_item_text(id);
String path = ScriptServer::get_global_class_path(selected_addon);
Ref<Script> script = ResourceLoader::load(path);
- if (!script.is_valid()) {
- ERR_EXPLAIN("VCS Addon path is invalid");
- }
+ ERR_FAIL_COND_MSG(!script.is_valid(), "VCS Addon path is invalid");
EditorVCSInterface *vcs_interface = memnew(EditorVCSInterface);
ScriptInstance *addon_script_instance = script->instance_create(vcs_interface);
- if (!addon_script_instance) {
- ERR_FAIL_NULL(addon_script_instance);
- return;
- }
+ ERR_FAIL_COND_MSG(!addon_script_instance, "Failed to create addon script instance.");
// The addon is attached as a script to the VCS interface as a proxy end-point
vcs_interface->set_script_and_instance(script.get_ref_ptr(), addon_script_instance);
@@ -137,10 +128,8 @@ void VersionControlEditorPlugin::_initialize_vcs() {
EditorFileSystem::get_singleton()->connect("filesystem_changed", this, "_refresh_stage_area");
String res_dir = OS::get_singleton()->get_resource_dir();
- if (!EditorVCSInterface::get_singleton()->initialize(res_dir)) {
- ERR_EXPLAIN("VCS was not initialized");
- }
+ ERR_FAIL_COND_MSG(!EditorVCSInterface::get_singleton()->initialize(res_dir), "VCS was not initialized");
_refresh_stage_area();
}
@@ -397,8 +386,9 @@ void VersionControlEditorPlugin::clear_stage_area() {
void VersionControlEditorPlugin::shut_down() {
if (EditorVCSInterface::get_singleton()) {
-
- EditorFileSystem::get_singleton()->disconnect("filesystem_changed", this, "_refresh_stage_area");
+ if (EditorFileSystem::get_singleton()->is_connected("filesystem_changed", this, "_refresh_stage_area")) {
+ EditorFileSystem::get_singleton()->disconnect("filesystem_changed", this, "_refresh_stage_area");
+ }
EditorVCSInterface::get_singleton()->shut_down();
memdelete(EditorVCSInterface::get_singleton());
EditorVCSInterface::set_singleton(NULL);
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 3a9e48cfdb..1a74779fb5 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -109,11 +109,12 @@ void VisualShaderEditor::clear_custom_types() {
for (int i = 0; i < add_options.size(); i++) {
if (add_options[i].is_custom) {
add_options.remove(i);
+ i--;
}
}
}
-void VisualShaderEditor::add_custom_type(const String &p_name, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, const String &p_sub_category) {
+void VisualShaderEditor::add_custom_type(const String &p_name, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, const String &p_subcategory) {
ERR_FAIL_COND(!p_name.is_valid_identifier());
ERR_FAIL_COND(!p_script.is_valid());
@@ -131,9 +132,25 @@ void VisualShaderEditor::add_custom_type(const String &p_name, const Ref<Script>
ao.return_type = p_return_icon_type;
ao.description = p_description;
ao.category = p_category;
- ao.sub_category = p_sub_category;
+ ao.sub_category = p_subcategory;
ao.is_custom = true;
+ bool begin = false;
+
+ for (int i = 0; i < add_options.size(); i++) {
+ if (add_options[i].is_custom) {
+ if (add_options[i].category == p_category) {
+ if (!begin) {
+ begin = true;
+ }
+ } else {
+ if (begin) {
+ add_options.insert(i, ao);
+ return;
+ }
+ }
+ }
+ }
add_options.push_back(ao);
}
@@ -184,6 +201,7 @@ void VisualShaderEditor::update_custom_nodes() {
clear_custom_types();
List<StringName> class_list;
ScriptServer::get_global_class_list(&class_list);
+ Dictionary added;
for (int i = 0; i < class_list.size(); i++) {
if (ScriptServer::get_global_class_native_base(class_list[i]) == "VisualShaderNodeCustom") {
@@ -222,14 +240,44 @@ void VisualShaderEditor::update_custom_nodes() {
category = "Custom";
}
- String sub_category = "";
+ String subcategory = "";
if (ref->has_method("_get_subcategory")) {
- sub_category = (String)ref->call("_get_subcategory");
+ subcategory = (String)ref->call("_get_subcategory");
}
- add_custom_type(name, script, description, return_icon_type, category, sub_category);
+ Dictionary dict;
+ dict["name"] = name;
+ dict["script"] = script;
+ dict["description"] = description;
+ dict["return_icon_type"] = return_icon_type;
+ dict["category"] = category;
+ dict["subcategory"] = subcategory;
+
+ String key;
+ key = category;
+ key += "/";
+ if (subcategory != "") {
+ key += subcategory;
+ key += "/";
+ }
+ key += name;
+
+ added[key] = dict;
}
}
+
+ Array keys = added.keys();
+ keys.sort();
+
+ for (int i = 0; i < keys.size(); i++) {
+
+ const Variant &key = keys.get(i);
+
+ const Dictionary &value = (Dictionary)added[key];
+
+ add_custom_type(value["name"], value["script"], value["description"], value["return_icon_type"], value["category"], value["subcategory"]);
+ }
+
_update_options_menu();
}
@@ -2414,7 +2462,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Darken", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Darken operator."), VisualShaderNodeColorOp::OP_DARKEN, VisualShaderNode::PORT_TYPE_VECTOR));
add_options.push_back(AddOption("Difference", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Difference operator."), VisualShaderNodeColorOp::OP_DIFFERENCE, VisualShaderNode::PORT_TYPE_VECTOR));
add_options.push_back(AddOption("Dodge", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Dodge operator."), VisualShaderNodeColorOp::OP_DODGE, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("HardLight", "Color", "Operators", "VisualShaderNodeColorOp", TTR("HardLight operator"), VisualShaderNodeColorOp::OP_HARD_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("HardLight", "Color", "Operators", "VisualShaderNodeColorOp", TTR("HardLight operator."), VisualShaderNodeColorOp::OP_HARD_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR));
add_options.push_back(AddOption("Lighten", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Lighten operator."), VisualShaderNodeColorOp::OP_LIGHTEN, VisualShaderNode::PORT_TYPE_VECTOR));
add_options.push_back(AddOption("Overlay", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Overlay operator."), VisualShaderNodeColorOp::OP_OVERLAY, VisualShaderNode::PORT_TYPE_VECTOR));
add_options.push_back(AddOption("Screen", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Screen operator."), VisualShaderNodeColorOp::OP_SCREEN, VisualShaderNode::PORT_TYPE_VECTOR));
@@ -2483,9 +2531,11 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Alpha", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Binormal", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal"), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("DepthTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "depth_texture"), "depth_texture", VisualShaderNode::PORT_TYPE_SAMPLER, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("FragCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("FrontFacing", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "front_facing"), "front_facing", VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("PointCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "point_coord"), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("ScreenTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_texture"), "screen_texture", VisualShaderNode::PORT_TYPE_SAMPLER, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("ScreenUV", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Side", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "side"), "side", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Tangent", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "tangent"), "tangent", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
@@ -2519,9 +2569,12 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("FragCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("LightPass", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "light_pass"), "light_pass", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("NormalTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "normal_texture"), "normal_texture", VisualShaderNode::PORT_TYPE_SAMPLER, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("PointCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "point_coord"), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("ScreenPixelSize", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_pixel_size"), "screen_pixel_size", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("ScreenTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_texture"), "screen_texture", VisualShaderNode::PORT_TYPE_SAMPLER, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("ScreenUV", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("Texture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "texture"), "texture", VisualShaderNode::PORT_TYPE_SAMPLER, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("FragCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("LightAlpha", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_alpha"), "light_alpha", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM));
@@ -2533,6 +2586,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("PointCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "point_coord"), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("ScreenUV", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("ShadowColor", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "shadow_color"), "shadow_color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("Texture", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "texture"), "texture", VisualShaderNode::PORT_TYPE_SAMPLER, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("Extra", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "extra"), "extra", VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShader::TYPE_VERTEX, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("LightPass", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "light_pass"), "light_pass", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_CANVAS_ITEM));
@@ -2726,7 +2780,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Expression", "Special", "", "VisualShaderNodeExpression", TTR("Custom Godot Shader Language expression, with custom amount of input and output ports. This is a direct injection of code into the vertex/fragment/light function, do not use it to write the function declarations inside.")));
add_options.push_back(AddOption("Fresnel", "Special", "", "VisualShaderNodeFresnel", TTR("Returns falloff based on the dot product of surface normal and view direction of camera (pass associated inputs to it)."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("GlobalExpression", "Special", "", "VisualShaderNodeGlobalExpression", TTR("Custom Godot Shader Language expression, which placed on top of the resulted shader. You can place various function definitions inside and call it later in the Expressions. You can also declare varyings, uniforms and constants.")));
+ add_options.push_back(AddOption("GlobalExpression", "Special", "", "VisualShaderNodeGlobalExpression", TTR("Custom Godot Shader Language expression, which is placed on top of the resulted shader. You can place various function definitions inside and call it later in the Expressions. You can also declare varyings, uniforms and constants.")));
add_options.push_back(AddOption("ScalarDerivativeFunc", "Special", "Common", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) Scalar derivative function."), -1, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true));
add_options.push_back(AddOption("VectorDerivativeFunc", "Special", "Common", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) Vector derivative function."), -1, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true));
@@ -2830,11 +2884,12 @@ public:
void setup(const Ref<VisualShaderNodeInput> &p_input) {
input = p_input;
- Ref<Texture> type_icon[4] = {
+ Ref<Texture> type_icon[5] = {
EditorNode::get_singleton()->get_gui_base()->get_icon("float", "EditorIcons"),
EditorNode::get_singleton()->get_gui_base()->get_icon("Vector3", "EditorIcons"),
EditorNode::get_singleton()->get_gui_base()->get_icon("bool", "EditorIcons"),
EditorNode::get_singleton()->get_gui_base()->get_icon("Transform", "EditorIcons"),
+ EditorNode::get_singleton()->get_gui_base()->get_icon("ImageTexture", "EditorIcons"),
};
add_item("[None]");
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index 6f77641936..5197f8c77f 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -264,7 +264,7 @@ public:
static VisualShaderEditor *get_singleton() { return singleton; }
void clear_custom_types();
- void add_custom_type(const String &p_name, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, const String &p_sub_category);
+ void add_custom_type(const String &p_name, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, const String &p_subcategory);
virtual Size2 get_minimum_size() const;
void edit(VisualShader *p_visual_shader);